refactor: update API with DexParamEnum and simplify TradeConfig

- Introduce DexParamEnum to replace Dex enum for protocol parameters
- Simplify TradeConfig::new() to accept only 3 essential parameters
- Update all examples to use new DexParamEnum API
- Optimize executor and params modules
- Remove deprecated wsol_use_seed and mint_use_seed parameters
- Fix fast_fn module exports
This commit is contained in:
Wood
2025-12-08 01:35:40 +08:00
parent de8c55e599
commit 80ad2e052e
24 changed files with 240 additions and 226 deletions
+51 -8
View File
@@ -34,6 +34,7 @@ struct TaskResult {
success: bool,
signature: Signature,
error: Option<anyhow::Error>,
swqos_type: SwqosType, // 🔧 增加:记录SWQOS类型
}
struct ResultCollector {
@@ -66,24 +67,44 @@ impl ResultCollector {
self.completed_count.fetch_add(1, Ordering::Release);
}
async fn wait_for_success(&self) -> Option<(bool, Signature, Option<anyhow::Error>)> {
async fn wait_for_success(&self) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>)> {
let start = Instant::now();
let timeout = std::time::Duration::from_secs(30);
loop {
// 🚀 Acquire 确保看到 push 的内容
if self.success_flag.load(Ordering::Acquire) {
// 🔧 修复:收集所有签名
let mut signatures = Vec::new();
let mut has_success = false;
while let Some(result) = self.results.pop() {
signatures.push(result.signature);
if result.success {
return Some((true, result.signature, None));
has_success = true;
}
}
if has_success && !signatures.is_empty() {
return Some((true, signatures, None));
}
}
let completed = self.completed_count.load(Ordering::Acquire);
if completed >= self.total_tasks {
// 🔧 修复:收集所有签名
let mut signatures = Vec::new();
let mut last_error = None;
let mut any_success = false;
while let Some(result) = self.results.pop() {
return Some((result.success, result.signature, result.error));
signatures.push(result.signature);
if result.success {
any_success = true;
}
if result.error.is_some() {
last_error = result.error;
}
}
if !signatures.is_empty() {
return Some((any_success, signatures, last_error));
}
return None;
}
@@ -95,15 +116,31 @@ impl ResultCollector {
}
}
fn get_first(&self) -> Option<(bool, Signature, Option<anyhow::Error>,)> {
if let Some(result) = self.results.pop() {
Some((result.success, result.signature, result.error))
fn get_first(&self) -> Option<(bool, Vec<Signature>, Option<anyhow::Error>)> {
// 🔧 修复:收集已提交的所有签名
let mut signatures = Vec::new();
let mut has_success = false;
let mut last_error = None;
while let Some(result) = self.results.pop() {
signatures.push(result.signature);
if result.success {
has_success = true;
}
if result.error.is_some() {
last_error = result.error;
}
}
if !signatures.is_empty() {
Some((has_success, signatures, last_error))
} else {
None
}
}
}
/// 🔧 修复:返回Vec<Signature>支持多SWQOS并发交易
pub async fn execute_parallel(
swqos_clients: Vec<Arc<SwqosClient>>,
payer: Arc<Keypair>,
@@ -119,7 +156,7 @@ pub async fn execute_parallel(
wait_transaction_confirmed: bool,
with_tip: bool,
gas_fee_strategy: GasFeeStrategy,
) -> Result<(bool, Signature, Option<anyhow::Error>)> {
) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)> {
let _exec_start = Instant::now();
if swqos_clients.is_empty() {
@@ -241,6 +278,7 @@ pub async fn execute_parallel(
success: false,
signature: Signature::default(),
error: Some(e),
swqos_type, // 🔧 记录SWQOS类型
});
return;
}
@@ -268,7 +306,12 @@ pub async fn execute_parallel(
// Transaction sent
if let Some(signature) = transaction.signatures.first() {
collector.submit(TaskResult { success, signature: *signature, error: err });
collector.submit(TaskResult {
success,
signature: *signature,
error: err,
swqos_type, // 🔧 记录SWQOS类型
});
}
});
}
+36 -59
View File
@@ -44,7 +44,7 @@ impl GenericTradeExecutor {
#[async_trait::async_trait]
impl TradeExecutor for GenericTradeExecutor {
async fn swap(&self, params: SwapParams) -> Result<(bool, Signature, Option<anyhow::Error>)> {
async fn swap(&self, params: SwapParams) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)> {
let total_start = Instant::now();
// 判断买卖方向
@@ -152,30 +152,21 @@ impl TradeExecutor for GenericTradeExecutor {
let total_elapsed = total_start.elapsed();
// Get performance metrics using fast timestamp
let timestamp_ns = SYSCALL_BYPASS.fast_timestamp_nanos();
// Print all timing metrics at once to avoid blocking critical path
println!("[Timestamp] {}ns", timestamp_ns);
println!(
"[Build Instructions] Time: {:.3}ms ({:.0}μs)",
build_elapsed.as_micros() as f64 / 1000.0,
build_elapsed.as_micros()
);
println!(
"[Before Submit] {:.3}ms ({:.0}μs)",
before_submit_elapsed.as_micros() as f64 / 1000.0,
before_submit_elapsed.as_micros()
);
println!(
"[Send Transaction] Time: {:.3}ms ({:.0}μs)",
send_elapsed.as_micros() as f64 / 1000.0,
send_elapsed.as_micros()
);
println!(
"[Total Time] {:.3}ms ({:.0}μs)",
total_elapsed.as_micros() as f64 / 1000.0,
total_elapsed.as_micros()
);
#[cfg(feature = "perf-trace")]
{
let timestamp_ns = SYSCALL_BYPASS.fast_timestamp_nanos();
log::trace!(
"[Execute] timestamp_ns={} build_us={} before_submit_us={} send_us={} total_us={}",
timestamp_ns,
build_elapsed.as_micros(),
before_submit_elapsed.as_micros(),
send_elapsed.as_micros(),
total_elapsed.as_micros()
);
}
#[cfg(not(feature = "perf-trace"))]
let _ = (build_elapsed, before_submit_elapsed, send_elapsed, total_elapsed);
result
}
@@ -185,7 +176,7 @@ impl TradeExecutor for GenericTradeExecutor {
}
}
/// Simulate transaction using RPC client
/// 🔧 修复:Simulate模式返回Vec<Signature>(单个RPC模拟)
async fn simulate_transaction(
rpc: Option<Arc<SolanaRpcClient>>,
payer: Arc<Keypair>,
@@ -199,7 +190,7 @@ async fn simulate_transaction(
is_buy: bool,
with_tip: bool,
gas_fee_strategy: GasFeeStrategy,
) -> Result<(bool, Signature, Option<anyhow::Error>)> {
) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)> {
use crate::trading::common::build_transaction;
use solana_client::rpc_config::RpcSimulateTransactionConfig;
use solana_commitment_config::CommitmentLevel;
@@ -267,44 +258,30 @@ async fn simulate_transaction(
.clone();
if let Some(err) = simulate_result.value.err {
println!("\n========== [Simulation Failed] ==========");
println!("Error Type: {:?}", err);
println!("Signature: {:?}", signature);
// Print logs
if let Some(logs) = simulate_result.value.logs {
println!("\n========== Transaction Logs ==========");
for (i, log) in logs.iter().enumerate() {
println!("{:3}. {}", i + 1, log);
#[cfg(feature = "perf-trace")]
{
log::warn!("[Simulation Failed] error={:?} signature={:?}", err, signature);
if let Some(logs) = &simulate_result.value.logs {
log::trace!("Transaction logs: {:?}", logs);
}
if let Some(units_consumed) = simulate_result.value.units_consumed {
log::trace!("Compute Units Consumed: {}", units_consumed);
}
}
// Print account usage
if let Some(units_consumed) = simulate_result.value.units_consumed {
println!("\n========== Resource Consumption ==========");
println!("Compute Units Consumed: {}", units_consumed);
}
println!("=========================================\n");
return Ok((false, signature, Some(anyhow::anyhow!("{:?}", err))));
return Ok((false, vec![signature], Some(anyhow::anyhow!("{:?}", err))));
}
// Simulation succeeded
println!("\n========== [Simulation Succeeded] ==========");
println!("Signature: {:?}", signature);
if let Some(units_consumed) = simulate_result.value.units_consumed {
println!("Compute Units Consumed: {}", units_consumed);
}
if let Some(logs) = simulate_result.value.logs {
println!("\n========== Transaction Logs ==========");
for (i, log) in logs.iter().enumerate() {
println!("{:3}. {}", i + 1, log);
#[cfg(feature = "perf-trace")]
{
log::info!("[Simulation Succeeded] signature={:?}", signature);
if let Some(units_consumed) = simulate_result.value.units_consumed {
log::trace!("Compute Units Consumed: {}", units_consumed);
}
if let Some(logs) = &simulate_result.value.logs {
log::trace!("Transaction logs: {:?}", logs);
}
}
println!("============================================\n");
Ok((true, signature, None))
Ok((true, vec![signature], None))
}
+28 -63
View File
@@ -1,4 +1,3 @@
use super::traits::ProtocolParams;
use crate::common::bonding_curve::BondingCurveAccount;
use crate::common::nonce_cache::DurableNonceInfo;
use crate::common::spl_associated_token_account::get_associated_token_address_with_program_id;
@@ -14,6 +13,32 @@ use solana_sdk::message::AddressLookupTableAccount;
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use std::sync::Arc;
/// DEX 参数枚举 - 零开销抽象替代 Box<dyn ProtocolParams>
#[derive(Clone)]
pub enum DexParamEnum {
PumpFun(PumpFunParams),
PumpSwap(PumpSwapParams),
Bonk(BonkParams),
RaydiumCpmm(RaydiumCpmmParams),
RaydiumAmmV4(RaydiumAmmV4Params),
MeteoraDammV2(MeteoraDammV2Params),
}
impl DexParamEnum {
/// 获取内部参数的 Any 引用,用于向后兼容的类型检查
#[inline]
pub fn as_any(&self) -> &dyn std::any::Any {
match self {
DexParamEnum::PumpFun(p) => p,
DexParamEnum::PumpSwap(p) => p,
DexParamEnum::Bonk(p) => p,
DexParamEnum::RaydiumCpmm(p) => p,
DexParamEnum::RaydiumAmmV4(p) => p,
DexParamEnum::MeteoraDammV2(p) => p,
}
}
}
/// Swap parameters
#[derive(Clone)]
pub struct SwapParams {
@@ -30,7 +55,7 @@ pub struct SwapParams {
pub recent_blockhash: Option<Hash>,
pub data_size_limit: u32,
pub wait_transaction_confirmed: bool,
pub protocol_params: Box<dyn ProtocolParams>,
pub protocol_params: DexParamEnum,
pub open_seed_optimize: bool,
pub swqos_clients: Vec<Arc<SwqosClient>>,
pub middleware_manager: Option<Arc<MiddlewareManager>>,
@@ -47,7 +72,7 @@ pub struct SwapParams {
impl std::fmt::Debug for SwapParams {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SwapParams: {:?}", self)
write!(f, "SwapParams: ...")
}
}
@@ -178,16 +203,6 @@ impl PumpFunParams {
}
}
impl ProtocolParams for PumpFunParams {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_box(&self) -> Box<dyn ProtocolParams> {
Box::new(self.clone())
}
}
/// PumpSwap Protocol Specific Parameters
///
/// Parameters for configuring PumpSwap trading protocol, including liquidity pool information,
@@ -326,16 +341,6 @@ impl PumpSwapParams {
}
}
impl ProtocolParams for PumpSwapParams {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_box(&self) -> Box<dyn ProtocolParams> {
Box::new(self.clone())
}
}
/// Bonk protocol specific parameters
/// Configuration parameters specific to Bonk trading protocol
#[derive(Clone, Default)]
@@ -512,16 +517,6 @@ impl BonkParams {
}
}
impl ProtocolParams for BonkParams {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_box(&self) -> Box<dyn ProtocolParams> {
Box::new(self.clone())
}
}
/// RaydiumCpmm protocol specific parameters
/// Configuration parameters specific to Raydium CPMM trading protocol
#[derive(Clone)]
@@ -609,16 +604,6 @@ impl RaydiumCpmmParams {
}
}
impl ProtocolParams for RaydiumCpmmParams {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_box(&self) -> Box<dyn ProtocolParams> {
Box::new(self.clone())
}
}
/// RaydiumCpmm protocol specific parameters
/// Configuration parameters specific to Raydium CPMM trading protocol
#[derive(Clone)]
@@ -670,16 +655,6 @@ impl RaydiumAmmV4Params {
}
}
impl ProtocolParams for RaydiumAmmV4Params {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_box(&self) -> Box<dyn ProtocolParams> {
Box::new(self.clone())
}
}
/// MeteoraDammV2 protocol specific parameters
/// Configuration parameters specific to Meteora Damm V2 trading protocol
#[derive(Clone)]
@@ -731,13 +706,3 @@ impl MeteoraDammV2Params {
})
}
}
impl ProtocolParams for MeteoraDammV2Params {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_box(&self) -> Box<dyn ProtocolParams> {
Box::new(self.clone())
}
}
+5 -16
View File
@@ -5,7 +5,11 @@ use solana_sdk::{instruction::Instruction, signature::Signature};
/// 交易执行器trait - 定义了所有交易协议都需要实现的核心方法
#[async_trait::async_trait]
pub trait TradeExecutor: Send + Sync {
async fn swap(&self, params: SwapParams) -> Result<(bool, Signature, Option<anyhow::Error>)>;
/// 🔧 修复:返回Vec<Signature>支持多SWQOS并发交易
/// - bool: 是否至少有一个交易成功
/// - Vec<Signature>: 所有提交的交易签名(按SWQOS顺序)
/// - Option<anyhow::Error>: 最后一个错误(如果全部失败)
async fn swap(&self, params: SwapParams) -> Result<(bool, Vec<Signature>, Option<anyhow::Error>)>;
/// 获取协议名称
fn protocol_name(&self) -> &'static str;
}
@@ -19,18 +23,3 @@ pub trait InstructionBuilder: Send + Sync {
/// 构建卖出指令
async fn build_sell_instructions(&self, params: &SwapParams) -> Result<Vec<Instruction>>;
}
/// 协议特定参数trait - 允许每个协议定义自己的参数
pub trait ProtocolParams: Send + Sync {
/// 将参数转换为Any以便向下转型
fn as_any(&self) -> &dyn std::any::Any;
/// 克隆参数
fn clone_box(&self) -> Box<dyn ProtocolParams>;
}
impl Clone for Box<dyn ProtocolParams> {
fn clone(&self) -> Self {
self.clone_box()
}
}