refactor: unify transaction building and execution architecture
- Remove redundant transaction builder functions and merge into single build_transaction() - Simplify compute budget manager with unified add_compute_budget_instructions() - Consolidate trade executor interface by removing separate buy/sell methods - Unify BuyParams/SellParams usage, remove *WithTipParams structs - Streamline parallel execution logic and remove TradeType parameter - Delete obsolete files: address_lookup.rs, tip_cache.rs - Clean up nonce manager by removing unused is_using_nonce() function This refactoring reduces code duplication and provides a cleaner, more maintainable API for transaction building and execution across all trading protocols.
This commit is contained in:
+17
-121
@@ -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<Arc<MiddlewareManager>>,
|
||||
) -> 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<Arc<SwqosClient>>,
|
||||
middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
) -> 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<Arc<MiddlewareManager>>,
|
||||
) -> 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<Arc<SwqosClient>>,
|
||||
middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
) -> 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?;
|
||||
|
||||
|
||||
@@ -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<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
data_size_limit: u32,
|
||||
trade_type: TradeType,
|
||||
middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
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<JoinHandle<Result<()>>> = 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>(())
|
||||
|
||||
@@ -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<Arc<SolanaRpcClient>>,
|
||||
@@ -43,26 +40,7 @@ pub struct BuyParams {
|
||||
pub protocol_params: Box<dyn ProtocolParams>,
|
||||
}
|
||||
|
||||
/// Buy parameters with MEV service support
|
||||
/// Extends BuyParams with MEV client configurations for transaction acceleration
|
||||
#[derive(Clone)]
|
||||
pub struct BuyWithTipParams {
|
||||
pub rpc: Option<Arc<SolanaRpcClient>>,
|
||||
pub swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
pub payer: Arc<Keypair>,
|
||||
pub mint: Pubkey,
|
||||
pub sol_amount: u64,
|
||||
pub slippage_basis_points: Option<u64>,
|
||||
pub priority_fee: PriorityFee,
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
pub recent_blockhash: Hash,
|
||||
pub data_size_limit: u32,
|
||||
pub wait_transaction_confirmed: bool,
|
||||
pub protocol_params: Box<dyn ProtocolParams>,
|
||||
}
|
||||
|
||||
/// Common sell parameters
|
||||
/// Contains all necessary information for executing sell transactions
|
||||
/// Sell parameters
|
||||
#[derive(Clone)]
|
||||
pub struct SellParams {
|
||||
pub rpc: Option<Arc<SolanaRpcClient>>,
|
||||
@@ -74,23 +52,7 @@ pub struct SellParams {
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
pub recent_blockhash: Hash,
|
||||
pub wait_transaction_confirmed: bool,
|
||||
pub protocol_params: Box<dyn ProtocolParams>,
|
||||
}
|
||||
|
||||
/// Sell parameters with MEV service support
|
||||
/// Extends SellParams with MEV client configurations for transaction acceleration
|
||||
#[derive(Clone)]
|
||||
pub struct SellWithTipParams {
|
||||
pub rpc: Option<Arc<SolanaRpcClient>>,
|
||||
pub swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
pub payer: Arc<Keypair>,
|
||||
pub mint: Pubkey,
|
||||
pub token_amount: Option<u64>,
|
||||
pub slippage_basis_points: Option<u64>,
|
||||
pub priority_fee: PriorityFee,
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
pub recent_blockhash: Hash,
|
||||
pub wait_transaction_confirmed: bool,
|
||||
pub with_tip: bool,
|
||||
pub protocol_params: Box<dyn ProtocolParams>,
|
||||
}
|
||||
|
||||
@@ -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<Arc<SwqosClient>>) -> 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<Arc<SwqosClient>>) -> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-12
@@ -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<Arc<MiddlewareManager>>) -> Result<()>;
|
||||
|
||||
/// 使用MEV服务执行买入交易
|
||||
async fn buy_with_tip(&self, params: BuyWithTipParams, middleware_manager: Option<Arc<MiddlewareManager>>) -> Result<()>;
|
||||
|
||||
/// 执行卖出交易
|
||||
async fn sell(&self, params: SellParams, middleware_manager: Option<Arc<MiddlewareManager>>) -> Result<()>;
|
||||
|
||||
async fn buy_with_tip(
|
||||
&self,
|
||||
params: BuyParams,
|
||||
swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
) -> Result<()>;
|
||||
/// 使用MEV服务执行卖出交易
|
||||
async fn sell_with_tip(&self, params: SellWithTipParams, middleware_manager: Option<Arc<MiddlewareManager>>) -> Result<()>;
|
||||
|
||||
async fn sell_with_tip(
|
||||
&self,
|
||||
params: SellParams,
|
||||
swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
) -> Result<()>;
|
||||
/// 获取协议名称
|
||||
fn protocol_name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user