diff --git a/src/common/gas_fee_strategy.rs b/src/common/gas_fee_strategy.rs index 8c1eebd..35c217c 100644 --- a/src/common/gas_fee_strategy.rs +++ b/src/common/gas_fee_strategy.rs @@ -33,45 +33,26 @@ impl GasFeeStrategy { /// 设置全局费率策略 /// Set global fee strategy pub fn set_global_fee_strategy(cu_limit: u32, cu_price: u64, buy_tip: f64, sell_tip: f64) { - GasFeeStrategy::add_normal_fee_strategies( - &SwqosType::values() - .into_iter() - .filter(|swqos_type| !swqos_type.eq(&SwqosType::Default)) - .collect::>(), - TradeType::Buy, - cu_limit, - cu_price, - buy_tip, - ); - GasFeeStrategy::add_normal_fee_strategies( - &SwqosType::values() - .into_iter() - .filter(|swqos_type| !swqos_type.eq(&SwqosType::Default)) - .collect::>(), - TradeType::Sell, - cu_limit, - cu_price, - sell_tip, - ); - GasFeeStrategy::add_normal_fee_strategy( + for swqos_type in SwqosType::values() { + if swqos_type.eq(&SwqosType::Default) { + continue; + } + GasFeeStrategy::set(swqos_type, TradeType::Buy, cu_limit, cu_price, buy_tip); + GasFeeStrategy::set(swqos_type, TradeType::Sell, cu_limit, cu_price, sell_tip); + } + + GasFeeStrategy::set_normal_fee_strategy( SwqosType::Default, - TradeType::Buy, cu_limit, cu_price, 0.0, - ); - GasFeeStrategy::add_normal_fee_strategy( - SwqosType::Default, - TradeType::Sell, - cu_limit, - cu_price, 0.0, ); } /// 为多个服务类型添加高低费率策略,会移除(SwqosType,TradeType)的默认策略。 /// Add high-low fee strategies for multiple service types, Will remove the default strategy of (SwqosType,TradeType) - pub fn add_high_low_fee_strategies( + pub fn set_high_low_fee_strategies( swqos_types: &[SwqosType], trade_type: TradeType, cu_limit: u32, @@ -81,30 +62,15 @@ impl GasFeeStrategy { high_tip: f64, ) { for swqos_type in swqos_types { - GasFeeStrategy::remove_strategy(*swqos_type, trade_type); + GasFeeStrategy::del(*swqos_type, trade_type); + GasFeeStrategy::set(*swqos_type, trade_type, cu_limit, high_cu_price, low_tip); + GasFeeStrategy::set(*swqos_type, trade_type, cu_limit, low_cu_price, high_tip); } - STRATEGIES.rcu(|current_map| { - let mut new_map = (**current_map).clone(); - for swqos_type in swqos_types { - if swqos_type.eq(&SwqosType::Default) { - continue; - } - new_map.insert( - (*swqos_type, trade_type, GasFeeStrategyType::LowTipHighCuPrice), - GasFeeStrategyValue { cu_limit, cu_price: high_cu_price, tip: low_tip }, - ); - new_map.insert( - (*swqos_type, trade_type, GasFeeStrategyType::HighTipLowCuPrice), - GasFeeStrategyValue { cu_limit, cu_price: low_cu_price, tip: high_tip }, - ); - } - Arc::new(new_map) - }); } - + /// 为单个服务类型添加高低费率策略,会移除(SwqosType,TradeType)的默认策略。 /// Add high-low fee strategy for a single service type, Will remove the default strategy of (SwqosType,TradeType) - pub fn add_high_low_fee_strategy( + pub fn set_high_low_fee_strategy( swqos_type: SwqosType, trade_type: TradeType, cu_limit: u32, @@ -116,24 +82,14 @@ impl GasFeeStrategy { if swqos_type.eq(&SwqosType::Default) { return; } - GasFeeStrategy::remove_strategy(swqos_type, trade_type); - STRATEGIES.rcu(|current_map| { - let mut new_map = (**current_map).clone(); - new_map.insert( - (swqos_type, trade_type, GasFeeStrategyType::LowTipHighCuPrice), - GasFeeStrategyValue { cu_limit, cu_price: high_cu_price, tip: low_tip }, - ); - new_map.insert( - (swqos_type, trade_type, GasFeeStrategyType::HighTipLowCuPrice), - GasFeeStrategyValue { cu_limit, cu_price: low_cu_price, tip: high_tip }, - ); - Arc::new(new_map) - }); + GasFeeStrategy::del(swqos_type, trade_type); + GasFeeStrategy::set(swqos_type, trade_type, cu_limit, high_cu_price, low_tip); + GasFeeStrategy::set(swqos_type, trade_type, cu_limit, low_cu_price, high_tip); } /// 为多个服务类型添加标准费率策略,会移除(SwqosType,TradeType)的高低价策略。 /// Add normal fee strategies for multiple service types, Will remove the high-low strategies of (SwqosType,TradeType) - pub fn add_normal_fee_strategies( + pub fn set_normal_fee_strategies( swqos_types: &[SwqosType], trade_type: TradeType, cu_limit: u32, @@ -141,30 +97,30 @@ impl GasFeeStrategy { tip: f64, ) { for swqos_type in swqos_types { - GasFeeStrategy::remove_strategy(*swqos_type, trade_type); + GasFeeStrategy::del(*swqos_type, trade_type); + GasFeeStrategy::set(*swqos_type, trade_type, cu_limit, cu_price, tip); } - STRATEGIES.rcu(|current_map| { - let mut new_map = (**current_map).clone(); - for swqos_type in swqos_types { - new_map.insert( - (*swqos_type, trade_type, GasFeeStrategyType::Normal), - GasFeeStrategyValue { cu_limit, cu_price, tip }, - ); - } - Arc::new(new_map) - }); } - /// 为单个服务类型添加标准费率策略,会移除(SwqosType,TradeType)的高低价策略。 - /// Add normal fee strategy for a single service type, Will remove the high-low strategies of (SwqosType,TradeType) - pub fn add_normal_fee_strategy( + pub fn set_normal_fee_strategy( + swqos_type: SwqosType, + cu_limit: u32, + cu_price: u64, + buy_tip: f64, + sell_tip: f64, + ) { + GasFeeStrategy::set(swqos_type, TradeType::Buy, cu_limit, cu_price, buy_tip); + GasFeeStrategy::set(swqos_type, TradeType::Sell, cu_limit, cu_price, sell_tip); + } + + fn set( swqos_type: SwqosType, trade_type: TradeType, cu_limit: u32, cu_price: u64, tip: f64, ) { - GasFeeStrategy::remove_strategy(swqos_type, trade_type); + GasFeeStrategy::del(swqos_type, trade_type); STRATEGIES.rcu(|current_map| { let mut new_map = (**current_map).clone(); new_map.insert( @@ -177,7 +133,7 @@ impl GasFeeStrategy { /// 移除指定(SwqosType,TradeType)的策略。 /// Remove strategy for specified (SwqosType,TradeType) - pub fn remove_strategy(swqos_type: SwqosType, trade_type: TradeType) { + fn del(swqos_type: SwqosType, trade_type: TradeType) { STRATEGIES.rcu(|current_map| { let mut new_map = (**current_map).clone(); new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::Normal)); diff --git a/src/common/nonce_cache.rs b/src/common/nonce_cache.rs index 579aa61..e7e4299 100755 --- a/src/common/nonce_cache.rs +++ b/src/common/nonce_cache.rs @@ -19,6 +19,15 @@ pub struct NonceInfo { pub used: bool, } +/// DurableNonceInfo structure to store durable nonce-related information +#[derive(Clone)] +pub struct DurableNonceInfo { + /// Nonce account address + pub nonce_account: Option, + /// Current nonce value + pub current_nonce: Option, +} + /// NonceInfoStore singleton for storing and managing NonceInfo pub struct NonceCache { /// Internally stored NonceInfo data @@ -50,8 +59,8 @@ impl NonceCache { self.update_nonce_info_partial(nonce_account, None, Some(false)); } - /// Get a copy of NonceInfo - pub fn get_nonce_info(&self) -> NonceInfo { + /// Get a copy of NonceInfo + pub fn get_nonce_info(&self) -> NonceInfo { let nonce_info = self.nonce_info.lock(); NonceInfo { nonce_account: nonce_info.nonce_account, @@ -60,6 +69,20 @@ impl NonceCache { } } + pub fn get_durable_nonce_info() -> DurableNonceInfo { + let nonce_info = Self::get_instance().get_nonce_info(); + let nonce_account = nonce_info.nonce_account; + let current_nonce = if nonce_account.is_some() && nonce_info.current_nonce != Hash::default() { + Some(nonce_info.current_nonce) + } else { + None + }; + DurableNonceInfo { + nonce_account, + current_nonce, + } + } + /// Partially update NonceInfo, only update the passed fields pub fn update_nonce_info_partial( &self, diff --git a/src/lib.rs b/src/lib.rs index c06ba2e..373243b 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub mod swqos; pub mod trading; pub mod utils; use crate::common::TradeConfig; +use crate::common::nonce_cache::DurableNonceInfo; use crate::constants::trade::trade::DEFAULT_SLIPPAGE; use crate::swqos::SwqosClient; use crate::swqos::SwqosConfig; @@ -74,7 +75,7 @@ pub struct TradeBuyParams { /// Optional slippage tolerance in basis points (e.g., 100 = 1%) pub slippage_basis_points: Option, /// Recent blockhash for transaction validity - pub recent_blockhash: Hash, + pub recent_blockhash: Option, /// Protocol-specific parameters (PumpFun, Raydium, etc.) pub extension_params: Box, // Extended configuration @@ -91,9 +92,11 @@ pub struct TradeBuyParams { /// Whether to enable seed-based optimization for account creation pub open_seed_optimize: bool, /// Nonce account for transaction validity - pub nonce_account: Option, - /// Recent nonce for transaction validity - pub current_nonce: Option, + // pub nonce_account: Option, + // /// Recent nonce for transaction validity + // pub current_nonce: Option, + /// Durable nonce information + pub durable_nonce: Option, } /// Parameters for executing sell orders across different DEX protocols @@ -112,7 +115,7 @@ pub struct TradeSellParams { /// Optional slippage tolerance in basis points (e.g., 100 = 1%) pub slippage_basis_points: Option, /// Recent blockhash for transaction validity - pub recent_blockhash: Hash, + pub recent_blockhash: Option, /// Whether to include tip for transaction priority pub with_tip: bool, /// Protocol-specific parameters (PumpFun, Raydium, etc.) @@ -129,9 +132,11 @@ pub struct TradeSellParams { /// Whether to enable seed-based optimization for account creation pub open_seed_optimize: bool, /// Nonce account for transaction validity - pub nonce_account: Option, - /// Recent nonce for transaction validity - pub current_nonce: Option, + // pub nonce_account: Option, + // /// Recent nonce for transaction validity + // pub current_nonce: Option, + /// Durable nonce information + pub durable_nonce: Option, } impl SolanaTrade { @@ -272,8 +277,7 @@ impl SolanaTrade { create_mint_ata: params.create_mint_ata, swqos_clients: self.swqos_clients.clone(), middleware_manager: self.middleware_manager.clone(), - nonce_account: params.nonce_account, - current_nonce: params.current_nonce, + durable_nonce: params.durable_nonce, }; // Validate protocol params @@ -344,8 +348,7 @@ impl SolanaTrade { middleware_manager: self.middleware_manager.clone(), create_wsol_ata: params.create_wsol_ata, close_wsol_ata: params.close_wsol_ata, - nonce_account: params.nonce_account, - current_nonce: params.current_nonce, + durable_nonce: params.durable_nonce, }; // Validate protocol params diff --git a/src/trading/common/nonce_manager.rs b/src/trading/common/nonce_manager.rs index 32ebca2..79ba286 100755 --- a/src/trading/common/nonce_manager.rs +++ b/src/trading/common/nonce_manager.rs @@ -2,6 +2,8 @@ use solana_hash::Hash; use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signature::Keypair, signer::Signer}; use solana_system_interface::instruction::advance_nonce_account; +use crate::common::nonce_cache::DurableNonceInfo; + /// Add nonce advance instruction to the instruction set /// /// Nonce functionality is only used when nonce_pubkey is provided @@ -10,26 +12,29 @@ use solana_system_interface::instruction::advance_nonce_account; pub fn add_nonce_instruction( instructions: &mut Vec, payer: &Keypair, - nonce_account: Option, - current_nonce: Option, + // nonce_account: Option, + // current_nonce: Option, + durable_nonce: Option, ) -> Result<(), anyhow::Error> { - if nonce_account.is_some() && current_nonce.is_some() { - let nonce_advance_ix = advance_nonce_account(&nonce_account.unwrap(), &payer.pubkey()); + if let Some(durable_nonce) = durable_nonce { + let nonce_advance_ix = advance_nonce_account(&durable_nonce.nonce_account.unwrap(), &payer.pubkey()); instructions.push(nonce_advance_ix); } + Ok(()) } /// Get blockhash for transaction /// If nonce account is used, return blockhash from nonce, otherwise return the provided recent_blockhash pub fn get_transaction_blockhash( - recent_blockhash: Hash, - nonce_account: Option, - current_nonce: Option, + recent_blockhash: Option, + durable_nonce: Option, + // nonce_account: Option, + // current_nonce: Option, ) -> Hash { - if nonce_account.is_some() && current_nonce.is_some() { - current_nonce.unwrap() + if let Some(durable_nonce) = durable_nonce { + durable_nonce.current_nonce.unwrap() } else { - recent_blockhash + recent_blockhash.unwrap() } } diff --git a/src/trading/common/transaction_builder.rs b/src/trading/common/transaction_builder.rs index 80262c4..a7ed3d1 100755 --- a/src/trading/common/transaction_builder.rs +++ b/src/trading/common/transaction_builder.rs @@ -16,7 +16,7 @@ use super::{ compute_budget_manager::compute_budget_instructions, nonce_manager::{add_nonce_instruction, get_transaction_blockhash}, }; -use crate::{common::SolanaRpcClient, trading::MiddlewareManager}; +use crate::{common::{nonce_cache::DurableNonceInfo, SolanaRpcClient}, trading::MiddlewareManager}; /// Build standard RPC transaction pub async fn build_transaction( @@ -26,7 +26,7 @@ pub async fn build_transaction( unit_price: u64, business_instructions: Vec, lookup_table_key: Option, - recent_blockhash: Hash, + recent_blockhash: Option, data_size_limit: u32, middleware_manager: Option>, protocol_name: &str, @@ -34,14 +34,15 @@ pub async fn build_transaction( with_tip: bool, tip_account: &Pubkey, tip_amount: f64, - nonce_account: Option, - current_nonce: Option, + durable_nonce: Option, + // nonce_account: Option, + // current_nonce: Option, ) -> Result { let mut instructions = Vec::with_capacity(business_instructions.len() + 5); // Add nonce instruction if let Err(e) = - add_nonce_instruction(&mut instructions, payer.as_ref(), nonce_account, current_nonce) + add_nonce_instruction(&mut instructions, payer.as_ref(), durable_nonce.clone()) { return Err(e); } @@ -67,7 +68,7 @@ pub async fn build_transaction( instructions.extend(business_instructions); // Get blockhash for transaction - let blockhash = get_transaction_blockhash(recent_blockhash, nonce_account, current_nonce); + let blockhash = get_transaction_blockhash(recent_blockhash, durable_nonce.clone()); // Get address lookup table accounts let address_lookup_table_accounts = diff --git a/src/trading/core/parallel.rs b/src/trading/core/parallel.rs index e0142b2..86e49d2 100755 --- a/src/trading/core/parallel.rs +++ b/src/trading/core/parallel.rs @@ -9,6 +9,7 @@ use tokio::task::JoinHandle; use crate::{ common::{GasFeeStrategy, SolanaRpcClient}, + common::nonce_cache::DurableNonceInfo, swqos::{SwqosClient, SwqosType, TradeType}, trading::{common::build_transaction, BuyParams, MiddlewareManager, SellParams}, }; @@ -25,8 +26,9 @@ pub async fn buy_parallel_execute( instructions, params.lookup_table_key, params.recent_blockhash, - params.nonce_account, - params.current_nonce, + params.durable_nonce.clone(), + // params.nonce_account, + // params.current_nonce, params.data_size_limit, params.middleware_manager, protocol_name, @@ -49,8 +51,9 @@ pub async fn sell_parallel_execute( instructions, params.lookup_table_key, params.recent_blockhash, - params.nonce_account, - params.current_nonce, + params.durable_nonce.clone(), + // params.nonce_account, + // params.current_nonce, 0, params.middleware_manager, protocol_name, @@ -68,9 +71,10 @@ async fn parallel_execute( rpc: Option>, instructions: Vec, lookup_table_key: Option, - recent_blockhash: Hash, - nonce_account: Option, - current_nonce: Option, + recent_blockhash: Option, + durable_nonce: Option, + // nonce_account: Option, + // current_nonce: Option, data_size_limit: u32, middleware_manager: Option>, protocol_name: &'static str, @@ -133,6 +137,7 @@ async fn parallel_execute( let swqos_type = swqos_type.clone(); let tip_account = tip_account.clone(); let rpc = rpc.clone(); + let durable_nonce = durable_nonce.clone(); let handle = tokio::spawn(async move { core_affinity::set_for_current(core_id); @@ -156,8 +161,8 @@ async fn parallel_execute( swqos_type != SwqosType::Default, &tip_account, tip_amount, - nonce_account, - current_nonce, + durable_nonce, + // current_nonce, ) .await?; diff --git a/src/trading/core/params.rs b/src/trading/core/params.rs index 41d6df4..8786ad3 100755 --- a/src/trading/core/params.rs +++ b/src/trading/core/params.rs @@ -1,6 +1,7 @@ use super::traits::ProtocolParams; use crate::common::bonding_curve::BondingCurveAccount; use crate::common::SolanaRpcClient; +use crate::common::nonce_cache::DurableNonceInfo; use crate::solana_streamer_sdk::streaming::event_parser::common::EventType; use crate::solana_streamer_sdk::streaming::event_parser::protocols::bonk::BonkTradeEvent; use crate::swqos::SwqosClient; @@ -25,7 +26,7 @@ pub struct BuyParams { pub sol_amount: u64, pub slippage_basis_points: Option, pub lookup_table_key: Option, - pub recent_blockhash: Hash, + pub recent_blockhash: Option, pub data_size_limit: u32, pub wait_transaction_confirmed: bool, pub protocol_params: Box, @@ -35,8 +36,9 @@ pub struct BuyParams { pub create_wsol_ata: bool, pub close_wsol_ata: bool, pub create_mint_ata: bool, - pub nonce_account: Option, - pub current_nonce: Option, + // pub nonce_account: Option, + // pub current_nonce: Option, + pub durable_nonce: Option, } /// Sell parameters @@ -48,7 +50,7 @@ pub struct SellParams { pub token_amount: Option, pub slippage_basis_points: Option, pub lookup_table_key: Option, - pub recent_blockhash: Hash, + pub recent_blockhash: Option, pub wait_transaction_confirmed: bool, pub with_tip: bool, pub protocol_params: Box, @@ -57,8 +59,9 @@ pub struct SellParams { pub middleware_manager: Option>, pub create_wsol_ata: bool, pub close_wsol_ata: bool, - pub nonce_account: Option, - pub current_nonce: Option, + // pub nonce_account: Option, + // pub current_nonce: Option, + pub durable_nonce: Option, } impl std::fmt::Debug for BuyParams {