diff --git a/tee-worker/omni-executor/Cargo.lock b/tee-worker/omni-executor/Cargo.lock
index 54e5472deb..f9e3bd11f3 100644
--- a/tee-worker/omni-executor/Cargo.lock
+++ b/tee-worker/omni-executor/Cargo.lock
@@ -4013,7 +4013,6 @@ dependencies = [
"clap",
"config-loader",
"cross-chain-intent-executor",
- "ethereum-intent-executor",
"ethereum-rpc",
"ethers",
"executor-core",
@@ -4026,7 +4025,6 @@ dependencies = [
"jsonrpsee",
"metrics-exporter-prometheus",
"mock-server",
- "native-task-handler",
"pumpx",
"rand 0.8.5",
"rpc-server",
@@ -4038,7 +4036,6 @@ dependencies = [
"sha2 0.10.9",
"signer-client",
"solana",
- "solana-intent-executor",
"tokio",
"tracing",
"tracing-subscriber",
@@ -5224,7 +5221,7 @@ dependencies = [
"hyper 1.7.0",
"hyper-util",
"log",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
@@ -5665,9 +5662,9 @@ dependencies = [
[[package]]
name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itertools"
@@ -5830,7 +5827,7 @@ dependencies = [
"http 1.3.1",
"jsonrpsee-core",
"pin-project",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-pki-types",
"rustls-platform-verifier 0.5.3",
"soketto",
@@ -5883,7 +5880,7 @@ dependencies = [
"hyper-util",
"jsonrpsee-core",
"jsonrpsee-types",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-platform-verifier 0.5.3",
"serde",
"serde_json",
@@ -6572,35 +6569,6 @@ dependencies = [
"typenum",
]
-[[package]]
-name = "native-task-handler"
-version = "0.1.0"
-dependencies = [
- "aa-contracts-client",
- "alloy",
- "async-trait",
- "binance-api",
- "chrono",
- "ethereum-rpc",
- "executor-core",
- "executor-crypto",
- "executor-primitives",
- "executor-storage",
- "heima-authentication",
- "heima-identity-verification",
- "hex",
- "hyperliquid",
- "parity-scale-codec",
- "pumpx",
- "rand 0.8.5",
- "serde",
- "signer-client",
- "sp-core 35.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio",
- "tokio-test",
- "tracing",
-]
-
[[package]]
name = "native-tls"
version = "0.2.14"
@@ -6934,9 +6902,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
-version = "1.70.1"
+version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "opaque-debug"
@@ -7762,7 +7730,7 @@ dependencies = [
"quinn-proto",
"quinn-udp",
"rustc-hash",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"socket2 0.6.1",
"thiserror 2.0.17",
"tokio",
@@ -7783,7 +7751,7 @@ dependencies = [
"rand 0.9.2",
"ring 0.17.14",
"rustc-hash",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-pki-types",
"rustls-platform-verifier 0.6.1",
"slab",
@@ -8131,7 +8099,7 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"quinn",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-pki-types",
"serde",
"serde_json",
@@ -8350,9 +8318,9 @@ dependencies = [
"heima-utils",
"hex",
"http 1.3.1",
+ "hyperliquid",
"hyperliquid_rust_sdk",
"jsonrpsee",
- "native-task-handler",
"oauth-providers",
"parity-scale-codec",
"pumpx",
@@ -8514,9 +8482,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.23.33"
+version = "0.23.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c"
+checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7"
dependencies = [
"aws-lc-rs",
"log",
@@ -8570,7 +8538,7 @@ dependencies = [
"jni",
"log",
"once_cell",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki 0.103.7",
@@ -8591,7 +8559,7 @@ dependencies = [
"jni",
"log",
"once_cell",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki 0.103.7",
@@ -10634,7 +10602,7 @@ dependencies = [
"log",
"quinn",
"quinn-proto",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"solana-connection-cache",
"solana-keypair",
"solana-measure",
@@ -11170,7 +11138,7 @@ dependencies = [
"quinn",
"quinn-proto",
"rand 0.8.5",
- "rustls 0.23.33",
+ "rustls 0.23.34",
"smallvec",
"socket2 0.5.10",
"solana-keypair",
@@ -11323,7 +11291,7 @@ version = "2.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec21c6c242ee93642aa50b829f5727470cdbdf6b461fb7323fe4bc31d1b54c08"
dependencies = [
- "rustls 0.23.33",
+ "rustls 0.23.34",
"solana-keypair",
"solana-pubkey",
"solana-signer",
@@ -13147,7 +13115,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
dependencies = [
- "rustls 0.23.33",
+ "rustls 0.23.34",
"tokio",
]
@@ -13163,19 +13131,6 @@ dependencies = [
"tokio-util",
]
-[[package]]
-name = "tokio-test"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
-dependencies = [
- "async-stream",
- "bytes",
- "futures-core",
- "tokio",
- "tokio-stream",
-]
-
[[package]]
name = "tokio-tungstenite"
version = "0.20.1"
diff --git a/tee-worker/omni-executor/Cargo.toml b/tee-worker/omni-executor/Cargo.toml
index 1bd7ea0126..0654fe486c 100644
--- a/tee-worker/omni-executor/Cargo.toml
+++ b/tee-worker/omni-executor/Cargo.toml
@@ -20,7 +20,6 @@ members = [
"intent/executors/solana",
"intent/token-query",
"mock-server",
- "native-task-handler",
"oauth-providers",
"omni-cli",
"pumpx",
@@ -118,7 +117,6 @@ hyperliquid = { path = "hyperliquid" }
intent-asset-lock = { path = "intent/asset-lock" }
intent-token-query = { path = "intent/token-query" }
mock-server = { path = "mock-server" }
-native-task-handler = { path = "native-task-handler" }
oauth-providers = { path = "oauth-providers" }
pumpx = { path = "pumpx" }
rpc-server = { path = "rpc-server" }
diff --git a/tee-worker/omni-executor/native-task-handler/src/aes256_key_store.rs b/tee-worker/omni-executor/executor-core/src/aes256_key_store.rs
similarity index 96%
rename from tee-worker/omni-executor/native-task-handler/src/aes256_key_store.rs
rename to tee-worker/omni-executor/executor-core/src/aes256_key_store.rs
index b7ea1a425e..b408084181 100644
--- a/tee-worker/omni-executor/native-task-handler/src/aes256_key_store.rs
+++ b/tee-worker/omni-executor/executor-core/src/aes256_key_store.rs
@@ -1,4 +1,4 @@
-use executor_core::key_store::KeyStore;
+use crate::key_store::KeyStore;
use executor_crypto::aes256::Aes256Key;
use rand::Rng;
diff --git a/tee-worker/omni-executor/executor-core/src/lib.rs b/tee-worker/omni-executor/executor-core/src/lib.rs
index b1b6f742a5..8373a75823 100644
--- a/tee-worker/omni-executor/executor-core/src/lib.rs
+++ b/tee-worker/omni-executor/executor-core/src/lib.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Litentry. If not, see .
+pub mod aes256_key_store;
pub mod ecdsa_key_store;
pub mod ed25519_key_store;
pub mod event_handler;
@@ -26,3 +27,5 @@ pub mod shielding_key_store;
pub mod sync_checkpoint_repository;
pub mod types;
pub mod wallet_metrics;
+
+pub use aes256_key_store::Aes256KeyStore;
diff --git a/tee-worker/omni-executor/executor-worker/Cargo.toml b/tee-worker/omni-executor/executor-worker/Cargo.toml
index af95ae30a3..16a4bd2a51 100644
--- a/tee-worker/omni-executor/executor-worker/Cargo.toml
+++ b/tee-worker/omni-executor/executor-worker/Cargo.toml
@@ -29,7 +29,6 @@ accounting-contract-client = { workspace = true }
binance-api = { workspace = true }
config-loader = { workspace = true }
cross-chain-intent-executor = { workspace = true }
-ethereum-intent-executor = { workspace = true }
ethereum-rpc = { workspace = true }
executor-core = { workspace = true }
executor-crypto = { workspace = true }
@@ -38,12 +37,10 @@ executor-storage = { workspace = true }
heima-identity-verification = { workspace = true }
intent-asset-lock = { workspace = true }
mock-server = { workspace = true }
-native-task-handler = { workspace = true }
pumpx = { workspace = true }
rpc-server = { workspace = true }
signer-client = { workspace = true }
solana = { workspace = true }
-solana-intent-executor = { workspace = true }
wildmeta-api = { workspace = true }
[features]
diff --git a/tee-worker/omni-executor/executor-worker/src/main.rs b/tee-worker/omni-executor/executor-worker/src/main.rs
index 1c7b530576..4036892378 100644
--- a/tee-worker/omni-executor/executor-worker/src/main.rs
+++ b/tee-worker/omni-executor/executor-worker/src/main.rs
@@ -26,7 +26,6 @@ use clap::Parser;
use cli::{Cli, Commands, ExportBundlerKeyArgs};
use config_loader::ConfigLoader;
use cross_chain_intent_executor::{Chain, CrossChainIntentExecutor, RpcEndpointRegistry};
-use ethereum_intent_executor::EthereumIntentExecutor;
use ethereum_rpc::client::EthereumRpcClient;
use executor_core::ecdsa_key_store::EcdsaKeyStore;
use executor_core::ed25519_key_store::Ed25519KeyStore;
@@ -36,18 +35,17 @@ use executor_core::wallet_metrics::Wallet;
use executor_core::wallet_metrics::{
start_wallet_metrics, WalletBalanceFetcher, WalletId, WalletMetrics, WalletNetworkType,
};
+use executor_core::Aes256KeyStore;
use executor_crypto::{ecdsa, ed25519, PairTrait};
use executor_storage::init_storage;
use intent_asset_lock::precise::PreciseAssetsLock;
use intent_asset_lock::AccountAssetLocks;
use metrics_exporter_prometheus::PrometheusBuilder;
-use native_task_handler::Aes256KeyStore;
use pumpx::{pubkey_to_evm_address, pubkey_to_solana_address};
use pumpx::{PumpxApi, PumpxApiClient};
use rpc_server::{start_server as start_rpc_server, AuthTokenKeyStore};
use rust_decimal::Decimal;
use solana::SolanaRpcClient;
-use solana_intent_executor::SolanaIntentExecutor;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::path::Path;
@@ -178,12 +176,6 @@ async fn main() -> Result<(), ()> {
pumpx_signer_pair,
)));
- let ethereum_intent_executor = EthereumIntentExecutor::new(
- &config_loader.ethereum_url,
- &args.delegation_contract_address,
- )?;
- let solana_intent_executor = SolanaIntentExecutor::new(&config_loader.solana_url)?;
-
let mut rpc_endpoint_registry = RpcEndpointRegistry::new();
rpc_endpoint_registry.insert(Chain::Solana, config_loader.solana_url.to_string());
rpc_endpoint_registry.insert(Chain::Ethereum(56), config_loader.bsc_url.to_string());
@@ -531,8 +523,6 @@ async fn main() -> Result<(), ()> {
wildmeta_backend_ecdsa_pubkey,
evm_accounting_ecdsa_signer_key,
bundler_key_export_authorized_pubkey,
- Arc::new(ethereum_intent_executor),
- Arc::new(solana_intent_executor),
Arc::new(cross_chain_intent_executor),
aes256_key,
entry_point_clients,
diff --git a/tee-worker/omni-executor/native-task-handler/Cargo.toml b/tee-worker/omni-executor/native-task-handler/Cargo.toml
deleted file mode 100644
index dd135849d7..0000000000
--- a/tee-worker/omni-executor/native-task-handler/Cargo.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-[package]
-name = "native-task-handler"
-version = "0.1.0"
-authors = ['Trust Computing GmbH ']
-edition.workspace = true
-
-[dependencies]
-alloy = { workspace = true }
-chrono = { workspace = true }
-hex = { workspace = true }
-parity-scale-codec = { workspace = true }
-rand = { workspace = true }
-serde = { workspace = true }
-tokio = { workspace = true }
-tracing = { workspace = true }
-
-# Local dependencies
-aa-contracts-client = { workspace = true }
-binance-api = { workspace = true }
-ethereum-rpc = { workspace = true }
-executor-core = { workspace = true }
-executor-crypto = { workspace = true }
-executor-primitives = { workspace = true }
-executor-storage = { workspace = true }
-heima-authentication = { workspace = true }
-heima-identity-verification = { workspace = true }
-hyperliquid = { workspace = true }
-pumpx = { workspace = true }
-signer-client = { workspace = true }
-sp-core = { workspace = true }
-
-[dev-dependencies]
-async-trait = { workspace = true }
-binance-api = { workspace = true, features = ["mocks"] }
-tokio-test = "0.4.4"
-
-[features]
-mocks = []
-
-[lints]
-workspace = true
diff --git a/tee-worker/omni-executor/native-task-handler/src/lib.rs b/tee-worker/omni-executor/native-task-handler/src/lib.rs
deleted file mode 100644
index a98d51dd92..0000000000
--- a/tee-worker/omni-executor/native-task-handler/src/lib.rs
+++ /dev/null
@@ -1,3611 +0,0 @@
-mod aes256_key_store;
-pub mod types;
-
-use aa_contracts_client::calculate_user_operation_hash;
-use aa_contracts_client::EntryPointClient;
-use alloy::primitives::{Address, Bytes, FixedBytes, U256};
-use binance_api::BinancePaymasterApi;
-use chrono::{Days, Utc};
-use ethereum_rpc::AlloyRpcProvider;
-use executor_core::{
- intent_executor::IntentExecutor,
- native_task::{NativeTask, NativeTaskWrapper},
- types::SerializablePackedUserOperation,
-};
-use executor_crypto::{
- aes256::{aes_decrypt, Aes256Key},
- jwt,
-};
-use executor_primitives::{
- utils::hex::{decode_hex, ToHexPrefixed},
- ChainId, Identity, Intent, PumpxAccountProfile, Web2IdentityType,
-};
-use executor_storage::{HeimaJwtStorage, IntentIdStorage, PumpxProfileStorage, Storage, StorageDB};
-use heima_authentication::{
- auth_token::*,
- constants::{AUTH_TOKEN_ACCESS_TYPE, AUTH_TOKEN_EXPIRATION_DAYS, AUTH_TOKEN_ID_TYPE},
-};
-use pumpx::{
- methods::create_transfer_tx::CreateTransferTxBody, signer_client::PumpxChainId, PumpxApi,
-};
-use signer_client::{ChainType, SignerClient};
-use std::{collections::HashMap, sync::Arc};
-use tokio::sync::{mpsc, oneshot};
-use tracing::{debug, error, info};
-
-pub use aes256_key_store::Aes256KeyStore;
-pub use types::{NativeTaskError, NativeTaskOk, PumpxApiError, PumpxSignerError};
-
-pub type ResponseSender = oneshot::Sender>;
-
-// ============================================================================
-// ERC20 Paymaster Exchange Rate Processing
-// ============================================================================
-
-// Constants for ERC20 paymaster processing
-// paymasterAndData format: paymaster_address (20) + validation_gas_limit (16) + postop_gas_limit (16) + paymaster_data
-// paymaster_data: token(20) + exchangeRate(32) + validUntil(32) + validAfter(32)
-const MIN_ERC20_PAYMASTER_DATA_LENGTH: usize = 52 + 20 + 32 + 32 + 32; // 168 bytes minimum
-const PAYMASTER_DATA_OFFSET: usize = 52; // paymaster address (20) + validation_gas_limit (16) + postop_gas_limit (16)
-const EXCHANGE_RATE_FEE_PERCENT: f64 = 0.0; // 0% fee for now
-const WEI_PER_ETH: u128 = 1_000_000_000_000_000_000; // 1e18 wei
-
-// Whitelisted paymaster addresses that we support (deployed by heima), the logic is:
-// - Unsigned userOp: If paymaster specified, **must** be whitelisted
-// - Signed userOp: Only allowed if paymasterAndData is empty (technically we could still relay it, but we are a private bundler and don't want to relay arbitrary userOps)
-//
-// These addresses are assumed to be the same across all EVM chains
-//
-// Note: the SimplePaymaster should be gradually deprecated in favor of the ERC20PaymasterV1.
-// Theoretically user could construct an unsiged userOp to use SimplePaymaster "freely"
-//
-// TODO: add ERC20 paymaster addresses
-const WHITELISTED_PAYMASTER_ADDRESSES: &[&str] = &[
- // SimplePaymaster
- "0x6255B9F4A4E80BC20eE389fD35DE9d2c029D5912", // staging-v1
- "0xD4dCB31763CBA7295bA4023E9411CB6db607DE07", // prod-v1
- // ERC20PaymasterV1
- "0xA8535e013236E04FAD5dc03eCc4c05A464c01f38", // staging
-];
-
-// Decode ERC20 paymaster data from paymasterAndData
-// Format: paymaster_address(20) + validation_gas_limit(16) + postop_gas_limit(16) + token(20) + exchangeRate(32) + validUntil(32) + validAfter(32)
-fn decode_erc20_paymaster_data(paymaster_and_data: &[u8]) -> Option<(Address, u128, u64, u64)> {
- if paymaster_and_data.len() < MIN_ERC20_PAYMASTER_DATA_LENGTH {
- return None;
- }
-
- // Extract token address from paymaster data (bytes 52-71)
- let token_address =
- Address::from_slice(&paymaster_and_data[PAYMASTER_DATA_OFFSET..PAYMASTER_DATA_OFFSET + 20]);
-
- // Extract exchange rate (bytes 72-103, 32 bytes, full u256 but we take as u128)
- let rate_bytes = &paymaster_and_data[PAYMASTER_DATA_OFFSET + 20..PAYMASTER_DATA_OFFSET + 52];
- let mut exchange_rate_bytes = [0u8; 16];
- exchange_rate_bytes.copy_from_slice(&rate_bytes[16..32]); // Last 16 bytes for u128
- let exchange_rate = u128::from_be_bytes(exchange_rate_bytes);
-
- // Extract validUntil (bytes 104-135, 32 bytes, take as u64)
- let valid_until_bytes =
- &paymaster_and_data[PAYMASTER_DATA_OFFSET + 52..PAYMASTER_DATA_OFFSET + 84];
- let mut until_bytes = [0u8; 8];
- until_bytes.copy_from_slice(&valid_until_bytes[24..32]); // Last 8 bytes for u64
- let valid_until = u64::from_be_bytes(until_bytes);
-
- // Extract validAfter (bytes 136-167, 32 bytes, take as u64)
- let valid_after_bytes =
- &paymaster_and_data[PAYMASTER_DATA_OFFSET + 84..PAYMASTER_DATA_OFFSET + 116];
- let mut after_bytes = [0u8; 8];
- after_bytes.copy_from_slice(&valid_after_bytes[24..32]); // Last 8 bytes for u64
- let valid_after = u64::from_be_bytes(after_bytes);
-
- Some((token_address, exchange_rate, valid_until, valid_after))
-}
-
-// Encode ERC20 paymaster data with updated exchange rate, preserving validUntil and validAfter
-fn encode_erc20_paymaster_data(
- original_data: &[u8],
- new_exchange_rate: u128,
- valid_until: u64,
- valid_after: u64,
-) -> Vec {
- let mut updated_data = original_data.to_vec();
-
- // Skip token address (20 bytes), update exchange rate (32 bytes, big-endian u128 in last 16 bytes)
- let rate_start = PAYMASTER_DATA_OFFSET + 20;
- let rate_bytes = [0u8; 16]
- .iter()
- .chain(&new_exchange_rate.to_be_bytes())
- .copied()
- .collect::>();
- updated_data[rate_start..rate_start + 32].copy_from_slice(&rate_bytes);
-
- // Update validUntil (32 bytes)
- let valid_until_start = rate_start + 32;
- let valid_until_bytes =
- [0u8; 24].iter().chain(&valid_until.to_be_bytes()).copied().collect::>();
- updated_data[valid_until_start..valid_until_start + 32].copy_from_slice(&valid_until_bytes);
-
- // Update validAfter (32 bytes)
- let valid_after_start = valid_until_start + 32;
- let valid_after_bytes =
- [0u8; 24].iter().chain(&valid_after.to_be_bytes()).copied().collect::>();
- updated_data[valid_after_start..valid_after_start + 32].copy_from_slice(&valid_after_bytes);
-
- updated_data
-}
-
-/// Extract paymaster address from paymasterAndData field
-/// Returns None if the data is too short to contain a valid paymaster address
-fn extract_paymaster_address(paymaster_and_data: &Bytes) -> Option {
- if paymaster_and_data.len() < 20 {
- return None;
- }
-
- // First 20 bytes contain the paymaster address
- Some(Address::from_slice(&paymaster_and_data[0..20]))
-}
-
-/// Check if a paymaster address is in our whitelist
-/// If so, the userOp must be unsigned to allow exchange rate processing
-fn is_whitelisted_paymaster(paymaster_address: &Address, whitelisted: &[Address]) -> bool {
- whitelisted.contains(paymaster_address)
-}
-
-/// Parse whitelisted paymaster addresses from const strings to Address types
-/// Returns empty vec if any address fails to parse (defensive programming)
-fn parse_whitelisted_paymasters() -> Vec {
- WHITELISTED_PAYMASTER_ADDRESSES
- .iter()
- .filter_map(|addr_str| addr_str.parse().ok())
- .collect()
-}
-
-// Comprehensive token mapping with expanded support
-#[derive(Debug, Clone)]
-struct TokenInfo {
- decimals: u8,
- binance_pair: &'static str,
-}
-
-// Get supported tokens - organized by chain for better scalability
-fn get_supported_tokens() -> std::collections::HashMap<(u64, &'static str), TokenInfo> {
- let mut tokens = std::collections::HashMap::new();
-
- // Ethereum mainnet (chain_id 1)
- tokens.insert(
- (1, "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), // USDC
- TokenInfo { decimals: 6, binance_pair: "ETHUSDC" },
- );
- tokens.insert(
- (1, "0xdac17f958d2ee523a2206206994597c13d831ec7"), // USDT
- TokenInfo { decimals: 6, binance_pair: "ETHUSDT" },
- );
- tokens.insert(
- (1, "0x6b175474e89094c44da98b954eedeac495271d0f"), // DAI
- TokenInfo { decimals: 18, binance_pair: "ETHDAI" },
- );
-
- // Arbitrum One (chain_id 42161)
- tokens.insert(
- (42161, "0xaf88d065e77c8cc2239327c5edb3a432268e5831"), // USDC
- TokenInfo { decimals: 6, binance_pair: "ETHUSDC" },
- );
- tokens.insert(
- (42161, "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"), // USDT
- TokenInfo { decimals: 6, binance_pair: "ETHUSDT" },
- );
-
- // Arbitrum Sepolia (chain_id 421614)
- tokens.insert(
- (421614, "0x75faf114eafb1bdbe2f0316df893fd58ce46aa4d"), // USDC
- TokenInfo { decimals: 6, binance_pair: "ETHUSDC" },
- );
-
- // BNB Smart Chain (chain_id 56)
- tokens.insert(
- (56, "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d"), // USDC
- TokenInfo { decimals: 18, binance_pair: "ETHUSDC" },
- );
- tokens.insert(
- (56, "0x55d398326f99059ff775485246999027b3197955"), // USDT
- TokenInfo { decimals: 18, binance_pair: "ETHUSDT" },
- );
-
- // Base (Chain ID 8453)
- tokens.insert(
- (8453, "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"), // USDC
- TokenInfo { decimals: 6, binance_pair: "ETHUSDC" },
- );
-
- tokens
-}
-
-// Map token address to Binance symbol and return (symbol, decimals) from hardcoded mapping
-async fn get_token_info_from_mapping(
- token_address: &Address,
- chain_id: u64,
-) -> Option<(String, u8)> {
- let tokens = get_supported_tokens();
- let address_str = token_address.to_string().to_lowercase();
-
- // Look up token info from our comprehensive mapping
- if let Some(token_info) = tokens.get(&(chain_id, address_str.as_str())) {
- // Use hardcoded values from our mapping
- return Some((token_info.binance_pair.to_string(), token_info.decimals));
- }
-
- debug!(
- "Token address {} on chain {} is not supported. Supported tokens: {:?}",
- token_address,
- chain_id,
- tokens.keys().filter(|(cid, _)| *cid == chain_id).collect::>()
- );
- None
-}
-
-// Calculate exchange rate using Binance API
-async fn calculate_exchange_rate_with_binance(
- binance_api: &dyn BinancePaymasterApi,
- token_symbol: &str,
- token_decimals: u8,
-) -> Result {
- // Query price from Binance
- // For ETHUSDC, this returns how many USDC for 1 ETH (e.g., 4479.99)
- let price_str = binance_api
- .get_symbol_price(token_symbol)
- .await
- .map_err(|e| format!("Failed to get price for {}: {:?}", token_symbol, e))?;
-
- let tokens_per_eth: f64 = price_str
- .parse()
- .map_err(|e| format!("Failed to parse price '{}': {}", price_str, e))?;
-
- if tokens_per_eth <= 0.0 {
- return Err(format!("Invalid price from Binance: {}", tokens_per_eth));
- }
-
- // Apply fee percentage (increase rate to charge more tokens)
- let tokens_per_eth_with_fee = tokens_per_eth * (1.0 + EXCHANGE_RATE_FEE_PERCENT / 100.0);
-
- // Calculate exchange rate according to ERC20PaymasterV1.sol:
- // exchangeRate = tokensPerEth * 10^tokenDecimals
- // Example: For 6-decimal USDC at $4000/ETH: rate = 4000 * 10^6 = 4000000000
- // This rate is used as: requiredTokenAmount = (maxCost * exchangeRate) / 1e18
- // Where maxCost is in wei, so 1 ETH of gas = 10^18 wei
- // Result: (10^18 * 4000000000) / 10^18 = 4000000000 USDC units = 4000 USDC ✓
-
- let exchange_rate_f64 = tokens_per_eth_with_fee * (10_f64.powi(token_decimals as i32));
-
- if exchange_rate_f64 <= 0.0 || exchange_rate_f64 >= u128::MAX as f64 {
- return Err(format!("Exchange rate {} is out of valid range", exchange_rate_f64));
- }
-
- info!(
- "Calculated exchange rate for {}: {} tokens per ETH -> rate {} (with {}% fee)",
- token_symbol, tokens_per_eth, exchange_rate_f64 as u128, EXCHANGE_RATE_FEE_PERCENT
- );
-
- Ok(exchange_rate_f64 as u128)
-}
-
-// Process ERC20 paymaster data
-async fn process_erc20_paymaster_data(
- binance_api: &dyn BinancePaymasterApi,
- paymaster_and_data: &Bytes,
- chain_id: u64,
-) -> Result