2025-06-17 23:32:20 +08:00
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
|
|
use super::{
|
|
|
|
|
parallel::parallel_execute_with_tips,
|
|
|
|
|
params::{BuyParams, BuyWithTipParams, SellParams, SellWithTipParams},
|
|
|
|
|
timer::TradeTimer,
|
|
|
|
|
traits::{InstructionBuilder, TradeExecutor},
|
|
|
|
|
};
|
|
|
|
|
use crate::{
|
|
|
|
|
swqos::TradeType,
|
|
|
|
|
trading::common::{build_rpc_transaction, build_sell_transaction},
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-10 18:14:21 +08:00
|
|
|
const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 256 * 1024;
|
|
|
|
|
|
2025-06-17 23:32:20 +08:00
|
|
|
/// 通用交易执行器实现
|
|
|
|
|
pub struct GenericTradeExecutor {
|
|
|
|
|
instruction_builder: Arc<dyn InstructionBuilder>,
|
|
|
|
|
protocol_name: &'static str,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl GenericTradeExecutor {
|
|
|
|
|
pub fn new(
|
|
|
|
|
instruction_builder: Arc<dyn InstructionBuilder>,
|
|
|
|
|
protocol_name: &'static str,
|
|
|
|
|
) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
instruction_builder,
|
|
|
|
|
protocol_name,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
|
impl TradeExecutor for GenericTradeExecutor {
|
2025-07-10 18:14:21 +08:00
|
|
|
async fn buy(&self, mut params: BuyParams) -> Result<()> {
|
|
|
|
|
if params.data_size_limit == 0 {
|
|
|
|
|
params.data_size_limit = MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT;
|
|
|
|
|
}
|
2025-06-17 23:32:20 +08:00
|
|
|
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("构建买入交易指令");
|
|
|
|
|
// 构建指令
|
|
|
|
|
let instructions = self
|
|
|
|
|
.instruction_builder
|
|
|
|
|
.build_buy_instructions(¶ms)
|
|
|
|
|
.await?;
|
2025-07-11 10:40:04 +08:00
|
|
|
timer.stage("构建rpc交易指令");
|
2025-06-17 23:32:20 +08:00
|
|
|
|
|
|
|
|
// 构建交易
|
|
|
|
|
let transaction = build_rpc_transaction(
|
|
|
|
|
params.payer.clone(),
|
|
|
|
|
¶ms.priority_fee,
|
|
|
|
|
instructions,
|
|
|
|
|
params.lookup_table_key,
|
|
|
|
|
params.recent_blockhash,
|
|
|
|
|
params.data_size_limit,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
2025-07-11 10:40:04 +08:00
|
|
|
timer.stage("rpc提交确认");
|
2025-06-17 23:32:20 +08:00
|
|
|
|
|
|
|
|
// 发送交易
|
|
|
|
|
rpc.send_and_confirm_transaction(&transaction).await?;
|
|
|
|
|
timer.finish();
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-10 18:14:21 +08:00
|
|
|
async fn buy_with_tip(&self, mut params: BuyWithTipParams) -> Result<()> {
|
|
|
|
|
if params.data_size_limit == 0 {
|
|
|
|
|
params.data_size_limit = MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT;
|
|
|
|
|
}
|
2025-07-11 10:40:04 +08:00
|
|
|
let timer = TradeTimer::new("构建买入交易指令");
|
2025-06-17 23:32:20 +08:00
|
|
|
|
|
|
|
|
// 验证参数 - 转换为BuyParams进行验证
|
|
|
|
|
let buy_params = BuyParams {
|
|
|
|
|
rpc: params.rpc,
|
|
|
|
|
payer: params.payer.clone(),
|
|
|
|
|
mint: params.mint,
|
|
|
|
|
creator: params.creator,
|
2025-07-10 23:54:49 +08:00
|
|
|
sol_amount: params.sol_amount,
|
2025-06-17 23:32:20 +08:00
|
|
|
slippage_basis_points: params.slippage_basis_points,
|
|
|
|
|
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,
|
|
|
|
|
protocol_params: params.protocol_params.clone(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 构建指令
|
|
|
|
|
let instructions = self
|
|
|
|
|
.instruction_builder
|
|
|
|
|
.build_buy_instructions(&buy_params)
|
|
|
|
|
.await?;
|
2025-07-11 10:40:04 +08:00
|
|
|
|
|
|
|
|
timer.finish();
|
2025-06-17 23:32:20 +08:00
|
|
|
|
|
|
|
|
// 并行执行交易
|
|
|
|
|
parallel_execute_with_tips(
|
2025-07-06 22:06:44 +08:00
|
|
|
params.swqos_clients,
|
2025-06-17 23:32:20 +08:00
|
|
|
params.payer,
|
|
|
|
|
instructions,
|
|
|
|
|
params.priority_fee,
|
|
|
|
|
params.lookup_table_key,
|
|
|
|
|
params.recent_blockhash,
|
|
|
|
|
params.data_size_limit,
|
|
|
|
|
TradeType::Buy,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn sell(&self, params: SellParams) -> 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("构建卖出交易指令");
|
|
|
|
|
|
|
|
|
|
// 构建指令
|
|
|
|
|
let instructions = self
|
|
|
|
|
.instruction_builder
|
|
|
|
|
.build_sell_instructions(¶ms)
|
|
|
|
|
.await?;
|
|
|
|
|
timer.stage("卖出交易指令");
|
|
|
|
|
|
|
|
|
|
// 构建交易
|
|
|
|
|
let transaction = build_sell_transaction(
|
|
|
|
|
params.payer.clone(),
|
|
|
|
|
¶ms.priority_fee,
|
|
|
|
|
instructions,
|
|
|
|
|
params.lookup_table_key,
|
|
|
|
|
params.recent_blockhash,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
timer.stage("卖出交易签名");
|
|
|
|
|
|
|
|
|
|
// 发送交易
|
|
|
|
|
rpc.send_and_confirm_transaction(&transaction).await?;
|
|
|
|
|
timer.finish();
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn sell_with_tip(&self, params: SellWithTipParams) -> Result<()> {
|
2025-07-11 10:40:04 +08:00
|
|
|
let timer = TradeTimer::new("构建卖出交易指令");
|
2025-06-17 23:32:20 +08:00
|
|
|
|
|
|
|
|
// 转换为SellParams进行指令构建
|
|
|
|
|
let sell_params = SellParams {
|
|
|
|
|
rpc: params.rpc,
|
|
|
|
|
payer: params.payer.clone(),
|
|
|
|
|
mint: params.mint,
|
|
|
|
|
creator: params.creator,
|
2025-07-10 23:54:49 +08:00
|
|
|
token_amount: params.token_amount,
|
2025-06-17 23:32:20 +08:00
|
|
|
slippage_basis_points: params.slippage_basis_points,
|
|
|
|
|
priority_fee: params.priority_fee.clone(),
|
|
|
|
|
lookup_table_key: params.lookup_table_key,
|
|
|
|
|
recent_blockhash: params.recent_blockhash,
|
|
|
|
|
protocol_params: params.protocol_params.clone(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 构建指令
|
|
|
|
|
let instructions = self
|
|
|
|
|
.instruction_builder
|
|
|
|
|
.build_sell_instructions(&sell_params)
|
|
|
|
|
.await?;
|
2025-07-11 10:40:04 +08:00
|
|
|
|
|
|
|
|
timer.finish();
|
2025-06-17 23:32:20 +08:00
|
|
|
|
|
|
|
|
// 并行执行交易
|
|
|
|
|
parallel_execute_with_tips(
|
2025-07-06 22:06:44 +08:00
|
|
|
params.swqos_clients,
|
2025-06-17 23:32:20 +08:00
|
|
|
params.payer,
|
|
|
|
|
instructions,
|
|
|
|
|
params.priority_fee,
|
|
|
|
|
params.lookup_table_key,
|
|
|
|
|
params.recent_blockhash,
|
|
|
|
|
0,
|
|
|
|
|
TradeType::Sell,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn protocol_name(&self) -> &'static str {
|
|
|
|
|
self.protocol_name
|
|
|
|
|
}
|
|
|
|
|
}
|