From 334e6851043432133905e9d3d5142a0820705d51 Mon Sep 17 00:00:00 2001 From: ysq Date: Mon, 22 Sep 2025 01:09:41 +0800 Subject: [PATCH] feat: upgrade to v1.1.0 and add universal token swap functionality - Version bump: upgrade from 1.0.2 to 1.1.0 - Add TradeSwapParams struct for universal token-to-token swapping - Update bonk_copy_trading example to use new swap method instead of buy/sell - Expand trading parameters documentation with TradeSwapParams details - Fix SOL_TOKEN_ACCOUNT constant definition - Add USD1 token support (Bonk protocol only) - Enhance account management and optimization options for token swaps --- Cargo.toml | 2 +- README.md | 4 +- README_CN.md | 4 +- docs/TRADING_PARAMETERS.md | 49 ++++++++ docs/TRADING_PARAMETERS_CN.md | 49 ++++++++ examples/bonk_copy_trading/src/main.rs | 40 ++++--- src/constants/accounts.rs | 2 +- src/lib.rs | 148 +++++++++++++++++++++++++ 8 files changed, 276 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d21cd2c..80f6233 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sol-trade-sdk" -version = "1.0.2" +version = "1.1.0" edition = "2021" authors = [ "William ", diff --git a/README.md b/README.md index a52706e..2d21da9 100644 --- a/README.md +++ b/README.md @@ -87,14 +87,14 @@ Add the dependency to your `Cargo.toml`: ```toml # Add to your Cargo.toml -sol-trade-sdk = { path = "./sol-trade-sdk", version = "1.0.2" } +sol-trade-sdk = { path = "./sol-trade-sdk", version = "1.1.0" } ``` ### Use crates.io ```toml # Add to your Cargo.toml -sol-trade-sdk = "1.0.2" +sol-trade-sdk = "1.1.0" ``` ## 🛠️ Usage Examples diff --git a/README_CN.md b/README_CN.md index 59f163f..ce7ed8c 100755 --- a/README_CN.md +++ b/README_CN.md @@ -87,14 +87,14 @@ git clone https://github.com/0xfnzero/sol-trade-sdk ```toml # 添加到您的 Cargo.toml -sol-trade-sdk = { path = "./sol-trade-sdk", version = "1.0.2" } +sol-trade-sdk = { path = "./sol-trade-sdk", version = "1.1.0" } ``` ### 使用 crates.io ```toml # 添加到您的 Cargo.toml -sol-trade-sdk = "1.0.2" +sol-trade-sdk = "1.1.0" ``` ## 🛠️ 使用示例 diff --git a/docs/TRADING_PARAMETERS.md b/docs/TRADING_PARAMETERS.md index a9df819..e7a302f 100644 --- a/docs/TRADING_PARAMETERS.md +++ b/docs/TRADING_PARAMETERS.md @@ -4,11 +4,60 @@ This document provides a comprehensive reference for all trading parameters used ## 📋 Table of Contents +- [TradeSwapParams](#tradeswapparams) - [TradeBuyParams](#tradebuyparams) - [TradeSellParams](#tradesellparams) - [Parameter Categories](#parameter-categories) - [Important Notes](#important-notes) +## TradeSwapParams + +The `TradeSwapParams` struct contains all parameters required for executing swap orders across different DEX protocols. This is the most flexible trading method that supports swapping between any supported tokens. + +### Basic Trading Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `dex_type` | `DexType` | ✅ | The trading protocol to use (PumpFun, PumpSwap, Bonk, RaydiumCpmm, RaydiumAmmV4) | +| `input_mint` | `Pubkey` | ✅ | The public key of the token to spend (input token) | +| `output_mint` | `Pubkey` | ✅ | The public key of the token to receive (output token) | +| `input_token_program` | `Pubkey` | ✅ | The token program ID for the input token | +| `output_token_program` | `Pubkey` | ✅ | The token program ID for the output token | +| `input_amount` | `u64` | ✅ | Amount of input token to spend (in smallest token units) | +| `slippage_basis_points` | `Option` | ❌ | Slippage tolerance in basis points (e.g., 100 = 1%, 500 = 5%) | +| `recent_blockhash` | `Option` | ❌ | Recent blockhash for transaction validity | +| `extension_params` | `Box` | ✅ | Protocol-specific parameters (PumpFunParams, PumpSwapParams, etc.) | + +### Advanced Configuration Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `lookup_table_key` | `Option` | ❌ | Address lookup table key for transaction optimization | +| `wait_transaction_confirmed` | `bool` | ✅ | Whether to wait for transaction confirmation | +| `create_input_mint_ata` | `bool` | ✅ | Whether to create input token Associated Token Account | +| `close_input_mint_ata` | `bool` | ✅ | Whether to close input token ATA after transaction | +| `create_output_mint_ata` | `bool` | ✅ | Whether to create output token ATA | +| `close_output_mint_ata` | `bool` | ✅ | Whether to close output token ATA after transaction | +| `open_seed_optimize` | `bool` | ✅ | Whether to use seed optimization for reduced CU consumption | +| `durable_nonce` | `Option` | ❌ | Durable nonce information containing nonce account and current nonce value | +| `with_tip` | `bool` | ✅ | Whether to include tip for transaction priority | + +### Supported Token Pairs + +The SDK currently supports swap trading between the following base tokens and other tokens: +- **SOL** (Native Solana token) +- **WSOL** (Wrapped SOL) +- **USD1** (USD1 stablecoin - currently only supported on Bonk protocol) + +**Important**: At least one token in the swap pair must be a supported base token (SOL, WSOL, or USD1). + +### USD1 Token Support + +USD1 token support has the following limitations: +- **Protocol Restriction**: USD1 trading is currently only supported on the Bonk protocol +- **Pair Requirements**: USD1 can be swapped with other tokens, but the swap must occur on Bonk DEX +- **Token Address**: `USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB` + ## TradeBuyParams The `TradeBuyParams` struct contains all parameters required for executing buy orders across different DEX protocols. diff --git a/docs/TRADING_PARAMETERS_CN.md b/docs/TRADING_PARAMETERS_CN.md index de2c1a9..897e214 100644 --- a/docs/TRADING_PARAMETERS_CN.md +++ b/docs/TRADING_PARAMETERS_CN.md @@ -4,11 +4,60 @@ ## 📋 目录 +- [TradeSwapParams](#tradeswapparams) - [TradeBuyParams](#tradebuyparams) - [TradeSellParams](#tradesellparams) - [参数分类](#参数分类) - [重要说明](#重要说明) +## TradeSwapParams + +`TradeSwapParams` 结构体包含在不同 DEX 协议上执行代币交换订单所需的所有参数。这是最灵活的交易方法,支持在任何支持的代币之间进行交换。 + +### 基础交易参数 + +| 参数 | 类型 | 必需 | 描述 | +|------|------|------|------| +| `dex_type` | `DexType` | ✅ | 要使用的交易协议 (PumpFun, PumpSwap, Bonk, RaydiumCpmm, RaydiumAmmV4) | +| `input_mint` | `Pubkey` | ✅ | 要花费的代币公钥(输入代币) | +| `output_mint` | `Pubkey` | ✅ | 要接收的代币公钥(输出代币) | +| `input_token_program` | `Pubkey` | ✅ | 输入代币的代币程序 ID | +| `output_token_program` | `Pubkey` | ✅ | 输出代币的代币程序 ID | +| `input_amount` | `u64` | ✅ | 要花费的输入代币数量(最小代币单位) | +| `slippage_basis_points` | `Option` | ❌ | 滑点容忍度(基点单位,例如 100 = 1%, 500 = 5%) | +| `recent_blockhash` | `Option` | ❌ | 用于交易有效性的最新区块哈希 | +| `extension_params` | `Box` | ✅ | 协议特定参数 (PumpFunParams, PumpSwapParams 等) | + +### 高级配置参数 + +| 参数 | 类型 | 必需 | 描述 | +|------|------|------|------| +| `lookup_table_key` | `Option` | ❌ | 用于交易优化的地址查找表键 | +| `wait_transaction_confirmed` | `bool` | ✅ | 是否等待交易确认 | +| `create_input_mint_ata` | `bool` | ✅ | 是否创建输入代币关联代币账户 | +| `close_input_mint_ata` | `bool` | ✅ | 交易后是否关闭输入代币 ATA | +| `create_output_mint_ata` | `bool` | ✅ | 是否创建输出代币 ATA | +| `close_output_mint_ata` | `bool` | ✅ | 交易后是否关闭输出代币 ATA | +| `open_seed_optimize` | `bool` | ✅ | 是否使用 seed 优化以减少 CU 消耗 | +| `durable_nonce` | `Option` | ❌ | 持久 nonce 信息,包含 nonce 账户和当前 nonce 值 | +| `with_tip` | `bool` | ✅ | 是否包含小费以提高交易优先级 | + +### 支持的代币交易对 + +SDK 目前支持以下基础代币与其他代币之间的交换交易: +- **SOL**(Solana 原生代币) +- **WSOL**(包装 SOL) +- **USD1**(USD1 稳定币 - 目前仅在 Bonk 协议上支持) + +**重要提示**:交换对中至少有一个代币必须是支持的基础代币(SOL、WSOL 或 USD1)。 + +### USD1 代币支持 + +USD1 代币支持有以下限制: +- **协议限制**:USD1 交易目前仅在 Bonk 协议上支持 +- **交易对要求**:USD1 可以与其他代币交换,但必须在 Bonk DEX 上进行 +- **代币地址**:`USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB` + ## TradeBuyParams `TradeBuyParams` 结构体包含在不同 DEX 协议上执行买入订单所需的所有参数。 diff --git a/examples/bonk_copy_trading/src/main.rs b/examples/bonk_copy_trading/src/main.rs index e80c2e1..e591dc6 100644 --- a/examples/bonk_copy_trading/src/main.rs +++ b/examples/bonk_copy_trading/src/main.rs @@ -88,9 +88,6 @@ fn create_event_callback() -> impl Fn(Box) { |event: Box| { match_event!(event, { BonkTradeEvent => |e: BonkTradeEvent| { - if e.base_token_mint != WSOL_TOKEN_ACCOUNT && e.quote_token_mint != WSOL_TOKEN_ACCOUNT { - return; - } // Test code, only test one transaction if !ALREADY_EXECUTED.swap(true, Ordering::SeqCst) { let event_clone = e.clone(); @@ -129,28 +126,34 @@ async fn bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult<()> let client = create_solana_trade_client().await?; let mint_pubkey = trade_info.base_token_mint; + let quote_mint_pubkey = trade_info.quote_token_mint; let slippage_basis_points = Some(100); let recent_blockhash = client.rpc.get_latest_blockhash().await?; // Buy tokens println!("Buying tokens from Bonk..."); let buy_sol_amount = 100_000; - let buy_params = sol_trade_sdk::TradeBuyParams { + let buy_params = sol_trade_sdk::TradeSwapParams { dex_type: DexType::Bonk, - mint: mint_pubkey, - sol_amount: buy_sol_amount, + input_mint: quote_mint_pubkey, + output_mint: mint_pubkey, + input_token_program: trade_info.quote_token_program, + output_token_program: trade_info.base_token_program, + input_amount: buy_sol_amount, slippage_basis_points: slippage_basis_points, recent_blockhash: Some(recent_blockhash), extension_params: Box::new(BonkParams::from_trade(trade_info.clone())), lookup_table_key: None, wait_transaction_confirmed: true, - create_wsol_ata: true, - close_wsol_ata: true, - create_mint_ata: true, + create_input_mint_ata: true, + close_input_mint_ata: false, + create_output_mint_ata: true, + close_output_mint_ata: true, open_seed_optimize: false, durable_nonce: None, + with_tip: true, }; - client.buy(buy_params).await?; + client.swap(buy_params).await?; // Sell tokens println!("Selling tokens from Bonk..."); @@ -163,22 +166,27 @@ async fn bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult<()> let amount_token = balance.amount.parse::().unwrap(); println!("Selling {} tokens", amount_token); - let sell_params = sol_trade_sdk::TradeSellParams { + let sell_params = sol_trade_sdk::TradeSwapParams { dex_type: DexType::Bonk, - mint: mint_pubkey, - token_amount: amount_token, + input_mint: mint_pubkey, + output_mint: quote_mint_pubkey, + input_token_program: trade_info.base_token_program, + output_token_program: trade_info.quote_token_program, + input_amount: amount_token, slippage_basis_points: slippage_basis_points, recent_blockhash: Some(recent_blockhash), extension_params: Box::new(BonkParams::from_trade(trade_info.clone())), lookup_table_key: None, wait_transaction_confirmed: true, - create_wsol_ata: true, - close_wsol_ata: true, open_seed_optimize: false, with_tip: false, durable_nonce: None, + create_input_mint_ata: false, + close_input_mint_ata: false, + create_output_mint_ata: true, + close_output_mint_ata: false, }; - client.sell(sell_params).await?; + client.swap(sell_params).await?; // Exit program std::process::exit(0); diff --git a/src/constants/accounts.rs b/src/constants/accounts.rs index 72a9492..0e11b83 100644 --- a/src/constants/accounts.rs +++ b/src/constants/accounts.rs @@ -24,7 +24,7 @@ pub const TOKEN_PROGRAM_2022_META: solana_sdk::instruction::AccountMeta = is_writable: false, }; -pub const SOL_TOKEN_ACCOUNT: Pubkey = pubkey!("So11111111111111111111111111111111111111112"); +pub const SOL_TOKEN_ACCOUNT: Pubkey = pubkey!("So11111111111111111111111111111111111111111"); pub const WSOL_TOKEN_ACCOUNT: Pubkey = pubkey!("So11111111111111111111111111111111111111112"); pub const WSOL_TOKEN_ACCOUNT_META: solana_sdk::instruction::AccountMeta = diff --git a/src/lib.rs b/src/lib.rs index f2384e2..cdb095d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ 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::USD1_TOKEN_ACCOUNT; use crate::constants::WSOL_TOKEN_ACCOUNT; use crate::swqos::SwqosClient; use crate::swqos::SwqosConfig; @@ -60,6 +61,52 @@ impl Clone for SolanaTrade { } } +/// Parameters for executing swap orders across different DEX protocols +/// +/// Contains all necessary configuration for swapping tokens, including +/// protocol-specific settings, account management options, and transaction preferences. +#[derive(Clone)] +pub struct TradeSwapParams { + // Trading configuration + /// The DEX protocol to use for the trade + pub dex_type: DexType, + /// Public key of the token to purchase + pub input_mint: Pubkey, + /// Public key of the token to sell + pub output_mint: Pubkey, + /// Public key of the token program to use for the input token + pub input_token_program: Pubkey, + /// Public key of the token program to use for the output token + pub output_token_program: Pubkey, + /// Amount of input token to spend (in lamports) + pub input_amount: u64, + /// Optional slippage tolerance in basis points (e.g., 100 = 1%) + pub slippage_basis_points: Option, + /// Recent blockhash for transaction validity + pub recent_blockhash: Option, + /// Protocol-specific parameters (PumpFun, Raydium, etc.) + pub extension_params: Box, + // Extended configuration + /// Optional address lookup table for transaction size optimization + pub lookup_table_key: Option, + /// Whether to wait for transaction confirmation before returning + pub wait_transaction_confirmed: bool, + /// Whether to create wrapped SOL associated token account + pub create_input_mint_ata: bool, + /// Whether to close wrapped SOL associated token account after trade + pub close_input_mint_ata: bool, + /// Whether to create token mint associated token account + pub create_output_mint_ata: bool, + /// Whether to close token mint associated token account after trade + pub close_output_mint_ata: bool, + /// Whether to enable seed-based optimization for account creation + pub open_seed_optimize: bool, + /// Durable nonce information + pub durable_nonce: Option, + /// Whether to include tip for transaction priority + pub with_tip: bool, +} + /// Parameters for executing buy orders across different DEX protocols /// /// Contains all necessary configuration for purchasing tokens, including @@ -224,6 +271,107 @@ impl SolanaTrade { .clone() } + /// Execute a swap order for a specified token + /// + /// # Arguments + /// + /// * `params` - Swap trade parameters containing all necessary trading configuration + /// + /// # Returns + /// + /// Returns `Ok(Signature)` with the transaction signature if the swap order is successfully executed, + /// or an error if the transaction fails. + /// + /// # Errors + /// + /// This function will return an error if: + /// - Invalid protocol parameters are provided for the specified DEX type + /// - The transaction fails to execute + /// - Network or RPC errors occur + /// - Insufficient token balance for the sale + /// - Token account doesn't exist or is not properly initialized + /// - Required accounts cannot be created or accessed + pub async fn swap(&self, params: TradeSwapParams) -> Result { + if params.slippage_basis_points.is_none() { + println!( + "slippage_basis_points is none, use default slippage basis points: {}", + DEFAULT_SLIPPAGE + ); + } + let executor = TradeFactory::create_executor(params.dex_type.clone()); + let protocol_params = params.extension_params; + let buy_params = SwapParams { + rpc: Some(self.rpc.clone()), + payer: self.payer.clone(), + input_mint: params.input_mint, + output_mint: params.output_mint, + input_token_program: Some(params.input_token_program), + output_token_program: Some(params.output_token_program), + input_amount: Some(params.input_amount), + slippage_basis_points: params.slippage_basis_points, + lookup_table_key: params.lookup_table_key, + recent_blockhash: params.recent_blockhash, + data_size_limit: 256 * 1024, + wait_transaction_confirmed: params.wait_transaction_confirmed, + protocol_params: protocol_params.clone(), + open_seed_optimize: params.open_seed_optimize, + swqos_clients: self.swqos_clients.clone(), + middleware_manager: self.middleware_manager.clone(), + durable_nonce: params.durable_nonce, + with_tip: params.with_tip, + create_input_mint_ata: params.create_input_mint_ata, + close_input_mint_ata: params.close_input_mint_ata, + create_output_mint_ata: params.create_output_mint_ata, + close_output_mint_ata: params.close_output_mint_ata, + }; + + // Validate protocol params + let is_valid_params = match params.dex_type { + DexType::PumpFun => protocol_params.as_any().downcast_ref::().is_some(), + DexType::PumpSwap => { + protocol_params.as_any().downcast_ref::().is_some() + } + DexType::Bonk => protocol_params.as_any().downcast_ref::().is_some(), + DexType::RaydiumCpmm => { + protocol_params.as_any().downcast_ref::().is_some() + } + DexType::RaydiumAmmV4 => { + protocol_params.as_any().downcast_ref::().is_some() + } + }; + + if !is_valid_params { + return Err(anyhow::anyhow!("Invalid protocol params for Trade")); + } + + let mut no_support_mint = false; + + // 检查是否至少有一个代币是支持的基础代币(SOL、WSOL、USD1) + let has_supported_base_token = params.input_mint == SOL_TOKEN_ACCOUNT + || params.output_mint == SOL_TOKEN_ACCOUNT + || params.input_mint == WSOL_TOKEN_ACCOUNT + || params.output_mint == WSOL_TOKEN_ACCOUNT + || params.input_mint == USD1_TOKEN_ACCOUNT + || params.output_mint == USD1_TOKEN_ACCOUNT; + + if !has_supported_base_token { + no_support_mint = true; + } + + // USD1 代币暂支持在 Bonk 协议上交易 + if (params.input_mint == USD1_TOKEN_ACCOUNT || params.output_mint == USD1_TOKEN_ACCOUNT) + && params.dex_type != DexType::Bonk + { + no_support_mint = true; + } + + if no_support_mint { + return Err(anyhow::anyhow!("Currently only supports swap trading between (SOL、WSOL、USD1) and other tokens. USD1 swap trading is currently only supported on the Bonk protocol.")); + } + + executor.swap(buy_params).await + } + /// Execute a buy order for a specified token /// /// # Arguments