diff --git a/examples/address_lookup/src/main.rs b/examples/address_lookup/src/main.rs index a75629c..9604443 100644 --- a/examples/address_lookup/src/main.rs +++ b/examples/address_lookup/src/main.rs @@ -6,6 +6,7 @@ use std::{ }, }; +use sol_trade_sdk::solana_streamer_sdk::match_event; use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::pumpfun::parser::PUMPFUN_PROGRAM_ID; use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::protocols::pumpfun::PumpFunTradeEvent; use sol_trade_sdk::solana_streamer_sdk::streaming::event_parser::{Protocol, UnifiedEvent}; @@ -13,9 +14,6 @@ use sol_trade_sdk::solana_streamer_sdk::streaming::yellowstone_grpc::{ AccountFilter, TransactionFilter, }; use sol_trade_sdk::solana_streamer_sdk::streaming::YellowstoneGrpc; -use sol_trade_sdk::{ - common::address_lookup::get_address_lookup_table, solana_streamer_sdk::match_event, -}; use sol_trade_sdk::{ common::address_lookup_cache::AddressLookupTableCache, solana_streamer_sdk::streaming::event_parser::common::EventType, @@ -109,13 +107,10 @@ async fn setup_lookup_table_cache( client: Arc, lookup_table_address: Pubkey, ) -> AnyResult<()> { - let lookup_table = get_address_lookup_table(client, &lookup_table_address) - .await - .map_err(|e| anyhow::anyhow!("Failed to get address lookup table: {}", e))?; - AddressLookupTableCache::get_instance() - .add_or_update_table(lookup_table_address, Some(lookup_table)); - + .set_address_lookup_table(client, &lookup_table_address) + .await + .map_err(|e| anyhow::anyhow!("Failed to set address lookup table: {}", e))?; Ok(()) } diff --git a/src/common/address_lookup.rs b/src/common/address_lookup.rs deleted file mode 100755 index 75da864..0000000 --- a/src/common/address_lookup.rs +++ /dev/null @@ -1,364 +0,0 @@ -use solana_program::{ - address_lookup_table::{ - instruction::{ - create_lookup_table as create_lookup_table_instruction, - extend_lookup_table as extend_lookup_table_instruction, - freeze_lookup_table as freeze_lookup_table_instruction, - }, - state::AddressLookupTable, - }, - instruction::Instruction, - pubkey::Pubkey, -}; -use solana_sdk::{ - message::{v0::Message as MessageV0, AddressLookupTableAccount, VersionedMessage}, - signature::{Keypair, Signer}, - transaction::{Transaction, VersionedTransaction}, -}; -use std::{error::Error, sync::Arc}; - -use crate::{common::SolanaRpcClient, constants}; - -/// Create address lookup table (if it doesn't exist) -pub async fn create_lookup_table_if_not_exists( - client: Arc, - authority: &Keypair, - payer: &Keypair, -) -> Result> { - // 1. Calculate the expected lookup table address - let recent_slot = client.get_slot().await?; - let (create_ix, lookup_table_address) = - create_lookup_table_instruction(authority.pubkey(), payer.pubkey(), recent_slot); - - // 2. Create new table - let blockhash = client.get_latest_blockhash().await?; - let transaction = Transaction::new_signed_with_payer( - &[create_ix], - Some(&payer.pubkey()), - &[payer, authority], - blockhash, - ); - - client.send_and_confirm_transaction(&transaction).await?; - - Ok(lookup_table_address) -} - -/// Add addresses to lookup table -pub async fn extend_lookup_table( - client: Arc, - payer: &Keypair, - authority: &Keypair, - lookup_table_address: &Pubkey, - addresses: Vec, -) -> Result<(), Box> { - let extend_ix = extend_lookup_table_instruction( - *lookup_table_address, - authority.pubkey(), - Some(payer.pubkey()), - addresses.clone(), - ); - - let blockhash = client.get_latest_blockhash().await?; - let transaction = Transaction::new_signed_with_payer( - &[extend_ix], - Some(&payer.pubkey()), - &[payer, authority], - blockhash, - ); - - client.send_and_confirm_transaction(&transaction).await?; - - Ok(()) -} - -/// Freeze lookup table to prevent further modifications -pub async fn freeze_lookup_table( - client: Arc, - payer: &Keypair, - authority: &Keypair, - lookup_table_address: &Pubkey, -) -> Result<(), Box> { - let freeze_ix = freeze_lookup_table_instruction(*lookup_table_address, authority.pubkey()); - - let blockhash = client.get_latest_blockhash().await?; - let transaction = Transaction::new_signed_with_payer( - &[freeze_ix], - Some(&payer.pubkey()), - &[payer, authority], - blockhash, - ); - - client.send_and_confirm_transaction(&transaction).await?; - - Ok(()) -} - -/// Get lookup table information -pub async fn get_address_lookup_table( - client: Arc, - lookup_table_address: &Pubkey, -) -> Result> { - let account = client.get_account(lookup_table_address).await?; - let lookup_table = AddressLookupTable::deserialize(&account.data)?; - - let address_lookup_table_account = AddressLookupTableAccount { - key: *lookup_table_address, - addresses: lookup_table.addresses.to_vec(), - }; - - Ok(address_lookup_table_account) -} - -/// Send transaction using lookup table -pub async fn send_transaction_with_lut( - client: Arc, - instructions: Vec, - payer: &Keypair, - signers: Vec<&Keypair>, - address_lookup_tables: Vec, -) -> Result<(), Box> { - let blockhash = client.get_latest_blockhash().await?; - - let message = VersionedMessage::V0(MessageV0::try_compile( - &payer.pubkey(), - &instructions, - &address_lookup_tables, - blockhash, - )?); - - let tx = VersionedTransaction::try_new(message, &signers)?; - - let signature = client.send_and_confirm_transaction(&tx).await?; - - println!("Transaction confirmed: {}", signature); - Ok(()) -} - -/// Send transaction using a specific subset of addresses from lookup table -pub async fn send_transaction_with_filtered_lut( - client: Arc, - instructions: Vec, - payer: &Keypair, - signers: Vec<&Keypair>, - lookup_table: AddressLookupTableAccount, - address_indices_to_use: &[usize], // List of address indices to use -) -> Result<(), Box> { - // Create a new lookup table account containing only selected addresses - let filtered_addresses: Vec = address_indices_to_use - .iter() - .filter_map(|&index| lookup_table.addresses.get(index).copied()) - .collect(); - - println!("Selected {} addresses from lookup table for transaction", filtered_addresses.len()); - for (i, addr) in filtered_addresses.iter().enumerate() { - println!("Using address {}: {}", i, addr); - } - - let filtered_lookup_table = - AddressLookupTableAccount { key: lookup_table.key, addresses: filtered_addresses }; - - let blockhash = client.get_latest_blockhash().await?; - - let message = VersionedMessage::V0(MessageV0::try_compile( - &payer.pubkey(), - &instructions, - &[filtered_lookup_table], - blockhash, - )?); - - let tx = VersionedTransaction::try_new(message, &signers)?; - - let signature = client.send_and_confirm_transaction(&tx).await?; - - println!("Transaction confirmed: {}", signature); - Ok(()) -} - -/// Get recent block slot for creating lookup table -pub async fn get_recent_slot(client: Arc) -> Result> { - let slot = client.get_slot().await?; - Ok(slot) -} - -/// Send transaction using specified address list -/// -/// This method accepts a set of target addresses, automatically finds their indices in the lookup table, -/// then uses these addresses to create a filtered lookup table for sending transactions -/// -/// # Arguments -/// * `instructions` - Transaction instructions -/// * `payer` - Account that pays transaction fees -/// * `signers` - Transaction signers -/// * `lookup_table` - Address lookup table -/// * `addresses_to_use` - List of addresses to use -/// -/// # Returns -/// Returns transaction signature on success, error on failure -pub async fn send_transaction_with_addresses( - client: Arc, - instructions: Vec, - payer: &Keypair, - signers: Vec<&Keypair>, - lookup_table: AddressLookupTableAccount, - addresses_to_use: &[Pubkey], -) -> Result> { - // Build address to index mapping - let mut address_to_index = std::collections::HashMap::new(); - for (i, addr) in lookup_table.addresses.iter().enumerate() { - address_to_index.insert(*addr, i); - } - - // Find indices of all existing addresses - let mut indices_to_use = Vec::new(); - let mut found_addresses = Vec::new(); - let mut missing_addresses = Vec::new(); - - for addr in addresses_to_use { - if let Some(&index) = address_to_index.get(addr) { - indices_to_use.push(index); - found_addresses.push(*addr); - } else { - missing_addresses.push(*addr); - } - } - - // Check if any addresses were not found - if !missing_addresses.is_empty() { - println!("Warning: {} addresses not found in lookup table", missing_addresses.len()); - for (i, addr) in missing_addresses.iter().enumerate() { - println!("Address not found {}: {}", i, addr); - } - } - - // Return error if no addresses were found - if indices_to_use.is_empty() { - return Err(Box::new(std::io::Error::new( - std::io::ErrorKind::NotFound, - "No specified addresses found in lookup table", - ))); - } - - // Create a new lookup table account containing only selected addresses - let filtered_addresses: Vec = indices_to_use - .iter() - .filter_map(|&index| lookup_table.addresses.get(index).copied()) - .collect(); - - println!("Selected {} addresses from lookup table for transaction", filtered_addresses.len()); - for (i, addr) in filtered_addresses.iter().enumerate() { - println!("Using address {}: {}", i, addr); - } - - let filtered_lookup_table = - AddressLookupTableAccount { key: lookup_table.key, addresses: filtered_addresses }; - - let blockhash = client.get_latest_blockhash().await?; - - let message = VersionedMessage::V0(MessageV0::try_compile( - &payer.pubkey(), - &instructions, - &[filtered_lookup_table], - blockhash, - )?); - - let tx = VersionedTransaction::try_new(message, &signers)?; - - let signature = client.send_and_confirm_transaction(&tx).await?; - - println!("Transaction confirmed: {}", signature); - Ok(signature.to_string()) -} - -pub async fn create_pumpfun_lookup_table( - client: Arc, - payer: &Keypair, - authority: &Keypair, -) -> Result> { - let recent_slot = client.get_slot().await?; - let (create_ix, lookup_table_address) = - create_lookup_table_instruction(authority.pubkey(), payer.pubkey(), recent_slot); - - let blockhash = client.get_latest_blockhash().await?; - let transaction = Transaction::new_signed_with_payer( - &[create_ix], - Some(&payer.pubkey()), - &[payer, authority], - blockhash, - ); - - client.send_and_confirm_transaction(&transaction).await?; - - Ok(lookup_table_address) -} - -pub async fn add_pumpfun_address_to_lookup_table( - client: Arc, - payer: &Keypair, - authority: &Keypair, - lookup_table_address: &Pubkey, -) -> Result<(), Box> { - let addresses = get_pumpfun_addresses(payer.pubkey(), vec![]); - extend_lookup_table(client, payer, authority, lookup_table_address, addresses).await?; - - Ok(()) -} - -pub async fn extend_pumpfun_address_to_lookup_table( - client: Arc, - payer: &Keypair, - authority: &Keypair, - lookup_table_address: &Pubkey, - addresses: Vec, -) -> Result<(), Box> { - extend_lookup_table(client, payer, authority, lookup_table_address, addresses).await?; - - Ok(()) -} - -pub fn get_pumpfun_addresses(payer: Pubkey, include_addresses: Vec) -> Vec { - let mut addresses = vec![ - payer, - constants::pumpfun::accounts::PUMPFUN, - constants::pumpfun::accounts::SYSTEM_PROGRAM, - constants::pumpfun::accounts::TOKEN_PROGRAM, - constants::pumpfun::accounts::RENT, - constants::pumpfun::accounts::EVENT_AUTHORITY, - constants::pumpfun::accounts::ASSOCIATED_TOKEN_PROGRAM, - constants::pumpfun::global_constants::GLOBAL_ACCOUNT, - constants::pumpfun::global_constants::FEE_RECIPIENT, - ]; - - addresses.extend(include_addresses); - - addresses -} - -pub fn get_pumpfun_filtered_addresses( - payer: Pubkey, - include_addresses: Vec, -) -> Vec { - let mut addresses = vec![ - payer, - constants::pumpfun::accounts::PUMPFUN, - constants::pumpfun::accounts::SYSTEM_PROGRAM, - constants::pumpfun::accounts::TOKEN_PROGRAM, - constants::pumpfun::accounts::RENT, - constants::pumpfun::accounts::EVENT_AUTHORITY, - constants::pumpfun::accounts::ASSOCIATED_TOKEN_PROGRAM, - constants::pumpfun::global_constants::GLOBAL_ACCOUNT, - constants::pumpfun::global_constants::FEE_RECIPIENT, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_1, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_2, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_3, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_4, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_5, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_6, - constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_7, - // constants::pumpfun::global_constants::PUMPFUN_AMM_FEE_8, - ]; - - addresses.extend(include_addresses); - - addresses -} diff --git a/src/common/address_lookup_cache.rs b/src/common/address_lookup_cache.rs index 44ba63b..f2f0122 100755 --- a/src/common/address_lookup_cache.rs +++ b/src/common/address_lookup_cache.rs @@ -1,6 +1,14 @@ use dashmap::DashMap; -use solana_sdk::{message::AddressLookupTableAccount, pubkey::Pubkey}; -use std::sync::{Arc, OnceLock}; +use solana_sdk::{ + address_lookup_table::state::AddressLookupTable, message::AddressLookupTableAccount, + pubkey::Pubkey, +}; +use std::{ + error::Error, + sync::{Arc, OnceLock}, +}; + +use crate::common::SolanaRpcClient; /// AddressLookupTableInfo struct, stores address lookup table related information #[derive(Clone)] @@ -28,8 +36,24 @@ impl AddressLookupTableCache { .clone() } + /// Get lookup table information + pub async fn set_address_lookup_table( + &self, + client: Arc, + lookup_table_address: &Pubkey, + ) -> Result<(), Box> { + let account = client.get_account(lookup_table_address).await?; + let lookup_table = AddressLookupTable::deserialize(&account.data)?; + let address_lookup_table_account = AddressLookupTableAccount { + key: *lookup_table_address, + addresses: lookup_table.addresses.to_vec(), + }; + self.add_or_update_table(lookup_table_address.clone(), Some(address_lookup_table_account)); + Ok(()) + } + /// Add or update address lookup table information - lock-free implementation - pub fn add_or_update_table( + fn add_or_update_table( &self, lookup_table_address: Pubkey, address_lookup_table: Option, @@ -51,42 +75,8 @@ impl AddressLookupTableCache { } } - /// Remove address lookup table - lock-free implementation - pub fn remove_table(&self, lookup_table_address: &Pubkey) -> bool { - self.tables.remove(lookup_table_address).is_some() - } - - /// Get address lookup table information - lock-free implementation - pub fn get_table(&self, lookup_table_address: &Pubkey) -> Option { - self.tables.get(lookup_table_address).map(|entry| entry.value().clone()) - } - - /// Get all table addresses - lock-free implementation - pub fn get_all_table_addresses(&self) -> Vec { - self.tables.iter().map(|entry| *entry.key()).collect() - } - - /// Check if table exists - lock-free implementation - pub fn table_exists(&self, lookup_table_address: &Pubkey) -> bool { - self.tables.contains_key(lookup_table_address) - } - - /// Update address lookup table content - lock-free implementation - pub fn update_table_content( - &self, - lookup_table_address: &Pubkey, - address_lookup_table: AddressLookupTableAccount, - ) -> bool { - if let Some(mut entry) = self.tables.get_mut(lookup_table_address) { - entry.address_lookup_table = Some(address_lookup_table); - true - } else { - false - } - } - /// Get table content - high-performance lock-free implementation - pub fn get_table_content(&self, lookup_table_address: &Pubkey) -> AddressLookupTableAccount { + fn get_table_content(&self, lookup_table_address: &Pubkey) -> AddressLookupTableAccount { let result = self .tables .get(lookup_table_address) diff --git a/src/common/mod.rs b/src/common/mod.rs index e421d9d..631923f 100755 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,6 +1,5 @@ -pub mod address_lookup; +// pub mod address_lookup; pub mod nonce_cache; -pub mod tip_cache; pub mod types; pub mod address_lookup_cache; pub mod subscription_handle; diff --git a/src/common/tip_cache.rs b/src/common/tip_cache.rs deleted file mode 100755 index 3f6c7b2..0000000 --- a/src/common/tip_cache.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::sync::{Arc, Mutex, OnceLock}; - -/// TipCache 单例,用于存储和管理 tip 金额 -pub struct TipCache { - /// tip 金额 - tip_amount: Mutex, -} - -static TIP_CACHE: OnceLock> = OnceLock::new(); - -impl TipCache { - /// 获取 TipCache 单例实例 - pub fn get_instance() -> Arc { - TIP_CACHE - .get_or_init(|| { - Arc::new(TipCache { - tip_amount: Mutex::new(0.001), - }) - }) - .clone() - } - - /// 初始化 tip 金额 - pub fn init(&self, tip_amount: Option) { - let amount = tip_amount.unwrap_or(0.001); - self.update_tip(amount); - } - - /// 获取 tip 金额 - pub fn get_tip(&self) -> f64 { - *self.tip_amount.lock().unwrap() - } - - /// 更新 tip 金额 - pub fn update_tip(&self, amount: f64) { - *self.tip_amount.lock().unwrap() = amount; - } -} \ No newline at end of file diff --git a/src/common/types.rs b/src/common/types.rs index eddcec6..f8a2dce 100755 --- a/src/common/types.rs +++ b/src/common/types.rs @@ -38,9 +38,10 @@ pub struct PriorityFee { pub tip_unit_price: u64, pub rpc_unit_limit: u32, pub rpc_unit_price: u64, - pub buy_tip_fee: f64, + // 与 swqos 顺序一致 (Matches the order of swqos) pub buy_tip_fees: Vec, - pub sell_tip_fee: f64, + // 与 swqos 顺序一致 (Matches the order of swqos) + pub sell_tip_fees: Vec, } impl Default for PriorityFee { @@ -50,9 +51,10 @@ impl Default for PriorityFee { tip_unit_price: DEFAULT_TIP_UNIT_PRICE, rpc_unit_limit: DEFAULT_RPC_UNIT_LIMIT, rpc_unit_price: DEFAULT_RPC_UNIT_PRICE, - buy_tip_fee: DEFAULT_BUY_TIP_FEE, - buy_tip_fees: vec![], - sell_tip_fee: DEFAULT_SELL_TIP_FEE, + // 与 swqos 顺序一致 (Matches the order of swqos) + buy_tip_fees: vec![DEFAULT_BUY_TIP_FEE], + // 与 swqos 顺序一致 (Matches the order of swqos) + sell_tip_fees: vec![DEFAULT_SELL_TIP_FEE], } } } diff --git a/src/lib.rs b/src/lib.rs index c59e2a3..64138ec 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod trading; pub mod utils; pub use solana_streamer_sdk; +use crate::constants::trade::trade::DEFAULT_SLIPPAGE; use crate::swqos::SwqosConfig; use crate::trading::core::params::BonkParams; use crate::trading::core::params::PumpFunParams; @@ -53,7 +54,7 @@ impl Clone for SolanaTrade { impl SolanaTrade { #[inline] - pub async fn new(payer: Arc, mut trade_config: TradeConfig) -> Self { + pub async fn new(payer: Arc, trade_config: TradeConfig) -> Self { if CryptoProvider::get_default().is_none() { let _ = default_provider() .install_default() @@ -62,23 +63,8 @@ impl SolanaTrade { let rpc_url = trade_config.rpc_url.clone(); let swqos_configs = trade_config.swqos_configs.clone(); - let mut priority_fee = trade_config.priority_fee.clone(); + let priority_fee = trade_config.priority_fee.clone(); let commitment = trade_config.commitment.clone(); - if priority_fee.buy_tip_fees.len() < swqos_configs.len() { - // Fill the array, only fill the missing elements - let mut buy_tip_fees = priority_fee.buy_tip_fees.clone(); - let default_fee = priority_fee.buy_tip_fee; - // Calculate the number of elements that need to be added - let missing_count = swqos_configs.len() - buy_tip_fees.len(); - // Add missing elements using default values - for _ in 0..missing_count { - buy_tip_fees.push(default_fee); - } - // Update buy_tip_fees in priority_fee - priority_fee.buy_tip_fees = buy_tip_fees; - trade_config.priority_fee = priority_fee.clone(); - } - let mut swqos_clients: Vec> = vec![]; for swqos in swqos_configs { @@ -160,6 +146,12 @@ impl SolanaTrade { lookup_table_key: Option, wait_transaction_confirmed: bool, ) -> Result<(), anyhow::Error> { + if slippage_basis_points.is_none() { + println!( + "slippage_basis_points is none, use default slippage basis points: {}", + DEFAULT_SLIPPAGE + ); + } let executor = TradeFactory::create_executor(dex_type.clone()); let protocol_params = extension_params; @@ -179,23 +171,8 @@ impl SolanaTrade { protocol_params: protocol_params.clone(), }; if custom_priority_fee.is_some() { - let mut custom_priority_fee = custom_priority_fee.unwrap(); - // Fill the array, only fill the missing elements - if custom_priority_fee.buy_tip_fees.len() < self.swqos_clients.len() { - let mut buy_tip_fees = custom_priority_fee.buy_tip_fees.clone(); - let default_fee = custom_priority_fee.buy_tip_fee; - // Calculate the number of elements that need to be added - let missing_count = self.swqos_clients.len() - buy_tip_fees.len(); - // Add missing elements using default values - for _ in 0..missing_count { - buy_tip_fees.push(default_fee); - } - // Update buy_tip_fees in custom_priority_fee - custom_priority_fee.buy_tip_fees = buy_tip_fees; - } - buy_params.priority_fee = custom_priority_fee; + buy_params.priority_fee = custom_priority_fee.unwrap(); } - let buy_with_tip_params = buy_params.clone().with_tip(self.swqos_clients.clone()); // Validate protocol params let is_valid_params = match dex_type { @@ -216,7 +193,9 @@ impl SolanaTrade { return Err(anyhow::anyhow!("Invalid protocol params for Trade")); } - executor.buy_with_tip(buy_with_tip_params, self.middleware_manager.clone()).await + executor + .buy_with_tip(buy_params, self.swqos_clients.clone(), self.middleware_manager.clone()) + .await } /// Execute a sell order for a specified token @@ -259,6 +238,12 @@ impl SolanaTrade { lookup_table_key: Option, wait_transaction_confirmed: bool, ) -> Result<(), anyhow::Error> { + if slippage_basis_points.is_none() { + println!( + "slippage_basis_points is none, use default slippage basis points: {}", + DEFAULT_SLIPPAGE + ); + } let executor = TradeFactory::create_executor(dex_type.clone()); let protocol_params = extension_params; @@ -275,25 +260,11 @@ impl SolanaTrade { recent_blockhash, wait_transaction_confirmed: wait_transaction_confirmed, protocol_params: protocol_params.clone(), + with_tip: with_tip, }; if custom_priority_fee.is_some() { - let mut custom_priority_fee = custom_priority_fee.unwrap(); - // Fill the array, only fill the missing elements - if custom_priority_fee.buy_tip_fees.len() < self.swqos_clients.len() { - let mut buy_tip_fees = custom_priority_fee.buy_tip_fees.clone(); - let default_fee = custom_priority_fee.buy_tip_fee; - // Calculate the number of elements that need to be added - let missing_count = self.swqos_clients.len() - buy_tip_fees.len(); - // Add missing elements using default values - for _ in 0..missing_count { - buy_tip_fees.push(default_fee); - } - // Update buy_tip_fees in custom_priority_fee - custom_priority_fee.buy_tip_fees = buy_tip_fees; - } - sell_params.priority_fee = custom_priority_fee; + sell_params.priority_fee = custom_priority_fee.unwrap(); } - let sell_with_tip_params = sell_params.clone().with_tip(self.swqos_clients.clone()); // Validate protocol params let is_valid_params = match dex_type { @@ -315,11 +286,9 @@ impl SolanaTrade { } // Execute sell based on tip preference - if with_tip { - executor.sell_with_tip(sell_with_tip_params, self.middleware_manager.clone()).await - } else { - executor.sell(sell_params, self.middleware_manager.clone()).await - } + executor + .sell_with_tip(sell_params, self.swqos_clients.clone(), self.middleware_manager.clone()) + .await } /// Execute a sell order for a percentage of the specified token amount diff --git a/src/trading/common/compute_budget_manager.rs b/src/trading/common/compute_budget_manager.rs index 61b2217..dc07ab9 100755 --- a/src/trading/common/compute_budget_manager.rs +++ b/src/trading/common/compute_budget_manager.rs @@ -2,72 +2,27 @@ use solana_sdk::{compute_budget::ComputeBudgetInstruction, instruction::Instruct use crate::common::PriorityFee; -/// 为RPC交易添加计算预算指令 -pub fn add_rpc_compute_budget_instructions( - instructions: &mut Vec, - priority_fee: &PriorityFee, - data_size_limit: u32, -) { - instructions - .push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size_limit)); - instructions.push(ComputeBudgetInstruction::set_compute_unit_price( - priority_fee.rpc_unit_price, - )); - instructions.push(ComputeBudgetInstruction::set_compute_unit_limit( - priority_fee.rpc_unit_limit, - )); -} - -/// 为带小费的交易添加计算预算指令 -pub fn add_tip_compute_budget_instructions( - instructions: &mut Vec, - priority_fee: &PriorityFee, - data_size_limit: u32, -) { - instructions - .push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size_limit)); - instructions.push(ComputeBudgetInstruction::set_compute_unit_price( - priority_fee.tip_unit_price, - )); - instructions.push(ComputeBudgetInstruction::set_compute_unit_limit( - priority_fee.tip_unit_limit, - )); -} - -/// 通用的计算预算指令添加函数 +/// 为交易添加计算预算指令 pub fn add_compute_budget_instructions( instructions: &mut Vec, - unit_price: u64, - unit_limit: u32, + priority_fee: &PriorityFee, data_size_limit: u32, + is_rpc: bool, + is_buy: bool, ) { - instructions - .push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size_limit)); - instructions.push(ComputeBudgetInstruction::set_compute_unit_price(unit_price)); - instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(unit_limit)); -} - -pub fn add_sell_compute_budget_instructions( - instructions: &mut Vec, - priority_fee: &PriorityFee, -) { - instructions.push(ComputeBudgetInstruction::set_compute_unit_price( - priority_fee.rpc_unit_price, - )); - instructions.push(ComputeBudgetInstruction::set_compute_unit_limit( - priority_fee.rpc_unit_limit, - )); -} - -/// 为带小费的交易添加计算预算指令 -pub fn add_sell_tip_compute_budget_instructions( - instructions: &mut Vec, - priority_fee: &PriorityFee, -) { - instructions.push(ComputeBudgetInstruction::set_compute_unit_price( - priority_fee.tip_unit_price, - )); - instructions.push(ComputeBudgetInstruction::set_compute_unit_limit( - priority_fee.tip_unit_limit, - )); + if is_buy { + instructions + .push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(data_size_limit)); + } + if is_rpc { + instructions + .push(ComputeBudgetInstruction::set_compute_unit_price(priority_fee.rpc_unit_price)); + instructions + .push(ComputeBudgetInstruction::set_compute_unit_limit(priority_fee.rpc_unit_limit)); + } else { + instructions + .push(ComputeBudgetInstruction::set_compute_unit_price(priority_fee.tip_unit_price)); + instructions + .push(ComputeBudgetInstruction::set_compute_unit_limit(priority_fee.tip_unit_limit)); + } } diff --git a/src/trading/common/nonce_manager.rs b/src/trading/common/nonce_manager.rs index f670b45..e55b4ea 100755 --- a/src/trading/common/nonce_manager.rs +++ b/src/trading/common/nonce_manager.rs @@ -47,10 +47,3 @@ pub fn get_transaction_blockhash(recent_blockhash: Hash) -> Hash { recent_blockhash } } - -/// Check if using nonce account -pub fn is_using_nonce() -> bool { - let nonce_cache = NonceCache::get_instance(); - let nonce_info = nonce_cache.get_nonce_info(); - nonce_info.nonce_account.is_some() -} diff --git a/src/trading/common/transaction_builder.rs b/src/trading/common/transaction_builder.rs index 8549453..c00ce33 100755 --- a/src/trading/common/transaction_builder.rs +++ b/src/trading/common/transaction_builder.rs @@ -13,21 +13,13 @@ use std::sync::Arc; use super::{ address_lookup_manager::get_address_lookup_table_accounts, - compute_budget_manager::{ - add_rpc_compute_budget_instructions, add_tip_compute_budget_instructions, - }, + compute_budget_manager::add_compute_budget_instructions, nonce_manager::{add_nonce_instruction, get_transaction_blockhash}, }; -use crate::{ - common::PriorityFee, - trading::{ - common::{add_sell_compute_budget_instructions, add_sell_tip_compute_budget_instructions}, - MiddlewareManager, - }, -}; +use crate::{common::PriorityFee, trading::MiddlewareManager}; /// 构建标准的RPC交易 -pub async fn build_rpc_transaction( +pub async fn build_transaction( payer: Arc, priority_fee: &PriorityFee, business_instructions: Vec, @@ -37,75 +29,37 @@ pub async fn build_rpc_transaction( middleware_manager: Option>, protocol_name: String, is_buy: bool, -) -> Result { - let mut instructions = vec![]; - - // 添加nonce指令 - if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) { - return Err(e); - } - - // 添加计算预算指令 - add_rpc_compute_budget_instructions(&mut instructions, priority_fee, data_size_limit); - - // 添加业务指令 - instructions.extend(business_instructions); - - // 获取交易使用的blockhash - let blockhash = get_transaction_blockhash(recent_blockhash); - - // 获取地址查找表账户 - let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await; - - // 构建交易 - build_versioned_transaction( - payer, - instructions, - address_lookup_table_accounts, - blockhash, - middleware_manager, - protocol_name, - is_buy, - ) - .await -} - -/// 构建带小费的交易 -pub async fn build_tip_transaction( - payer: Arc, - priority_fee: &PriorityFee, - business_instructions: Vec, + with_tip: bool, tip_account: &Pubkey, tip_amount: f64, - lookup_table_key: Option, - recent_blockhash: Hash, - data_size_limit: u32, - middleware_manager: Option>, - protocol_name: String, - is_buy: bool, ) -> Result { let mut instructions = vec![]; // 添加nonce指令 - if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) { - return Err(e); + if is_buy { + if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) { + return Err(e); + } } // 添加计算预算指令 - add_tip_compute_budget_instructions(&mut instructions, priority_fee, data_size_limit); + add_compute_budget_instructions(&mut instructions, priority_fee, data_size_limit, true, is_buy); // 添加业务指令 instructions.extend(business_instructions); // 添加小费转账指令 - instructions.push(transfer( - &payer.pubkey(), - tip_account, - sol_str_to_lamports(tip_amount.to_string().as_str()).unwrap_or(0), - )); + if with_tip { + instructions.push(transfer( + &payer.pubkey(), + tip_account, + sol_str_to_lamports(tip_amount.to_string().as_str()).unwrap_or(0), + )); + } // 获取交易使用的blockhash - let blockhash = get_transaction_blockhash(recent_blockhash); + let blockhash = + if is_buy { get_transaction_blockhash(recent_blockhash) } else { recent_blockhash }; // 获取地址查找表账户 let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await; @@ -150,136 +104,3 @@ async fn build_versioned_transaction( Ok(transaction) } - -/// 构建带小费的交易(使用PriorityFee中的tip_fee) -pub async fn build_tip_transaction_with_priority_fee( - payer: Arc, - priority_fee: &PriorityFee, - business_instructions: Vec, - tip_account: &Pubkey, - lookup_table_key: Option, - recent_blockhash: Hash, - data_size_limit: u32, - middleware_manager: Option>, - protocol_name: String, - is_buy: bool, -) -> Result { - build_tip_transaction( - payer, - priority_fee, - business_instructions, - tip_account, - priority_fee.buy_tip_fee, - lookup_table_key, - recent_blockhash, - data_size_limit, - middleware_manager, - protocol_name, - is_buy, - ) - .await -} - -/// 构建标准的RPC交易 -pub async fn build_sell_transaction( - payer: Arc, - priority_fee: &PriorityFee, - business_instructions: Vec, - lookup_table_key: Option, - recent_blockhash: Hash, - middleware_manager: Option>, - protocol_name: String, - is_buy: bool, -) -> Result { - let mut instructions = vec![]; - - // 添加计算预算指令 - add_sell_compute_budget_instructions(&mut instructions, priority_fee); - - // 添加业务指令 - instructions.extend(business_instructions); - - // 获取地址查找表账户 - let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await; - - // 构建交易 - build_versioned_transaction( - payer, - instructions, - address_lookup_table_accounts, - recent_blockhash, - middleware_manager, - protocol_name, - is_buy, - ) - .await -} - -pub async fn build_sell_tip_transaction( - payer: Arc, - priority_fee: &PriorityFee, - business_instructions: Vec, - tip_account: &Pubkey, - tip_amount: f64, - lookup_table_key: Option, - recent_blockhash: Hash, - middleware_manager: Option>, - protocol_name: String, - is_buy: bool, -) -> Result { - let mut instructions = vec![]; - - // 添加计算预算指令 - add_sell_tip_compute_budget_instructions(&mut instructions, priority_fee); - - // 添加业务指令 - instructions.extend(business_instructions); - - // 添加小费转账指令 - instructions.push(transfer( - &payer.pubkey(), - tip_account, - sol_str_to_lamports(tip_amount.to_string().as_str()).unwrap_or(0), - )); - - // 获取地址查找表账户 - let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await; - - // 构建交易 - build_versioned_transaction( - payer, - instructions, - address_lookup_table_accounts, - recent_blockhash, - middleware_manager, - protocol_name, - is_buy, - ) - .await -} - -pub async fn build_sell_tip_transaction_with_priority_fee( - payer: Arc, - priority_fee: &PriorityFee, - business_instructions: Vec, - tip_account: &Pubkey, - lookup_table_key: Option, - recent_blockhash: Hash, - middleware_manager: Option>, - protocol_name: String, - is_buy: bool, -) -> Result { - build_sell_tip_transaction( - payer, - priority_fee, - business_instructions, - tip_account, - priority_fee.sell_tip_fee, - lookup_table_key, - recent_blockhash, - middleware_manager, - protocol_name, - is_buy, - ) - .await -} diff --git a/src/trading/core/executor.rs b/src/trading/core/executor.rs index 51f5ab4..e293abd 100755 --- a/src/trading/core/executor.rs +++ b/src/trading/core/executor.rs @@ -1,19 +1,13 @@ -use anyhow::{anyhow, Result}; +use anyhow::Result; use std::sync::Arc; use super::{ parallel::parallel_execute_with_tips, - params::{BuyParams, BuyWithTipParams, SellParams, SellWithTipParams}, + params::{BuyParams, SellParams}, timer::TradeTimer, traits::{InstructionBuilder, TradeExecutor}, }; -use crate::{ - swqos::TradeType, - trading::{ - common::{build_rpc_transaction, build_sell_transaction}, - middleware::MiddlewareManager, - }, -}; +use crate::{swqos::SwqosClient, trading::middleware::MiddlewareManager}; const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 256 * 1024; @@ -34,66 +28,15 @@ impl GenericTradeExecutor { #[async_trait::async_trait] impl TradeExecutor for GenericTradeExecutor { - async fn buy( - &self, - mut params: BuyParams, - middleware_manager: Option>, - ) -> Result<()> { - if params.data_size_limit == 0 { - params.data_size_limit = MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT; - } - if params.rpc.is_none() { - return Err(anyhow!("RPC is not set")); - } - let rpc = params.rpc.as_ref().unwrap().clone(); - let mut timer = TradeTimer::new("Building buy transaction instructions"); - // Build instructions - let instructions = self.instruction_builder.build_buy_instructions(¶ms).await?; - let final_instructions = match middleware_manager.clone() { - Some(middleware_manager) => middleware_manager - .apply_middlewares_process_protocol_instructions( - instructions, - self.protocol_name.to_string(), - true, - )?, - None => instructions, - }; - timer.stage("Building RPC transaction instructions"); - - // Build transaction - let transaction = build_rpc_transaction( - params.payer.clone(), - ¶ms.priority_fee, - final_instructions, - params.lookup_table_key, - params.recent_blockhash, - params.data_size_limit, - middleware_manager, - self.protocol_name.to_string(), - true, - ) - .await?; - timer.stage("RPC submission confirmation"); - - // Send transaction - if params.wait_transaction_confirmed { - rpc.send_and_confirm_transaction(&transaction).await?; - } else { - // Send transaction asynchronously - rpc.send_transaction(&transaction).await?; - } - timer.finish(); - - Ok(()) - } - async fn buy_with_tip( &self, - mut params: BuyWithTipParams, + params: BuyParams, + swqos_clients: Vec>, middleware_manager: Option>, ) -> Result<()> { - if params.data_size_limit == 0 { - params.data_size_limit = MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT; + let mut data_size_limit = params.data_size_limit; + if data_size_limit == 0 { + data_size_limit = MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT; } let timer = TradeTimer::new("Building buy transaction instructions"); @@ -107,7 +50,7 @@ impl TradeExecutor for GenericTradeExecutor { priority_fee: params.priority_fee.clone(), lookup_table_key: params.lookup_table_key, recent_blockhash: params.recent_blockhash, - data_size_limit: params.data_size_limit, + data_size_limit: data_size_limit, wait_transaction_confirmed: params.wait_transaction_confirmed, protocol_params: params.protocol_params.clone(), }; @@ -128,76 +71,28 @@ impl TradeExecutor for GenericTradeExecutor { // Execute transactions in parallel parallel_execute_with_tips( - params.swqos_clients, + swqos_clients, params.payer, final_instructions, params.priority_fee, params.lookup_table_key, params.recent_blockhash, - params.data_size_limit, - TradeType::Buy, + data_size_limit, middleware_manager, self.protocol_name.to_string(), true, params.wait_transaction_confirmed, + true, ) .await?; Ok(()) } - async fn sell( - &self, - params: SellParams, - middleware_manager: Option>, - ) -> Result<()> { - if params.rpc.is_none() { - return Err(anyhow!("RPC is not set")); - } - let rpc = params.rpc.as_ref().unwrap().clone(); - let mut timer = TradeTimer::new("Building sell transaction instructions"); - - // Build instructions - let instructions = self.instruction_builder.build_sell_instructions(¶ms).await?; - let final_instructions = match middleware_manager.clone() { - Some(middleware_manager) => middleware_manager - .apply_middlewares_process_protocol_instructions( - instructions, - self.protocol_name.to_string(), - false, - )?, - None => instructions, - }; - timer.stage("Sell transaction instructions"); - - // Build transaction - let transaction = build_sell_transaction( - params.payer.clone(), - ¶ms.priority_fee, - final_instructions, - params.lookup_table_key, - params.recent_blockhash, - middleware_manager, - self.protocol_name.to_string(), - false, - ) - .await?; - timer.stage("Sell transaction signing"); - - // Send transaction - if params.wait_transaction_confirmed { - rpc.send_and_confirm_transaction(&transaction).await?; - } else { - rpc.send_transaction(&transaction).await?; - } - timer.finish(); - - Ok(()) - } - async fn sell_with_tip( &self, - params: SellWithTipParams, + params: SellParams, + swqos_clients: Vec>, middleware_manager: Option>, ) -> Result<()> { let timer = TradeTimer::new("Building sell transaction instructions"); @@ -214,6 +109,7 @@ impl TradeExecutor for GenericTradeExecutor { recent_blockhash: params.recent_blockhash, wait_transaction_confirmed: params.wait_transaction_confirmed, protocol_params: params.protocol_params.clone(), + with_tip: params.with_tip, }; // Build instructions @@ -232,18 +128,18 @@ impl TradeExecutor for GenericTradeExecutor { // Execute transactions in parallel parallel_execute_with_tips( - params.swqos_clients, + swqos_clients, params.payer, final_instructions, params.priority_fee, params.lookup_table_key, params.recent_blockhash, 0, - TradeType::Sell, middleware_manager, self.protocol_name.to_string(), false, params.wait_transaction_confirmed, + params.with_tip, ) .await?; diff --git a/src/trading/core/parallel.rs b/src/trading/core/parallel.rs index 029c0b1..e532f6b 100755 --- a/src/trading/core/parallel.rs +++ b/src/trading/core/parallel.rs @@ -8,14 +8,7 @@ use tokio::task::JoinHandle; use crate::{ common::PriorityFee, swqos::{SwqosClient, SwqosType, TradeType}, - trading::{ - common::{ - build_rpc_transaction, build_sell_tip_transaction_with_priority_fee, - build_sell_transaction, build_tip_transaction_with_priority_fee, - }, - core::timer::TradeTimer, - MiddlewareManager, - }, + trading::{common::build_transaction, core::timer::TradeTimer, MiddlewareManager}, }; /// Generic function for parallel transaction execution @@ -27,20 +20,30 @@ pub async fn parallel_execute_with_tips( lookup_table_key: Option, recent_blockhash: Hash, data_size_limit: u32, - trade_type: TradeType, middleware_manager: Option>, protocol_name: String, is_buy: bool, wait_transaction_confirmed: bool, + with_tip: bool, ) -> Result<()> { let cores = core_affinity::get_core_ids().unwrap(); let mut handles: Vec>> = vec![]; + if is_buy && swqos_clients.len() > priority_fee.buy_tip_fees.len() { + return Err(anyhow!("Number of tip clients exceeds the configured buy tip fees")); + } + if !is_buy && swqos_clients.len() > priority_fee.sell_tip_fees.len() { + return Err(anyhow!("Number of tip clients exceeds the configured sell tip fees")); + } + for i in 0..swqos_clients.len() { let swqos_client = swqos_clients[i].clone(); + if !with_tip && !matches!(swqos_client.get_swqos_type(), SwqosType::Default) { + continue; + } let payer = payer.clone(); let instructions = instructions.clone(); - let mut priority_fee = priority_fee.clone(); + let priority_fee = priority_fee.clone(); let core_id = cores[i % cores.len()]; let middleware_manager = middleware_manager.clone(); @@ -54,77 +57,40 @@ pub async fn parallel_execute_with_tips( swqos_client.get_swqos_type() )); - let transaction = if matches!(trade_type, TradeType::Sell) - && swqos_client.get_swqos_type() == SwqosType::Default - { - build_sell_transaction( - payer, - &priority_fee, - instructions, - lookup_table_key, - recent_blockhash, - middleware_manager, - protocol_name, - is_buy, - ) - .await? - } else if matches!(trade_type, TradeType::Sell) - && swqos_client.get_swqos_type() != SwqosType::Default - { - let tip_account = swqos_client.get_tip_account()?; - let tip_account = Arc::new(Pubkey::from_str(&tip_account).map_err(|e| anyhow!(e))?); - build_sell_tip_transaction_with_priority_fee( - payer, - &priority_fee, - instructions, - &tip_account, - lookup_table_key, - recent_blockhash, - middleware_manager, - protocol_name, - is_buy, - ) - .await? - } else if swqos_client.get_swqos_type() == SwqosType::Default { - build_rpc_transaction( - payer, - &priority_fee, - instructions, - lookup_table_key, - recent_blockhash, - data_size_limit, - middleware_manager, - protocol_name, - is_buy, - ) - .await? - } else { - let tip_account = swqos_client.get_tip_account()?; - let tip_account = Arc::new(Pubkey::from_str(&tip_account).map_err(|e| anyhow!(e))?); - priority_fee.buy_tip_fee = - priority_fee.buy_tip_fees[i % priority_fee.buy_tip_fees.len()]; + let tip_account = swqos_client.get_tip_account()?; + let tip_account = Arc::new(Pubkey::from_str(&tip_account).map_err(|e| anyhow!(e))?); + if priority_fee.buy_tip_fees.len() == 0 { + return Err(anyhow!("buy_tip_fees is empty")); + } + let tip_amount = priority_fee.buy_tip_fees[i]; - build_tip_transaction_with_priority_fee( - payer, - &priority_fee, - instructions, - &tip_account, - lookup_table_key, - recent_blockhash, - data_size_limit, - middleware_manager, - protocol_name, - is_buy, - ) - .await? - }; + let transaction = build_transaction( + payer, + &priority_fee, + instructions, + lookup_table_key, + recent_blockhash, + data_size_limit, + middleware_manager, + protocol_name, + is_buy, + swqos_client.get_swqos_type() != SwqosType::Default, + &tip_account, + tip_amount, + ) + .await?; timer.stage(format!( "Submitting transaction instructions: {:?}", swqos_client.get_swqos_type() )); - swqos_client.send_transaction(trade_type, &transaction).await?; + swqos_client + .send_transaction( + if is_buy { TradeType::Buy } else { TradeType::Sell }, + &transaction, + ) + .await?; timer.finish(); Ok::<(), anyhow::Error>(()) diff --git a/src/trading/core/params.rs b/src/trading/core/params.rs index 6622196..4e92142 100755 --- a/src/trading/core/params.rs +++ b/src/trading/core/params.rs @@ -15,7 +15,6 @@ use crate::constants::bonk::accounts::{ }; 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; use crate::trading::bonk::common::{ get_amount_in, get_amount_in_net, get_amount_out, get_creator_associated_account, get_platform_associated_account, @@ -25,9 +24,7 @@ use crate::trading::pumpswap::common::{ coin_creator_vault_ata, coin_creator_vault_authority, get_token_balances, }; use crate::trading::raydium_cpmm::common::get_pool_token_balances; - -/// Common buy parameters -/// Contains all necessary information for executing buy transactions +/// Buy parameters #[derive(Clone)] pub struct BuyParams { pub rpc: Option>, @@ -43,26 +40,7 @@ pub struct BuyParams { pub protocol_params: Box, } -/// Buy parameters with MEV service support -/// Extends BuyParams with MEV client configurations for transaction acceleration -#[derive(Clone)] -pub struct BuyWithTipParams { - pub rpc: Option>, - pub swqos_clients: Vec>, - pub payer: Arc, - pub mint: Pubkey, - pub sol_amount: u64, - pub slippage_basis_points: Option, - pub priority_fee: PriorityFee, - pub lookup_table_key: Option, - pub recent_blockhash: Hash, - pub data_size_limit: u32, - pub wait_transaction_confirmed: bool, - pub protocol_params: Box, -} - -/// Common sell parameters -/// Contains all necessary information for executing sell transactions +/// Sell parameters #[derive(Clone)] pub struct SellParams { pub rpc: Option>, @@ -74,23 +52,7 @@ pub struct SellParams { pub lookup_table_key: Option, pub recent_blockhash: Hash, pub wait_transaction_confirmed: bool, - pub protocol_params: Box, -} - -/// Sell parameters with MEV service support -/// Extends SellParams with MEV client configurations for transaction acceleration -#[derive(Clone)] -pub struct SellWithTipParams { - pub rpc: Option>, - pub swqos_clients: Vec>, - pub payer: Arc, - pub mint: Pubkey, - pub token_amount: Option, - pub slippage_basis_points: Option, - pub priority_fee: PriorityFee, - pub lookup_table_key: Option, - pub recent_blockhash: Hash, - pub wait_transaction_confirmed: bool, + pub with_tip: bool, pub protocol_params: Box, } @@ -532,44 +494,3 @@ impl ProtocolParams for RaydiumAmmV4Params { Box::new(self.clone()) } } - -impl BuyParams { - /// Convert to BuyWithTipParams - /// Transforms basic buy parameters into MEV-enabled parameters - pub fn with_tip(self, swqos_clients: Vec>) -> BuyWithTipParams { - BuyWithTipParams { - rpc: self.rpc, - swqos_clients, - payer: self.payer, - mint: self.mint, - sol_amount: self.sol_amount, - slippage_basis_points: self.slippage_basis_points, - priority_fee: self.priority_fee, - lookup_table_key: self.lookup_table_key, - recent_blockhash: self.recent_blockhash, - data_size_limit: self.data_size_limit, - wait_transaction_confirmed: self.wait_transaction_confirmed, - protocol_params: self.protocol_params, - } - } -} - -impl SellParams { - /// Convert to SellWithTipParams - /// Transforms basic sell parameters into MEV-enabled parameters - pub fn with_tip(self, swqos_clients: Vec>) -> SellWithTipParams { - SellWithTipParams { - rpc: self.rpc, - swqos_clients, - payer: self.payer, - mint: self.mint, - token_amount: self.token_amount, - slippage_basis_points: self.slippage_basis_points, - priority_fee: self.priority_fee, - lookup_table_key: self.lookup_table_key, - recent_blockhash: self.recent_blockhash, - wait_transaction_confirmed: self.wait_transaction_confirmed, - protocol_params: self.protocol_params, - } - } -} diff --git a/src/trading/core/traits.rs b/src/trading/core/traits.rs index 95d30b4..9801901 100755 --- a/src/trading/core/traits.rs +++ b/src/trading/core/traits.rs @@ -1,26 +1,28 @@ use std::sync::Arc; +use crate::{swqos::SwqosClient, trading::MiddlewareManager}; use anyhow::Result; use solana_sdk::instruction::Instruction; -use crate::trading::MiddlewareManager; -use super::params::{BuyParams, BuyWithTipParams, SellParams, SellWithTipParams}; +use super::params::{BuyParams, SellParams}; /// 交易执行器trait - 定义了所有交易协议都需要实现的核心方法 #[async_trait::async_trait] pub trait TradeExecutor: Send + Sync { - /// 执行买入交易 - async fn buy(&self, params: BuyParams, middleware_manager: Option>) -> Result<()>; - /// 使用MEV服务执行买入交易 - async fn buy_with_tip(&self, params: BuyWithTipParams, middleware_manager: Option>) -> Result<()>; - - /// 执行卖出交易 - async fn sell(&self, params: SellParams, middleware_manager: Option>) -> Result<()>; - + async fn buy_with_tip( + &self, + params: BuyParams, + swqos_clients: Vec>, + middleware_manager: Option>, + ) -> Result<()>; /// 使用MEV服务执行卖出交易 - async fn sell_with_tip(&self, params: SellWithTipParams, middleware_manager: Option>) -> Result<()>; - + async fn sell_with_tip( + &self, + params: SellParams, + swqos_clients: Vec>, + middleware_manager: Option>, + ) -> Result<()>; /// 获取协议名称 fn protocol_name(&self) -> &'static str; } diff --git a/src/trading/mod.rs b/src/trading/mod.rs index c8dd2d8..1d879d8 100755 --- a/src/trading/mod.rs +++ b/src/trading/mod.rs @@ -8,7 +8,7 @@ pub mod pumpswap; pub mod raydium_amm_v4; pub mod raydium_cpmm; -pub use core::params::{BuyParams, BuyWithTipParams, SellParams, SellWithTipParams}; +pub use core::params::{BuyParams, SellParams}; pub use core::traits::{InstructionBuilder, TradeExecutor}; pub use factory::TradeFactory; pub use middleware::{InstructionMiddleware, MiddlewareManager};