From 4780e71c11ac1c8015ce2862f77d736a1086535f Mon Sep 17 00:00:00 2001 From: ysq Date: Mon, 22 Sep 2025 00:05:20 +0800 Subject: [PATCH] refactor: unify trading parameters and add USD1 token pool support - Merge BuyParams and SellParams into unified SwapParams structure - Add USD1 token pool support with related constants and configurations - Refactor trade executor by combining buy_with_tip and sell_with_tip into swap method - Update all protocol instruction builders to support new parameter structure - Standardize ATA creation/closing parameter naming conventions - Update example code to use new API interfaces - Optimize trading logic with automatic direction detection based on input token type --- examples/bonk_sniper_trading/src/main.rs | 1 + examples/cli_trading/src/main.rs | 4 +- examples/raydium_cpmm_trading/src/main.rs | 13 +-- src/constants/accounts.rs | 8 ++ src/instruction/bonk.rs | 112 ++++++++++++++++------ src/instruction/pumpfun.rs | 34 +++---- src/instruction/pumpswap.rs | 32 +++---- src/instruction/raydium_amm_v4.rs | 32 +++---- src/instruction/raydium_cpmm.rs | 42 ++++---- src/instruction/utils/bonk.rs | 9 ++ src/lib.rs | 64 ++++++++----- src/trading/core/executor.rs | 57 +++++------ src/trading/core/parallel.rs | 18 ++-- src/trading/core/params.rs | 68 ++++++------- src/trading/core/traits.rs | 11 +-- src/trading/mod.rs | 4 +- 16 files changed, 274 insertions(+), 235 deletions(-) diff --git a/examples/bonk_sniper_trading/src/main.rs b/examples/bonk_sniper_trading/src/main.rs index acbd815..4389d9c 100644 --- a/examples/bonk_sniper_trading/src/main.rs +++ b/examples/bonk_sniper_trading/src/main.rs @@ -137,6 +137,7 @@ async fn bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyResult< trade_info.platform_config, trade_info.platform_associated_account, trade_info.creator_associated_account, + trade_info.global_config, )), lookup_table_key: None, wait_transaction_confirmed: true, diff --git a/examples/cli_trading/src/main.rs b/examples/cli_trading/src/main.rs index 371a805..994c1fe 100644 --- a/examples/cli_trading/src/main.rs +++ b/examples/cli_trading/src/main.rs @@ -694,7 +694,7 @@ async fn handle_buy_bonk( println!(" Slippage: {}%", slippage.unwrap()); } let mint_pubkey = Pubkey::from_str(mint)?; - let param = BonkParams::from_mint_by_rpc(&client.rpc, &mint_pubkey).await?; + let param = BonkParams::from_mint_by_rpc(&client.rpc, &mint_pubkey, false).await?; let recent_blockhash = client.rpc.get_latest_blockhash().await?; let sol_lamports = sol_str_to_lamports(sol_amount.to_string().as_str()).unwrap(); @@ -1059,7 +1059,7 @@ async fn handle_sell_bonk( } let client = initialize_real_client().await?; let mint_pubkey = Pubkey::from_str(mint)?; - let param = BonkParams::from_mint_by_rpc(&client.rpc, &mint_pubkey).await?; + let param = BonkParams::from_mint_by_rpc(&client.rpc, &mint_pubkey, false).await?; let recent_blockhash = client.rpc.get_latest_blockhash().await?; let sell_params = TradeSellParams { diff --git a/examples/raydium_cpmm_trading/src/main.rs b/examples/raydium_cpmm_trading/src/main.rs index d75d700..fca0c82 100644 --- a/examples/raydium_cpmm_trading/src/main.rs +++ b/examples/raydium_cpmm_trading/src/main.rs @@ -111,17 +111,8 @@ fn create_event_callback() -> impl Fn(Box) { /// Initializes a new SolanaTrade client with configuration async fn create_solana_trade_client() -> AnyResult { println!("🚀 Initializing SolanaTrade client..."); - - let payer = Keypair::from_bytes( - &std::fs::read_to_string("/Users/ysq/.config/solana/sdk_test.json") - .unwrap() - .trim_matches(|c| c == '[' || c == ']') - .split(',') - .map(|s| s.trim().parse::().unwrap()) - .collect::>(), - ) - .unwrap(); - let rpc_url = "https://ultra-bold-sunset.solana-mainnet.quiknode.pro/1210ea22139565495810678ac0aa33243fea8406/".to_string(); + let payer = Keypair::from_base58_string("use_your_payer_keypair_here"); + let rpc_url = "https://api.mainnet-beta.solana.com".to_string(); let commitment = CommitmentConfig::confirmed(); let swqos_configs: Vec = vec![SwqosConfig::Default(rpc_url.clone())]; let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment); diff --git a/src/constants/accounts.rs b/src/constants/accounts.rs index 640f2d9..72a9492 100644 --- a/src/constants/accounts.rs +++ b/src/constants/accounts.rs @@ -34,6 +34,14 @@ pub const WSOL_TOKEN_ACCOUNT_META: solana_sdk::instruction::AccountMeta = is_writable: false, }; +pub const USD1_TOKEN_ACCOUNT: Pubkey = pubkey!("USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB"); +pub const USD1_TOKEN_ACCOUNT_META: solana_sdk::instruction::AccountMeta = + solana_sdk::instruction::AccountMeta { + pubkey: USD1_TOKEN_ACCOUNT, + is_signer: false, + is_writable: false, + }; + pub const RENT: Pubkey = solana_sdk::sysvar::rent::id(); pub const RENT_META: solana_sdk::instruction::AccountMeta = solana_sdk::instruction::AccountMeta { pubkey: RENT, is_signer: false, is_writable: false }; diff --git a/src/instruction/bonk.rs b/src/instruction/bonk.rs index d0718c1..e529fe2 100755 --- a/src/instruction/bonk.rs +++ b/src/instruction/bonk.rs @@ -7,7 +7,7 @@ use crate::{ trading::{ common::utils::get_token_balance, core::{ - params::{BonkParams, BuyParams, SellParams}, + params::{BonkParams, SwapParams}, traits::InstructionBuilder, }, }, @@ -27,11 +27,11 @@ pub struct BonkInstructionBuilder; #[async_trait::async_trait] impl InstructionBuilder for BonkInstructionBuilder { - async fn build_buy_instructions(&self, params: &BuyParams) -> Result> { + async fn build_buy_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== - if params.sol_amount == 0 { + if params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Amount cannot be zero")); } let protocol_params = params @@ -40,16 +40,34 @@ impl InstructionBuilder for BonkInstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for Bonk"))?; + let usd1_pool = protocol_params.global_config == accounts::USD1_GLOBAL_CONFIG; + let pool_state = if protocol_params.pool_state == Pubkey::default() { - get_pool_pda(¶ms.mint, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + if usd1_pool { + get_pool_pda(¶ms.output_mint, &crate::constants::USD1_TOKEN_ACCOUNT).unwrap() + } else { + get_pool_pda(¶ms.output_mint, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + } } else { protocol_params.pool_state }; + let global_config = if usd1_pool { + accounts::USD1_GLOBAL_CONFIG_META + } else { + accounts::GLOBAL_CONFIG_META + }; + + let quote_token_mint = if usd1_pool { + crate::constants::USD1_TOKEN_ACCOUNT_META + } else { + crate::constants::WSOL_TOKEN_ACCOUNT_META + }; + // ======================================== // Trade calculation and account address preparation // ======================================== - let amount_in: u64 = params.sol_amount; + let amount_in: u64 = params.input_amount.unwrap_or(0); let share_fee_rate: u64 = 0; let minimum_amount_out: u64 = get_buy_token_amount_from_sol_amount( amount_in, @@ -63,25 +81,33 @@ impl InstructionBuilder for BonkInstructionBuilder { let user_base_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &protocol_params.mint_token_program, params.open_seed_optimize, ); let user_quote_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - &crate::constants::WSOL_TOKEN_ACCOUNT, + if usd1_pool { + &crate::constants::USD1_TOKEN_ACCOUNT + } else { + &crate::constants::WSOL_TOKEN_ACCOUNT + }, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ); let base_vault_account = if protocol_params.base_vault == Pubkey::default() { - get_vault_pda(&pool_state, ¶ms.mint).unwrap() + get_vault_pda(&pool_state, ¶ms.output_mint).unwrap() } else { protocol_params.base_vault }; let quote_vault_account = if protocol_params.quote_vault == Pubkey::default() { - get_vault_pda(&pool_state, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + if usd1_pool { + get_vault_pda(&pool_state, &crate::constants::USD1_TOKEN_ACCOUNT).unwrap() + } else { + get_vault_pda(&pool_state, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + } } else { protocol_params.quote_vault }; @@ -91,17 +117,17 @@ impl InstructionBuilder for BonkInstructionBuilder { // ======================================== let mut instructions = Vec::with_capacity(6); - if params.create_wsol_ata { + if params.create_input_mint_ata && !usd1_pool { instructions .extend(crate::trading::common::handle_wsol(¶ms.payer.pubkey(), amount_in)); } - if params.create_mint_ata { + if params.create_output_mint_ata { instructions.extend( crate::common::fast_fn::create_associated_token_account_idempotent_fast_use_seed( ¶ms.payer.pubkey(), ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &protocol_params.mint_token_program, params.open_seed_optimize, ), @@ -117,15 +143,15 @@ impl InstructionBuilder for BonkInstructionBuilder { let accounts: [AccountMeta; 18] = [ AccountMeta::new(params.payer.pubkey(), true), // Payer (signer) accounts::AUTHORITY_META, // Authority (readonly) - accounts::GLOBAL_CONFIG_META, // Global Config (readonly) + global_config, // Global Config (readonly) AccountMeta::new_readonly(protocol_params.platform_config, false), // Platform Config (readonly) AccountMeta::new(pool_state, false), // Pool State AccountMeta::new(user_base_token_account, false), // User Base Token AccountMeta::new(user_quote_token_account, false), // User Quote Token AccountMeta::new(base_vault_account, false), // Base Vault AccountMeta::new(quote_vault_account, false), // Quote Vault - AccountMeta::new_readonly(params.mint, false), // Base Token Mint (readonly) - crate::constants::WSOL_TOKEN_ACCOUNT_META, // Quote Token Mint (readonly) + AccountMeta::new_readonly(params.output_mint, false), // Base Token Mint (readonly) + quote_token_mint, // Quote Token Mint (readonly) AccountMeta::new_readonly(protocol_params.mint_token_program, false), // Base Token Program (readonly) crate::constants::TOKEN_PROGRAM_META, // Quote Token Program (readonly) accounts::EVENT_AUTHORITY_META, // Event Authority (readonly) @@ -137,14 +163,14 @@ impl InstructionBuilder for BonkInstructionBuilder { instructions.push(Instruction::new_with_bytes(accounts::BONK, &data, accounts.to_vec())); - if params.close_wsol_ata { + if params.close_input_mint_ata { instructions.extend(crate::trading::common::close_wsol(¶ms.payer.pubkey())); } Ok(instructions) } - async fn build_sell_instructions(&self, params: &SellParams) -> Result> { + async fn build_sell_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -158,12 +184,14 @@ impl InstructionBuilder for BonkInstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for Bonk"))?; + let usd1_pool = protocol_params.global_config == accounts::USD1_GLOBAL_CONFIG; + let rpc = params.rpc.as_ref().unwrap().clone(); - let mut amount = params.token_amount; - if params.token_amount.is_none() || params.token_amount.unwrap_or(0) == 0 { + let mut amount = params.input_amount; + if params.input_amount.is_none() || params.input_amount.unwrap_or(0) == 0 { let balance_u64 = - get_token_balance(rpc.as_ref(), ¶ms.payer.pubkey(), ¶ms.mint).await?; + get_token_balance(rpc.as_ref(), ¶ms.payer.pubkey(), ¶ms.input_mint).await?; amount = Some(balance_u64); } let amount = amount.unwrap_or(0); @@ -173,11 +201,27 @@ impl InstructionBuilder for BonkInstructionBuilder { } let pool_state = if protocol_params.pool_state == Pubkey::default() { - get_pool_pda(¶ms.mint, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + if usd1_pool { + get_pool_pda(¶ms.input_mint, &crate::constants::USD1_TOKEN_ACCOUNT).unwrap() + } else { + get_pool_pda(¶ms.input_mint, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + } } else { protocol_params.pool_state }; + let global_config = if usd1_pool { + accounts::USD1_GLOBAL_CONFIG_META + } else { + accounts::GLOBAL_CONFIG_META + }; + + let quote_token_mint = if usd1_pool { + crate::constants::USD1_TOKEN_ACCOUNT_META + } else { + crate::constants::WSOL_TOKEN_ACCOUNT_META + }; + // ======================================== // Trade calculation and account address preparation // ======================================== @@ -194,25 +238,33 @@ impl InstructionBuilder for BonkInstructionBuilder { let user_base_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.input_mint, &protocol_params.mint_token_program, params.open_seed_optimize, ); let user_quote_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - &crate::constants::WSOL_TOKEN_ACCOUNT, + if usd1_pool { + &crate::constants::USD1_TOKEN_ACCOUNT + } else { + &crate::constants::WSOL_TOKEN_ACCOUNT + }, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ); let base_vault_account = if protocol_params.base_vault == Pubkey::default() { - get_vault_pda(&pool_state, ¶ms.mint).unwrap() + get_vault_pda(&pool_state, ¶ms.input_mint).unwrap() } else { protocol_params.base_vault }; let quote_vault_account = if protocol_params.quote_vault == Pubkey::default() { - get_vault_pda(&pool_state, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + if usd1_pool { + get_vault_pda(&pool_state, &crate::constants::USD1_TOKEN_ACCOUNT).unwrap() + } else { + get_vault_pda(&pool_state, &crate::constants::WSOL_TOKEN_ACCOUNT).unwrap() + } } else { protocol_params.quote_vault }; @@ -222,7 +274,7 @@ impl InstructionBuilder for BonkInstructionBuilder { // ======================================== let mut instructions = Vec::with_capacity(3); - if params.create_wsol_ata { + if params.close_output_mint_ata && !usd1_pool { instructions.extend(crate::trading::common::create_wsol_ata(¶ms.payer.pubkey())); } @@ -235,15 +287,15 @@ impl InstructionBuilder for BonkInstructionBuilder { let accounts: [AccountMeta; 18] = [ AccountMeta::new(params.payer.pubkey(), true), // Payer (signer) accounts::AUTHORITY_META, // Authority (readonly) - accounts::GLOBAL_CONFIG_META, // Global Config (readonly) + global_config, // Global Config (readonly) AccountMeta::new_readonly(protocol_params.platform_config, false), // Platform Config (readonly) AccountMeta::new(pool_state, false), // Pool State AccountMeta::new(user_base_token_account, false), // User Base Token AccountMeta::new(user_quote_token_account, false), // User Quote Token AccountMeta::new(base_vault_account, false), // Base Vault AccountMeta::new(quote_vault_account, false), // Quote Vault - AccountMeta::new_readonly(params.mint, false), // Base Token Mint (readonly) - crate::constants::WSOL_TOKEN_ACCOUNT_META, // Quote Token Mint (readonly) + AccountMeta::new_readonly(params.input_mint, false), // Base Token Mint (readonly) + quote_token_mint, // Quote Token Mint (readonly) AccountMeta::new_readonly(protocol_params.mint_token_program, false), // Base Token Program (readonly) crate::constants::TOKEN_PROGRAM_META, // Quote Token Program (readonly) accounts::EVENT_AUTHORITY_META, // Event Authority (readonly) @@ -255,7 +307,7 @@ impl InstructionBuilder for BonkInstructionBuilder { instructions.push(Instruction::new_with_bytes(accounts::BONK, &data, accounts.to_vec())); - if params.close_wsol_ata { + if params.close_output_mint_ata { instructions.extend(crate::trading::common::close_wsol(¶ms.payer.pubkey())); } diff --git a/src/instruction/pumpfun.rs b/src/instruction/pumpfun.rs index 056a07c..66e8640 100755 --- a/src/instruction/pumpfun.rs +++ b/src/instruction/pumpfun.rs @@ -1,7 +1,7 @@ use crate::{ constants::trade::trade::DEFAULT_SLIPPAGE, trading::core::{ - params::{BuyParams, PumpFunParams, SellParams}, + params::{PumpFunParams, SwapParams}, traits::InstructionBuilder, }, }; @@ -25,7 +25,7 @@ pub struct PumpFunInstructionBuilder; #[async_trait::async_trait] impl InstructionBuilder for PumpFunInstructionBuilder { - async fn build_buy_instructions(&self, params: &BuyParams) -> Result> { + async fn build_buy_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -35,7 +35,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for PumpFun"))?; - if params.sol_amount == 0 { + if params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Amount cannot be zero")); } @@ -51,16 +51,16 @@ impl InstructionBuilder for PumpFunInstructionBuilder { bonding_curve.virtual_sol_reserves as u128, bonding_curve.real_token_reserves as u128, creator, - params.sol_amount, + params.input_amount.unwrap_or(0), ); let max_sol_cost = calculate_with_slippage_buy( - params.sol_amount, + params.input_amount.unwrap_or(0), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), ); let bonding_curve_addr = if bonding_curve.account == Pubkey::default() { - get_bonding_curve_pda(¶ms.mint).unwrap() + get_bonding_curve_pda(¶ms.output_mint).unwrap() } else { bonding_curve.account }; @@ -69,7 +69,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { if protocol_params.associated_bonding_curve == Pubkey::default() { crate::common::fast_fn::get_associated_token_address_with_program_id_fast( &bonding_curve_addr, - ¶ms.mint, + ¶ms.output_mint, &crate::constants::TOKEN_PROGRAM, ) } else { @@ -79,7 +79,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { let user_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ); @@ -93,12 +93,12 @@ impl InstructionBuilder for PumpFunInstructionBuilder { let mut instructions = Vec::with_capacity(2); // Create associated token account - if params.create_mint_ata { + if params.create_output_mint_ata { instructions.extend( crate::common::fast_fn::create_associated_token_account_idempotent_fast_use_seed( ¶ms.payer.pubkey(), ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ), @@ -113,7 +113,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { let accounts: [AccountMeta; 16] = [ global_constants::GLOBAL_ACCOUNT_META, global_constants::FEE_RECIPIENT_META, - AccountMeta::new_readonly(params.mint, false), + AccountMeta::new_readonly(params.output_mint, false), AccountMeta::new(bonding_curve_addr, false), AccountMeta::new(associated_bonding_curve, false), AccountMeta::new(user_token_account, false), @@ -138,7 +138,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { Ok(instructions) } - async fn build_sell_instructions(&self, params: &SellParams) -> Result> { + async fn build_sell_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -148,7 +148,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for PumpFun"))?; - let token_amount = if let Some(amount) = params.token_amount { + let token_amount = if let Some(amount) = params.input_amount { if amount == 0 { return Err(anyhow!("Amount cannot be zero")); } @@ -177,7 +177,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { ); let bonding_curve_addr = if bonding_curve.account == Pubkey::default() { - get_bonding_curve_pda(¶ms.mint).unwrap() + get_bonding_curve_pda(¶ms.input_mint).unwrap() } else { bonding_curve.account }; @@ -186,7 +186,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { if protocol_params.associated_bonding_curve == Pubkey::default() { crate::common::fast_fn::get_associated_token_address_with_program_id_fast( &bonding_curve_addr, - ¶ms.mint, + ¶ms.input_mint, &crate::constants::TOKEN_PROGRAM, ) } else { @@ -196,7 +196,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { let user_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.input_mint, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ); @@ -214,7 +214,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder { let accounts: [AccountMeta; 14] = [ global_constants::GLOBAL_ACCOUNT_META, global_constants::FEE_RECIPIENT_META, - AccountMeta::new_readonly(params.mint, false), + AccountMeta::new_readonly(params.input_mint, false), AccountMeta::new(bonding_curve_addr, false), AccountMeta::new(associated_bonding_curve, false), AccountMeta::new(user_token_account, false), diff --git a/src/instruction/pumpswap.rs b/src/instruction/pumpswap.rs index 1d27cc2..3481c76 100755 --- a/src/instruction/pumpswap.rs +++ b/src/instruction/pumpswap.rs @@ -7,7 +7,7 @@ use crate::{ trading::{ common::wsol_manager, core::{ - params::{BuyParams, PumpSwapParams, SellParams}, + params::{PumpSwapParams, SwapParams}, traits::InstructionBuilder, }, }, @@ -25,7 +25,7 @@ pub struct PumpSwapInstructionBuilder; #[async_trait::async_trait] impl InstructionBuilder for PumpSwapInstructionBuilder { - async fn build_buy_instructions(&self, params: &BuyParams) -> Result> { + async fn build_buy_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -35,7 +35,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for PumpSwap"))?; - if params.sol_amount == 0 { + if params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Amount cannot be zero")); } @@ -46,8 +46,8 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { let pool_quote_token_reserves = protocol_params.pool_quote_token_reserves; let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata; let params_coin_creator_vault_authority = protocol_params.coin_creator_vault_authority; - let create_wsol_ata = params.create_wsol_ata; - let close_wsol_ata = params.close_wsol_ata; + let create_wsol_ata = params.create_input_mint_ata; + let close_wsol_ata = params.close_input_mint_ata; let base_token_program = protocol_params.base_token_program; let quote_token_program = protocol_params.quote_token_program; let pool_base_token_account = protocol_params.pool_base_token_account; @@ -70,7 +70,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { let (token_amount, sol_amount) = if quote_mint_is_wsol { let result = buy_quote_input_internal( - params.sol_amount, + params.input_amount.unwrap_or(0), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), pool_base_token_reserves, pool_quote_token_reserves, @@ -81,7 +81,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { (result.base, result.max_quote) } else { let result = sell_base_input_internal( - params.sol_amount, + params.input_amount.unwrap_or(0), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), pool_base_token_reserves, pool_quote_token_reserves, @@ -89,7 +89,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { ) .unwrap(); // min_quote_amount_out, base_amount_in - (result.min_quote, params.sol_amount) + (result.min_quote, params.input_amount.unwrap_or(0)) }; let user_base_token_account = @@ -118,7 +118,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { .extend(crate::trading::common::handle_wsol(¶ms.payer.pubkey(), sol_amount)); } - if params.create_mint_ata { + if params.create_output_mint_ata { instructions.extend( crate::common::fast_fn::create_associated_token_account_idempotent_fast_use_seed( ¶ms.payer.pubkey(), @@ -191,7 +191,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { Ok(instructions) } - async fn build_sell_instructions(&self, params: &SellParams) -> Result> { + async fn build_sell_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -210,8 +210,8 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { let pool_quote_token_account = protocol_params.pool_quote_token_account; let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata; let params_coin_creator_vault_authority = protocol_params.coin_creator_vault_authority; - let create_wsol_ata = params.create_wsol_ata; - let close_wsol_ata = params.close_wsol_ata; + let create_wsol_ata = params.create_output_mint_ata; + let close_wsol_ata = params.close_output_mint_ata; let base_token_program = protocol_params.base_token_program; let quote_token_program = protocol_params.quote_token_program; @@ -220,7 +220,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { { return Err(anyhow!("Invalid base mint and quote mint")); } - if params.token_amount.is_none() { + if params.input_amount.is_none() { return Err(anyhow!("Token amount is not set")); } @@ -235,7 +235,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { let (token_amount, sol_amount) = if quote_mint_is_wsol { let result = sell_base_input_internal( - params.token_amount.unwrap(), + params.input_amount.unwrap(), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), pool_base_token_reserves, pool_quote_token_reserves, @@ -243,10 +243,10 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { ) .unwrap(); // base_amount_in, min_quote_amount_out - (params.token_amount.unwrap(), result.min_quote) + (params.input_amount.unwrap(), result.min_quote) } else { let result = buy_quote_input_internal( - params.token_amount.unwrap(), + params.input_amount.unwrap(), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), pool_base_token_reserves, pool_quote_token_reserves, diff --git a/src/instruction/raydium_amm_v4.rs b/src/instruction/raydium_amm_v4.rs index 6bc8af2..ee3a424 100755 --- a/src/instruction/raydium_amm_v4.rs +++ b/src/instruction/raydium_amm_v4.rs @@ -2,7 +2,7 @@ use crate::{ constants::trade::trade::DEFAULT_SLIPPAGE, instruction::utils::raydium_amm_v4::{accounts, SWAP_BASE_IN_DISCRIMINATOR}, trading::core::{ - params::{BuyParams, RaydiumAmmV4Params, SellParams}, + params::{RaydiumAmmV4Params, SwapParams}, traits::InstructionBuilder, }, utils::calc::raydium_amm_v4::compute_swap_amount, @@ -18,11 +18,11 @@ pub struct RaydiumAmmV4InstructionBuilder; #[async_trait::async_trait] impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { - async fn build_buy_instructions(&self, params: &BuyParams) -> Result> { + async fn build_buy_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== - if params.sol_amount == 0 { + if params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Amount cannot be zero")); } let protocol_params = params @@ -35,7 +35,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { // Trade calculation and account address preparation // ======================================== let is_base_in = protocol_params.coin_mint == crate::constants::WSOL_TOKEN_ACCOUNT; - let amount_in: u64 = params.sol_amount; + let amount_in: u64 = params.input_amount.unwrap_or(0); let swap_result = compute_swap_amount( protocol_params.coin_reserve, protocol_params.pc_reserve, @@ -55,7 +55,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { let user_destination_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ); @@ -65,17 +65,17 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { // ======================================== let mut instructions = Vec::with_capacity(6); - if params.create_wsol_ata { + if params.create_input_mint_ata { instructions .extend(crate::trading::common::handle_wsol(¶ms.payer.pubkey(), amount_in)); } - if params.create_mint_ata { + if params.create_output_mint_ata { instructions.extend( crate::common::fast_fn::create_associated_token_account_idempotent_fast_use_seed( ¶ms.payer.pubkey(), ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ), @@ -114,7 +114,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { accounts.to_vec(), )); - if params.close_wsol_ata { + if params.close_input_mint_ata { // Close wSOL ATA account, reclaim rent instructions.extend(crate::trading::common::close_wsol(¶ms.payer.pubkey())); } @@ -122,7 +122,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { Ok(instructions) } - async fn build_sell_instructions(&self, params: &SellParams) -> Result> { + async fn build_sell_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -132,7 +132,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for RaydiumCpmm"))?; - if params.token_amount.is_none() || params.token_amount.unwrap_or(0) == 0 { + if params.input_amount.is_none() || params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Token amount is not set")); } @@ -144,7 +144,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { protocol_params.coin_reserve, protocol_params.pc_reserve, is_base_in, - params.token_amount.unwrap_or(0), + params.input_amount.unwrap_or(0), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), ); let minimum_amount_out = swap_result.min_amount_out; @@ -152,7 +152,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { let user_source_token_account = crate::common::fast_fn::get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.input_mint, &crate::constants::TOKEN_PROGRAM, params.open_seed_optimize, ); @@ -169,7 +169,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { // ======================================== let mut instructions = Vec::with_capacity(3); - if params.create_wsol_ata { + if params.create_output_mint_ata { instructions.extend(crate::trading::common::create_wsol_ata(¶ms.payer.pubkey())); } @@ -196,7 +196,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { // Create instruction data let mut data = [0u8; 17]; data[..1].copy_from_slice(&SWAP_BASE_IN_DISCRIMINATOR); - data[1..9].copy_from_slice(¶ms.token_amount.unwrap_or(0).to_le_bytes()); + data[1..9].copy_from_slice(¶ms.input_amount.unwrap_or(0).to_le_bytes()); data[9..17].copy_from_slice(&minimum_amount_out.to_le_bytes()); instructions.push(Instruction::new_with_bytes( @@ -205,7 +205,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder { accounts.to_vec(), )); - if params.close_wsol_ata { + if params.close_output_mint_ata { instructions.extend(crate::trading::common::close_wsol(¶ms.payer.pubkey())); } diff --git a/src/instruction/raydium_cpmm.rs b/src/instruction/raydium_cpmm.rs index 0bee5e8..4106bd2 100755 --- a/src/instruction/raydium_cpmm.rs +++ b/src/instruction/raydium_cpmm.rs @@ -6,7 +6,7 @@ use crate::{ SWAP_BASE_IN_DISCRIMINATOR, }, trading::core::{ - params::{BuyParams, RaydiumCpmmParams, SellParams}, + params::{RaydiumCpmmParams, SwapParams}, traits::InstructionBuilder, }, utils::calc::raydium_cpmm::compute_swap_amount, @@ -23,11 +23,11 @@ pub struct RaydiumCpmmInstructionBuilder; #[async_trait::async_trait] impl InstructionBuilder for RaydiumCpmmInstructionBuilder { - async fn build_buy_instructions(&self, params: &BuyParams) -> Result> { + async fn build_buy_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== - if params.sol_amount == 0 { + if params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Amount cannot be zero")); } let protocol_params = params @@ -57,7 +57,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { protocol_params.base_token_program }; - let amount_in: u64 = params.sol_amount; + let amount_in: u64 = params.input_amount.unwrap_or(0); let result = compute_swap_amount( protocol_params.base_reserve, protocol_params.quote_reserve, @@ -75,7 +75,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { ); let mint_token_account = get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &mint_token_program, params.open_seed_optimize, ); @@ -87,7 +87,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { true, ); let mint_vault_account = - get_vault_account(&pool_state, ¶ms.mint, protocol_params, false); + get_vault_account(&pool_state, ¶ms.output_mint, protocol_params, false); let observation_state_account = if protocol_params.observation_state == Pubkey::default() { get_observation_state_pda(&pool_state).unwrap() @@ -100,17 +100,17 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { // ======================================== let mut instructions = Vec::with_capacity(6); - if params.create_wsol_ata { + if params.create_input_mint_ata { instructions .extend(crate::trading::common::handle_wsol(¶ms.payer.pubkey(), amount_in)); } - if params.create_mint_ata { + if params.create_output_mint_ata { instructions.extend( crate::common::fast_fn::create_associated_token_account_idempotent_fast_use_seed( ¶ms.payer.pubkey(), ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.output_mint, &mint_token_program, params.open_seed_optimize, ), @@ -130,7 +130,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { crate::constants::TOKEN_PROGRAM_META, // Input Token Program (readonly) AccountMeta::new_readonly(mint_token_program, false), // Output Token Program (readonly) crate::constants::WSOL_TOKEN_ACCOUNT_META, // Input token mint (readonly) - AccountMeta::new_readonly(params.mint, false), // Output token mint (readonly) + AccountMeta::new_readonly(params.output_mint, false), // Output token mint (readonly) AccountMeta::new(observation_state_account, false), // Observation State Account ]; // Create instruction data @@ -145,7 +145,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { accounts.to_vec(), )); - if params.close_wsol_ata { + if params.close_input_mint_ata { // Close wSOL ATA account, reclaim rent instructions.extend(crate::trading::common::close_wsol(¶ms.payer.pubkey())); } @@ -153,7 +153,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { Ok(instructions) } - async fn build_sell_instructions(&self, params: &SellParams) -> Result> { + async fn build_sell_instructions(&self, params: &SwapParams) -> Result> { // ======================================== // Parameter validation and basic data preparation // ======================================== @@ -163,7 +163,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { .downcast_ref::() .ok_or_else(|| anyhow!("Invalid protocol params for RaydiumCpmm"))?; - if params.token_amount.is_none() || params.token_amount.unwrap_or(0) == 0 { + if params.input_amount.is_none() || params.input_amount.unwrap_or(0) == 0 { return Err(anyhow!("Token amount is not set")); } @@ -181,7 +181,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { // ======================================== // Trade calculation and account address preparation // ======================================== - let is_base_in = protocol_params.base_mint == params.mint; + let is_base_in = protocol_params.base_mint == params.input_mint; let mint_token_program = if is_base_in { protocol_params.base_token_program } else { @@ -192,7 +192,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { protocol_params.base_reserve, protocol_params.quote_reserve, is_base_in, - params.token_amount.unwrap_or(0), + params.input_amount.unwrap_or(0), params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), ) .min_amount_out; @@ -205,7 +205,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { ); let mint_token_account = get_associated_token_address_with_program_id_fast_use_seed( ¶ms.payer.pubkey(), - ¶ms.mint, + ¶ms.input_mint, &mint_token_program, params.open_seed_optimize, ); @@ -217,7 +217,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { true, ); let mint_vault_account = - get_vault_account(&pool_state, ¶ms.mint, protocol_params, false); + get_vault_account(&pool_state, ¶ms.input_mint, protocol_params, false); let observation_state_account = if protocol_params.observation_state == Pubkey::default() { get_observation_state_pda(&pool_state).unwrap() @@ -230,7 +230,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { // ======================================== let mut instructions = Vec::with_capacity(3); - if params.create_wsol_ata { + if params.create_output_mint_ata { instructions.extend(crate::trading::common::create_wsol_ata(¶ms.payer.pubkey())); } @@ -246,14 +246,14 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { AccountMeta::new(wsol_vault_account, false), // Output Vault Account AccountMeta::new_readonly(mint_token_program, false), // Input Token Program (readonly) crate::constants::TOKEN_PROGRAM_META, // Output Token Program (readonly) - AccountMeta::new_readonly(params.mint, false), // Input token mint (readonly) + AccountMeta::new_readonly(params.input_mint, false), // Input token mint (readonly) crate::constants::WSOL_TOKEN_ACCOUNT_META, // Output token mint (readonly) AccountMeta::new(observation_state_account, false), // Observation State Account ]; // Create instruction data let mut data = [0u8; 24]; data[..8].copy_from_slice(&SWAP_BASE_IN_DISCRIMINATOR); - data[8..16].copy_from_slice(¶ms.token_amount.unwrap_or(0).to_le_bytes()); + data[8..16].copy_from_slice(¶ms.input_amount.unwrap_or(0).to_le_bytes()); data[16..24].copy_from_slice(&minimum_amount_out.to_le_bytes()); instructions.push(Instruction::new_with_bytes( @@ -262,7 +262,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder { accounts.to_vec(), )); - if params.close_wsol_ata { + if params.close_output_mint_ata { // Close wSOL ATA account, reclaim rent instructions.extend(crate::trading::common::close_wsol(¶ms.payer.pubkey())); } diff --git a/src/instruction/utils/bonk.rs b/src/instruction/utils/bonk.rs index 45b2ed1..fb55887 100644 --- a/src/instruction/utils/bonk.rs +++ b/src/instruction/utils/bonk.rs @@ -17,6 +17,7 @@ pub mod accounts { pub const AUTHORITY: Pubkey = pubkey!("WLHv2UAZm6z4KyaaELi5pjdbJh6RESMva1Rnn8pJVVh"); pub const GLOBAL_CONFIG: Pubkey = pubkey!("6s1xP3hpbAfFoNtUNF8mfHsjr2Bd97JxFJRWLbL6aHuX"); + pub const USD1_GLOBAL_CONFIG: Pubkey = pubkey!("EPiZbnrThjyLnoQ6QQzkxeFqyL5uyg9RzNHHAudUPxBz"); pub const EVENT_AUTHORITY: Pubkey = pubkey!("2DPAtwB8L12vrMRExbLuyGnC7n2J5LNoZQSejeQGpwkr"); pub const BONK: Pubkey = pubkey!("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"); @@ -37,6 +38,14 @@ pub mod accounts { is_signer: false, is_writable: false, }; + + pub const USD1_GLOBAL_CONFIG_META: solana_sdk::instruction::AccountMeta = + solana_sdk::instruction::AccountMeta { + pubkey: USD1_GLOBAL_CONFIG, + is_signer: false, + is_writable: false, + }; + pub const EVENT_AUTHORITY_META: solana_sdk::instruction::AccountMeta = solana_sdk::instruction::AccountMeta { pubkey: EVENT_AUTHORITY, diff --git a/src/lib.rs b/src/lib.rs index 373243b..f2384e2 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,9 +5,11 @@ pub mod protos; pub mod swqos; pub mod trading; pub mod utils; -use crate::common::TradeConfig; use crate::common::nonce_cache::DurableNonceInfo; +use crate::common::TradeConfig; use crate::constants::trade::trade::DEFAULT_SLIPPAGE; +use crate::constants::SOL_TOKEN_ACCOUNT; +use crate::constants::WSOL_TOKEN_ACCOUNT; use crate::swqos::SwqosClient; use crate::swqos::SwqosConfig; use crate::trading::core::params::BonkParams; @@ -17,9 +19,8 @@ use crate::trading::core::params::RaydiumAmmV4Params; use crate::trading::core::params::RaydiumCpmmParams; use crate::trading::core::traits::ProtocolParams; use crate::trading::factory::DexType; -use crate::trading::BuyParams; use crate::trading::MiddlewareManager; -use crate::trading::SellParams; +use crate::trading::SwapParams; use crate::trading::TradeFactory; use common::SolanaRpcClient; use parking_lot::Mutex; @@ -91,10 +92,6 @@ pub struct TradeBuyParams { pub create_mint_ata: bool, /// 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, /// Durable nonce information pub durable_nonce: Option, } @@ -131,10 +128,6 @@ pub struct TradeSellParams { pub close_wsol_ata: bool, /// 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, /// Durable nonce information pub durable_nonce: Option, } @@ -259,12 +252,19 @@ impl SolanaTrade { } let executor = TradeFactory::create_executor(params.dex_type.clone()); let protocol_params = params.extension_params; - - let buy_params = BuyParams { + let input_mint = if params.dex_type == DexType::PumpFun { + SOL_TOKEN_ACCOUNT + } else { + WSOL_TOKEN_ACCOUNT + }; + let buy_params = SwapParams { rpc: Some(self.rpc.clone()), payer: self.payer.clone(), - mint: params.mint, - sol_amount: params.sol_amount, + input_mint: input_mint, + output_mint: params.mint, + input_token_program: None, + output_token_program: None, + input_amount: Some(params.sol_amount), slippage_basis_points: params.slippage_basis_points, lookup_table_key: params.lookup_table_key, recent_blockhash: params.recent_blockhash, @@ -272,12 +272,14 @@ impl SolanaTrade { wait_transaction_confirmed: params.wait_transaction_confirmed, protocol_params: protocol_params.clone(), open_seed_optimize: params.open_seed_optimize, - create_wsol_ata: params.create_wsol_ata, - close_wsol_ata: params.close_wsol_ata, - create_mint_ata: params.create_mint_ata, swqos_clients: self.swqos_clients.clone(), middleware_manager: self.middleware_manager.clone(), durable_nonce: params.durable_nonce, + with_tip: true, + create_input_mint_ata: params.create_wsol_ata, + close_input_mint_ata: params.close_wsol_ata, + create_output_mint_ata: params.create_mint_ata, + close_output_mint_ata: false, }; // Validate protocol params @@ -299,7 +301,7 @@ impl SolanaTrade { return Err(anyhow::anyhow!("Invalid protocol params for Trade")); } - executor.buy_with_tip(buy_params).await + executor.swap(buy_params).await } /// Execute a sell order for a specified token @@ -331,12 +333,19 @@ impl SolanaTrade { } let executor = TradeFactory::create_executor(params.dex_type.clone()); let protocol_params = params.extension_params; - - let sell_params = SellParams { + let output_mint = if params.dex_type == DexType::PumpFun { + SOL_TOKEN_ACCOUNT + } else { + WSOL_TOKEN_ACCOUNT + }; + let sell_params = SwapParams { rpc: Some(self.rpc.clone()), payer: self.payer.clone(), - mint: params.mint, - token_amount: Some(params.token_amount), + input_mint: params.mint, + output_mint: output_mint, + input_token_program: None, + output_token_program: None, + input_amount: Some(params.token_amount), slippage_basis_points: params.slippage_basis_points, lookup_table_key: params.lookup_table_key, recent_blockhash: params.recent_blockhash, @@ -346,9 +355,12 @@ impl SolanaTrade { open_seed_optimize: params.open_seed_optimize, swqos_clients: self.swqos_clients.clone(), middleware_manager: self.middleware_manager.clone(), - create_wsol_ata: params.create_wsol_ata, - close_wsol_ata: params.close_wsol_ata, durable_nonce: params.durable_nonce, + data_size_limit: 0, + create_input_mint_ata: false, + close_input_mint_ata: false, + create_output_mint_ata: params.create_wsol_ata, + close_output_mint_ata: params.close_wsol_ata, }; // Validate protocol params @@ -371,7 +383,7 @@ impl SolanaTrade { } // Execute sell based on tip preference - executor.sell_with_tip(sell_params).await + executor.swap(sell_params).await } /// Execute a sell order for a percentage of the specified token amount diff --git a/src/trading/core/executor.rs b/src/trading/core/executor.rs index 2a94407..00c3e57 100755 --- a/src/trading/core/executor.rs +++ b/src/trading/core/executor.rs @@ -2,13 +2,13 @@ use anyhow::Result; use solana_sdk::signature::Signature; use std::{sync::Arc, time::Instant}; -use crate::trading::core::parallel::{buy_parallel_execute, sell_parallel_execute}; - -use super::{ - params::{BuyParams, SellParams}, - traits::{InstructionBuilder, TradeExecutor}, +use crate::trading::core::{ + parallel::{buy_parallel_execute, sell_parallel_execute}, + traits::TradeExecutor, }; +use super::{params::SwapParams, traits::InstructionBuilder}; + /// Generic trade executor implementation pub struct GenericTradeExecutor { instruction_builder: Arc, @@ -26,46 +26,35 @@ impl GenericTradeExecutor { #[async_trait::async_trait] impl TradeExecutor for GenericTradeExecutor { - async fn buy_with_tip(&self, params: BuyParams) -> Result { + async fn swap(&self, params: SwapParams) -> Result { let start = Instant::now(); - + // 暂时支持这三种。后续重构扩展builder 支持所有的 swap + let is_buy = params.input_mint == crate::constants::SOL_TOKEN_ACCOUNT + || params.input_mint == crate::constants::WSOL_TOKEN_ACCOUNT + || (params.input_mint == crate::constants::USD1_TOKEN_ACCOUNT + && params.output_mint != crate::constants::WSOL_TOKEN_ACCOUNT); // Build instructions directly from params to avoid unnecessary cloning - let instructions = self.instruction_builder.build_buy_instructions(¶ms).await?; + let instructions = if is_buy { + self.instruction_builder.build_buy_instructions(¶ms).await? + } else { + self.instruction_builder.build_sell_instructions(¶ms).await? + }; let final_instructions = match ¶ms.middleware_manager { Some(middleware_manager) => middleware_manager .apply_middlewares_process_protocol_instructions( instructions, self.protocol_name.to_string(), - true, + is_buy, )?, None => instructions, }; - - println!("Building buy transaction instructions time cost: {:?}", start.elapsed()); - + println!("Building swap transaction instructions time cost: {:?}", start.elapsed()); // Execute transactions in parallel - buy_parallel_execute(params, final_instructions, self.protocol_name).await - } - - async fn sell_with_tip(&self, params: SellParams) -> Result { - let start = Instant::now(); - - // Build instructions directly from params to avoid unnecessary cloning - let instructions = self.instruction_builder.build_sell_instructions(¶ms).await?; - let final_instructions = match ¶ms.middleware_manager { - Some(middleware_manager) => middleware_manager - .apply_middlewares_process_protocol_instructions( - instructions, - self.protocol_name.to_string(), - false, - )?, - None => instructions, - }; - - println!("Building sell transaction instructions time cost: {:?}", start.elapsed()); - - // Execute transactions in parallel - sell_parallel_execute(params, final_instructions, self.protocol_name).await + if is_buy { + buy_parallel_execute(params, final_instructions, self.protocol_name).await + } else { + sell_parallel_execute(params, final_instructions, self.protocol_name).await + } } fn protocol_name(&self) -> &'static str { diff --git a/src/trading/core/parallel.rs b/src/trading/core/parallel.rs index 86e49d2..7cc01d3 100755 --- a/src/trading/core/parallel.rs +++ b/src/trading/core/parallel.rs @@ -8,14 +8,14 @@ use tokio::sync::mpsc; use tokio::task::JoinHandle; use crate::{ - common::{GasFeeStrategy, SolanaRpcClient}, common::nonce_cache::DurableNonceInfo, + common::{GasFeeStrategy, SolanaRpcClient}, swqos::{SwqosClient, SwqosType, TradeType}, - trading::{common::build_transaction, BuyParams, MiddlewareManager, SellParams}, + trading::{common::build_transaction, MiddlewareManager, SwapParams}, }; pub async fn buy_parallel_execute( - params: BuyParams, + params: SwapParams, instructions: Vec, protocol_name: &'static str, ) -> Result { @@ -26,9 +26,7 @@ pub async fn buy_parallel_execute( instructions, params.lookup_table_key, params.recent_blockhash, - params.durable_nonce.clone(), - // params.nonce_account, - // params.current_nonce, + params.durable_nonce, params.data_size_limit, params.middleware_manager, protocol_name, @@ -40,7 +38,7 @@ pub async fn buy_parallel_execute( } pub async fn sell_parallel_execute( - params: SellParams, + params: SwapParams, instructions: Vec, protocol_name: &'static str, ) -> Result { @@ -51,9 +49,7 @@ pub async fn sell_parallel_execute( instructions, params.lookup_table_key, params.recent_blockhash, - params.durable_nonce.clone(), - // params.nonce_account, - // params.current_nonce, + params.durable_nonce, 0, params.middleware_manager, protocol_name, @@ -73,8 +69,6 @@ async fn parallel_execute( lookup_table_key: Option, recent_blockhash: Option, durable_nonce: Option, - // nonce_account: Option, - // current_nonce: Option, data_size_limit: u32, middleware_manager: Option>, protocol_name: &'static str, diff --git a/src/trading/core/params.rs b/src/trading/core/params.rs index 8786ad3..a2000fb 100755 --- a/src/trading/core/params.rs +++ b/src/trading/core/params.rs @@ -1,7 +1,7 @@ use super::traits::ProtocolParams; use crate::common::bonding_curve::BondingCurveAccount; -use crate::common::SolanaRpcClient; use crate::common::nonce_cache::DurableNonceInfo; +use crate::common::SolanaRpcClient; 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; @@ -17,13 +17,17 @@ use solana_streamer_sdk::streaming::event_parser::protocols::raydium_amm_v4::typ use solana_streamer_sdk::streaming::event_parser::protocols::raydium_cpmm::RaydiumCpmmSwapEvent; use spl_associated_token_account::get_associated_token_address; use std::sync::Arc; -/// Buy parameters + +/// Swap parameters #[derive(Clone)] -pub struct BuyParams { +pub struct SwapParams { pub rpc: Option>, pub payer: Arc, - pub mint: Pubkey, - pub sol_amount: u64, + pub input_mint: Pubkey, + pub input_token_program: Option, + pub output_mint: Pubkey, + pub output_token_program: Option, + pub input_amount: Option, pub slippage_basis_points: Option, pub lookup_table_key: Option, pub recent_blockhash: Option, @@ -33,46 +37,17 @@ pub struct BuyParams { pub open_seed_optimize: bool, pub swqos_clients: Vec>, pub middleware_manager: Option>, - pub create_wsol_ata: bool, - pub close_wsol_ata: bool, - pub create_mint_ata: bool, - // pub nonce_account: Option, - // pub current_nonce: Option, pub durable_nonce: Option, -} - -/// Sell parameters -#[derive(Clone)] -pub struct SellParams { - pub rpc: Option>, - pub payer: Arc, - pub mint: Pubkey, - pub token_amount: Option, - pub slippage_basis_points: Option, - pub lookup_table_key: Option, - pub recent_blockhash: Option, - pub wait_transaction_confirmed: bool, pub with_tip: bool, - pub protocol_params: Box, - pub open_seed_optimize: bool, - pub swqos_clients: Vec>, - pub middleware_manager: Option>, - pub create_wsol_ata: bool, - pub close_wsol_ata: bool, - // pub nonce_account: Option, - // pub current_nonce: Option, - pub durable_nonce: Option, + pub create_input_mint_ata: bool, + pub close_input_mint_ata: bool, + pub create_output_mint_ata: bool, + pub close_output_mint_ata: bool, } -impl std::fmt::Debug for BuyParams { +impl std::fmt::Debug for SwapParams { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "BuyParams: {:?}", self) - } -} - -impl std::fmt::Debug for SellParams { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "SellParams: {:?}", self) + write!(f, "SwapParams: {:?}", self) } } @@ -332,6 +307,7 @@ pub struct BonkParams { pub platform_config: Pubkey, pub platform_associated_account: Pubkey, pub creator_associated_account: Pubkey, + pub global_config: Pubkey, } impl BonkParams { @@ -340,12 +316,14 @@ impl BonkParams { platform_config: Pubkey, platform_associated_account: Pubkey, creator_associated_account: Pubkey, + global_config: Pubkey, ) -> Self { Self { mint_token_program, platform_config, platform_associated_account, creator_associated_account, + global_config, ..Default::default() } } @@ -362,6 +340,7 @@ impl BonkParams { platform_config: trade_info.platform_config, platform_associated_account: trade_info.platform_associated_account, creator_associated_account: trade_info.creator_associated_account, + global_config: trade_info.global_config, } } @@ -417,16 +396,22 @@ impl BonkParams { platform_config: trade_info.platform_config, platform_associated_account: trade_info.platform_associated_account, creator_associated_account: trade_info.creator_associated_account, + global_config: trade_info.global_config, } } pub async fn from_mint_by_rpc( rpc: &SolanaRpcClient, mint: &Pubkey, + usd1_pool: bool, ) -> Result { let pool_address = crate::instruction::utils::bonk::get_pool_pda( mint, - &crate::constants::WSOL_TOKEN_ACCOUNT, + if usd1_pool { + &crate::constants::USD1_TOKEN_ACCOUNT + } else { + &crate::constants::WSOL_TOKEN_ACCOUNT + }, ) .unwrap(); let pool_data = @@ -452,6 +437,7 @@ impl BonkParams { platform_config: pool_data.platform_config, platform_associated_account, creator_associated_account, + global_config: pool_data.global_config, }) } } diff --git a/src/trading/core/traits.rs b/src/trading/core/traits.rs index 273b2f2..574b484 100755 --- a/src/trading/core/traits.rs +++ b/src/trading/core/traits.rs @@ -1,14 +1,11 @@ -use super::params::{BuyParams, SellParams}; +use crate::trading::SwapParams; use anyhow::Result; use solana_sdk::{instruction::Instruction, signature::Signature}; /// 交易执行器trait - 定义了所有交易协议都需要实现的核心方法 #[async_trait::async_trait] pub trait TradeExecutor: Send + Sync { - /// 使用MEV服务执行买入交易 - async fn buy_with_tip(&self, params: BuyParams) -> Result; - /// 使用MEV服务执行卖出交易 - async fn sell_with_tip(&self, params: SellParams) -> Result; + async fn swap(&self, params: SwapParams) -> Result; /// 获取协议名称 fn protocol_name(&self) -> &'static str; } @@ -17,10 +14,10 @@ pub trait TradeExecutor: Send + Sync { #[async_trait::async_trait] pub trait InstructionBuilder: Send + Sync { /// 构建买入指令 - async fn build_buy_instructions(&self, params: &BuyParams) -> Result>; + async fn build_buy_instructions(&self, params: &SwapParams) -> Result>; /// 构建卖出指令 - async fn build_sell_instructions(&self, params: &SellParams) -> Result>; + async fn build_sell_instructions(&self, params: &SwapParams) -> Result>; } /// 协议特定参数trait - 允许每个协议定义自己的参数 diff --git a/src/trading/mod.rs b/src/trading/mod.rs index c8d5d8d..506bb01 100755 --- a/src/trading/mod.rs +++ b/src/trading/mod.rs @@ -3,7 +3,7 @@ pub mod core; pub mod factory; pub mod middleware; -pub use core::params::{BuyParams, SellParams}; -pub use core::traits::{InstructionBuilder, TradeExecutor}; +pub use core::params::SwapParams; +pub use core::traits::InstructionBuilder; pub use factory::TradeFactory; pub use middleware::{InstructionMiddleware, MiddlewareManager};