diff --git a/README.md b/README.md index d01fe14..a3a4c72 100755 --- a/README.md +++ b/README.md @@ -55,6 +55,20 @@ In PumpSwap, Bonk, and Raydium CPMM trading, the `auto_handle_wsol` parameter is - When selling: automatically unwraps the received wSOL to SOL - Default value is `true` +#### lookup_table_key Parameter + +The `lookup_table_key` parameter is an optional `Pubkey` that specifies an address lookup table for transaction optimization: + +- **Purpose**: Address lookup tables can reduce transaction size and improve execution speed by storing frequently used addresses +- **Usage**: + - Can be set globally in `TradeConfig` for all transactions + - Can be overridden per transaction in `buy()` and `sell()` methods + - If not provided, defaults to `None` +- **Benefits**: + - Reduces transaction size by referencing addresses from lookup tables + - Improves transaction success rate and speed + - Particularly useful for complex transactions with many account references + ### 1. Event Subscription - Monitor Token Trading #### 1.1 Subscribe to Events Using Yellowstone gRPC @@ -344,6 +358,7 @@ async fn test_pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> Some(Box::new(PumpFunParams { bonding_curve: Some(Arc::new(bonding_curve.clone())), })), + None, ) .await?; @@ -380,6 +395,7 @@ async fn test_pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> Any Some(Box::new(PumpFunParams { bonding_curve: Some(Arc::new(bonding_curve.clone())), })), + None, ) .await?; @@ -399,6 +415,7 @@ async fn test_pumpfun_sell() -> AnyResult<()> { None, false, None, + None, ) .await?; } @@ -442,6 +459,7 @@ async fn test_pumpswap() -> AnyResult<()> { pool_quote_token_reserves: Some(pool_quote_token_reserves), auto_handle_wsol: true, })), + None, ).await?; // Sell tokens @@ -464,6 +482,7 @@ async fn test_pumpswap() -> AnyResult<()> { pool_quote_token_reserves: Some(pool_quote_token_reserves), auto_handle_wsol: true, })), + None, ).await?; Ok(()) @@ -513,6 +532,7 @@ async fn test_raydium_cpmm() -> Result<(), Box> { minimum_amount_out: Some(buy_amount_out), // If not provided, defaults to 0 auto_handle_wsol: true, // Automatically handle wSOL wrapping/unwrapping })), + None, ).await?; println!("Selling tokens from Raydium CPMM..."); @@ -535,6 +555,7 @@ async fn test_raydium_cpmm() -> Result<(), Box> { minimum_amount_out: Some(sell_sol_amount), // If not provided, defaults to 0 auto_handle_wsol: true, // Automatically handle wSOL wrapping/unwrapping })), + None, ).await?; Ok(()) @@ -571,6 +592,7 @@ async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyRe recent_blockhash, None, Some(Box::new(BonkParams::from_dev_trade(trade_info))), + None, ).await?; println!("Selling tokens from letsbonk.fun..."); @@ -585,6 +607,7 @@ async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyRe None, false, None, + None, ).await?; Ok(()) @@ -612,6 +635,7 @@ async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult recent_blockhash, None, Some(Box::new(BonkParams::from_trade(trade_info))), + None, ).await?; println!("Selling tokens from letsbonk.fun..."); @@ -626,6 +650,7 @@ async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult None, false, None, + None, ).await?; Ok(()) @@ -653,6 +678,7 @@ async fn test_bonk() -> Result<(), Box> { recent_blockhash, None, None, + None, ) .await?; @@ -669,6 +695,7 @@ async fn test_bonk() -> Result<(), Box> { None, false, None, + None, ) .await?; diff --git a/README_CN.md b/README_CN.md index 65ea322..a01d8f4 100755 --- a/README_CN.md +++ b/README_CN.md @@ -55,6 +55,20 @@ sol-trade-sdk = "0.3.4" - 卖出时:自动将获得的 wSOL 解包装为 SOL - 默认值为 `true` +#### lookup_table_key 参数 + +`lookup_table_key` 参数是一个可选的 `Pubkey`,用于指定地址查找表以优化交易: + +- **用途**:地址查找表可以通过存储常用地址来减少交易大小并提高执行速度 +- **使用方法**: + - 可以在 `TradeConfig` 中全局设置,用于所有交易 + - 可以在 `buy()` 和 `sell()` 方法中按交易覆盖 + - 如果不提供,默认为 `None` +- **优势**: + - 通过从查找表引用地址来减少交易大小 + - 提高交易成功率和速度 + - 特别适用于具有许多账户引用的复杂交易 + ### 1. 事件订阅 - 监听代币交易 #### 1.1 使用 Yellowstone gRPC 订阅事件 @@ -344,6 +358,7 @@ async fn test_pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> Some(Box::new(PumpFunParams { bonding_curve: Some(Arc::new(bonding_curve.clone())), })), + None, ) .await?; @@ -379,6 +394,7 @@ async fn test_pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> Any Some(Box::new(PumpFunParams { bonding_curve: Some(Arc::new(bonding_curve.clone())), })), + None, ) .await?; @@ -396,6 +412,8 @@ async fn test_pumpfun_sell() -> AnyResult<()> { slippage_basis_points, recent_blockhash, None, + false, + None, None, ) .await?; @@ -440,6 +458,7 @@ async fn test_pumpswap() -> AnyResult<()> { pool_quote_token_reserves: Some(pool_quote_token_reserves), auto_handle_wsol: true, })), + None, ).await?; // 卖出代币 @@ -462,6 +481,7 @@ async fn test_pumpswap() -> AnyResult<()> { pool_quote_token_reserves: Some(pool_quote_token_reserves), auto_handle_wsol: true, })), + None, ).await?; Ok(()) @@ -511,6 +531,7 @@ async fn test_raydium_cpmm() -> Result<(), Box> { minimum_amount_out: Some(buy_amount_out), // 如果不传,默认为0 auto_handle_wsol: true, // 自动处理 wSOL 包装/解包装 })), + None, ).await?; println!("Selling tokens from Raydium CPMM..."); @@ -533,6 +554,7 @@ async fn test_raydium_cpmm() -> Result<(), Box> { minimum_amount_out: Some(sell_sol_amount), // 如果不传,默认为0 auto_handle_wsol: true, // 自动处理 wSOL 包装/解包装 })), + None, ).await?; Ok(()) @@ -569,6 +591,7 @@ async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyRe recent_blockhash, None, Some(Box::new(BonkParams::from_dev_trade(trade_info))), + None, ).await?; println!("Selling tokens from letsbonk.fun..."); @@ -583,6 +606,7 @@ async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyRe None, false, None, + None, ).await?; Ok(()) @@ -610,6 +634,7 @@ async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult recent_blockhash, None, Some(Box::new(BonkParams::from_trade(trade_info))), + None, ).await?; println!("Selling tokens from letsbonk.fun..."); @@ -624,6 +649,7 @@ async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult None, false, None, + None, ).await?; Ok(()) @@ -651,6 +677,7 @@ async fn test_bonk() -> Result<(), Box> { recent_blockhash, None, None, + None, ) .await?; @@ -667,6 +694,7 @@ async fn test_bonk() -> Result<(), Box> { None, false, None, + None, ) .await?; diff --git a/src/lib.rs b/src/lib.rs index 6c71e18..b9c7be0 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,6 +128,7 @@ impl SolanaTrade { /// * `recent_blockhash` - Recent blockhash for transaction validity /// * `custom_buy_tip_fee` - Optional custom tip fee for priority processing (in SOL) /// * `extension_params` - Optional protocol-specific parameters (uses defaults if None) + /// * `lookup_table_key` - Optional address lookup table key for transaction optimization /// /// # Returns /// @@ -162,6 +163,7 @@ impl SolanaTrade { /// recent_blockhash, /// None, /// None, + /// Some(lookup_table_pubkey), /// ).await?; /// ``` pub async fn buy( @@ -174,6 +176,7 @@ impl SolanaTrade { recent_blockhash: Hash, custom_buy_tip_fee: Option, extension_params: Option>, + lookup_table_key: Option, ) -> Result<(), anyhow::Error> { let executor = TradeFactory::create_executor(dex_type.clone()); let protocol_params = if let Some(params) = extension_params { @@ -188,6 +191,9 @@ impl SolanaTrade { } } }; + + let final_lookup_table_key = lookup_table_key.or(self.trade_config.lookup_table_key); + let buy_params = BuyParams { rpc: Some(self.rpc.clone()), payer: self.payer.clone(), @@ -196,7 +202,7 @@ impl SolanaTrade { sol_amount: sol_amount, slippage_basis_points: slippage_basis_points, priority_fee: self.trade_config.priority_fee.clone(), - lookup_table_key: self.trade_config.lookup_table_key, + lookup_table_key: final_lookup_table_key, recent_blockhash, data_size_limit: 0, protocol_params: protocol_params.clone(), @@ -252,6 +258,7 @@ impl SolanaTrade { /// * `custom_buy_tip_fee` - Optional custom tip fee for priority processing (in SOL) /// * `with_tip` - Optional boolean to indicate if the transaction should be sent with tip /// * `extension_params` - Optional protocol-specific parameters (uses defaults if None) + /// * `lookup_table_key` - Optional address lookup table key for transaction optimization /// /// # Returns /// @@ -288,6 +295,7 @@ impl SolanaTrade { /// None, /// false, /// None, + /// Some(lookup_table_pubkey), /// ).await?; /// ``` pub async fn sell( @@ -301,6 +309,7 @@ impl SolanaTrade { custom_buy_tip_fee: Option, with_tip: bool, extension_params: Option>, + lookup_table_key: Option, ) -> Result<(), anyhow::Error> { let executor = TradeFactory::create_executor(dex_type.clone()); let protocol_params = if let Some(params) = extension_params { @@ -315,6 +324,9 @@ impl SolanaTrade { } } }; + + let final_lookup_table_key = lookup_table_key.or(self.trade_config.lookup_table_key); + let sell_params = SellParams { rpc: Some(self.rpc.clone()), payer: self.payer.clone(), @@ -323,7 +335,7 @@ impl SolanaTrade { token_amount: Some(token_amount), slippage_basis_points: slippage_basis_points, priority_fee: self.trade_config.priority_fee.clone(), - lookup_table_key: self.trade_config.lookup_table_key, + lookup_table_key: final_lookup_table_key, recent_blockhash, protocol_params: protocol_params.clone(), }; @@ -385,7 +397,9 @@ impl SolanaTrade { /// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%) /// * `recent_blockhash` - Recent blockhash for transaction validity /// * `custom_buy_tip_fee` - Optional custom tip fee for priority processing (in SOL) + /// * `with_tip` - Whether to use tip for priority processing /// * `extension_params` - Optional protocol-specific parameters (uses defaults if None) + /// * `lookup_table_key` - Optional lookup table key for address lookup optimization /// /// # Returns /// @@ -424,6 +438,8 @@ impl SolanaTrade { /// slippage, /// recent_blockhash, /// None, + /// false, + /// None, /// None, /// ).await?; /// ``` @@ -439,6 +455,7 @@ impl SolanaTrade { custom_buy_tip_fee: Option, with_tip: bool, extension_params: Option>, + lookup_table_key: Option, ) -> Result<(), anyhow::Error> { if percent == 0 || percent > 100 { return Err(anyhow::anyhow!("Percentage must be between 1 and 100")); @@ -454,6 +471,7 @@ impl SolanaTrade { custom_buy_tip_fee, with_tip, extension_params, + lookup_table_key, ) .await } diff --git a/src/main.rs b/src/main.rs index 801b0dc..f270a89 100755 --- a/src/main.rs +++ b/src/main.rs @@ -98,6 +98,7 @@ async fn test_pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> Any Some(Box::new(PumpFunParams { bonding_curve: Some(Arc::new(bonding_curve.clone())), })), + None, ).await?; // Sell tokens @@ -113,6 +114,7 @@ async fn test_pumpfun_copy_trade_with_grpc(trade_info: PumpFunTradeEvent) -> Any None, false, None, + None, ).await?; Ok(()) @@ -152,6 +154,7 @@ async fn test_pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> Some(Box::new(PumpFunParams { bonding_curve: Some(Arc::new(bonding_curve.clone())), })), + None, ).await?; // Sell tokens @@ -167,6 +170,7 @@ async fn test_pumpfun_sniper_trade_with_shreds(trade_info: PumpFunTradeEvent) -> None, false, None, + None, ).await?; Ok(()) @@ -205,6 +209,7 @@ async fn test_pumpswap() -> AnyResult<()> { pool_quote_token_reserves: Some(pool_quote_token_reserves), auto_handle_wsol: true, })), + None, ).await?; // Sell tokens @@ -227,6 +232,7 @@ async fn test_pumpswap() -> AnyResult<()> { pool_quote_token_reserves: Some(pool_quote_token_reserves), auto_handle_wsol: true, })), + None, ).await?; Ok(()) @@ -254,6 +260,7 @@ async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult recent_blockhash, None, Some(Box::new(BonkParams::from_trade(trade_info))), + None, ).await?; // Sell tokens @@ -269,6 +276,7 @@ async fn test_bonk_copy_trade_with_grpc(trade_info: BonkTradeEvent) -> AnyResult None, false, None, + None, ).await?; Ok(()) @@ -298,6 +306,7 @@ async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyRe recent_blockhash, None, Some(Box::new(BonkParams::from_dev_trade(trade_info))), + None, ).await?; // Sell tokens @@ -313,6 +322,7 @@ async fn test_bonk_sniper_trade_with_shreds(trade_info: BonkTradeEvent) -> AnyRe None, false, None, + None, ).await?; Ok(()) @@ -339,6 +349,7 @@ async fn test_bonk() -> Result<(), Box> { recent_blockhash, None, None, + None, ).await?; // Sell tokens @@ -354,6 +365,7 @@ async fn test_bonk() -> Result<(), Box> { None, false, None, + None, ).await?; Ok(()) @@ -387,6 +399,7 @@ async fn test_raydium_cpmm() -> Result<(), Box> { minimum_amount_out: Some(buy_amount_out), // 如果不传、默认为0 auto_handle_wsol: true, })), + None, ).await?; // Sell tokens @@ -409,6 +422,7 @@ async fn test_raydium_cpmm() -> Result<(), Box> { minimum_amount_out: Some(sell_sol_amount), // 如果不传、默认为0 auto_handle_wsol: true, })), + None, ).await?; Ok(())