From dd4f42324ebfc01c2a70f699cdd91553c75de002 Mon Sep 17 00:00:00 2001 From: Wood Date: Fri, 27 Feb 2026 00:27:36 +0800 Subject: [PATCH] feat: IDL updates, PumpFun/PumpSwap instruction and utils, fast_fn, release notes - idl: pump.json and pump_amm.json updates - instruction: pumpfun.rs, pumpswap.rs and utils (pumpfun, pumpswap) - common: fast_fn.rs - docs: release_notes_v3.5.0.md Made-with: Cursor --- idl/pump.json | 45 +++++++++++++++++++++++++++++ idl/pump_amm.json | 47 ++++++++++++++++++++++++++++++- release_notes_v3.5.0.md | 19 ++++++------- src/common/fast_fn.rs | 2 ++ src/instruction/pumpfun.rs | 14 ++++++--- src/instruction/pumpswap.rs | 12 +++++++- src/instruction/utils/pumpfun.rs | 16 +++++++++++ src/instruction/utils/pumpswap.rs | 13 +++++++++ 8 files changed, 152 insertions(+), 16 deletions(-) diff --git a/idl/pump.json b/idl/pump.json index 9977ae3..ff25a33 100644 --- a/idl/pump.json +++ b/idl/pump.json @@ -768,6 +768,21 @@ { "name": "fee_program", "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + }, + { + "name": "bonding_curve_v2", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [98, 111, 110, 100, 105, 110, 103, 45, 99, 117, 114, 118, 101, 45, 118, 50] + }, + { + "kind": "account", + "path": "mint" + } + ] + } } ], "args": [ @@ -1164,6 +1179,21 @@ { "name": "fee_program", "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + }, + { + "name": "bonding_curve_v2", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [98, 111, 110, 100, 105, 110, 103, 45, 99, 117, 114, 118, 101, 45, 118, 50] + }, + { + "kind": "account", + "path": "mint" + } + ] + } } ], "args": [ @@ -3957,6 +3987,21 @@ { "name": "fee_program", "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + }, + { + "name": "bonding_curve_v2", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [98, 111, 110, 100, 105, 110, 103, 45, 99, 117, 114, 118, 101, 45, 118, 50] + }, + { + "kind": "account", + "path": "mint" + } + ] + } } ], "args": [ diff --git a/idl/pump_amm.json b/idl/pump_amm.json index 47d7b95..22d8332 100644 --- a/idl/pump_amm.json +++ b/idl/pump_amm.json @@ -688,6 +688,21 @@ { "name": "fee_program", "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + }, + { + "name": "pool_v2", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [112, 111, 111, 108, 45, 118, 50] + }, + { + "kind": "account", + "path": "base_mint" + } + ] + } } ], "args": [ @@ -1119,6 +1134,21 @@ { "name": "fee_program", "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + }, + { + "name": "pool_v2", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [112, 111, 111, 108, 45, 118, 50] + }, + { + "kind": "account", + "path": "base_mint" + } + ] + } } ], "args": [ @@ -3162,6 +3192,21 @@ { "name": "fee_program", "address": "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ" + }, + { + "name": "pool_v2", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [112, 111, 111, 108, 45, 118, 50] + }, + { + "kind": "account", + "path": "base_mint" + } + ] + } } ], "args": [ @@ -4835,7 +4880,7 @@ }, { "code": 6052, - "name": "CashbackEarnedDoesNotMatchTokenInVault" + "name": "TokensInVaultLessThanCashbackEarned" } ], "types": [ diff --git a/release_notes_v3.5.0.md b/release_notes_v3.5.0.md index 6bd3602..133dbd4 100644 --- a/release_notes_v3.5.0.md +++ b/release_notes_v3.5.0.md @@ -6,20 +6,19 @@ Rust SDK for Solana DEX trading (Pump.fun, PumpSwap, Raydium, Bonk, Meteora, etc ### Performance -- **Hot-path timing**: `Instant::now()` for build/submit/total/confirm only when `log_enabled` or (for total) simulate, reducing cold-path syscalls. -- **Fewer clones**: `execute_parallel` now takes `&[Arc]` instead of `Vec>`; caller no longer clones the client list. -- **SWQoS HTTP**: Named constants for pool idle timeout, connect/request timeouts, and HTTP/2 keepalive in `swqos/common.rs`. +- **Executor hot path**: Sample `Instant::now()` only when `log_enabled` or `simulate` (total, build, submit, confirm) to reduce cold-path syscalls. +- **SWQOS**: `execute_parallel` now takes `&[Arc]` to avoid cloning the client list on each swap. +- **Constants**: Named constants for instruction/account sizes and HTTP client timeouts; no magic numbers in hot paths. -### Code quality +### Code Quality -- **Protocol params**: Single `validate_protocol_params(dex_type, params)` used by both buy and sell; removed duplicated match blocks. -- **Constants**: `BYTES_PER_ACCOUNT`, `MAX_INSTRUCTIONS_WARN` in execution; HTTP timeout constants in swqos common. -- **Comments**: Prefetch and branch-hint safety/usage documented; `SYSCALL_BYPASS` marked as reserved for future use. +- **Protocol params**: Single `validate_protocol_params()` used for both buy and sell; removed duplicate match blocks in `lib.rs`. +- **Comments**: Bilingual (English + 中文) doc and inline comments across execution, executor, perf (hardware_optimizations, syscall_bypass), and swqos/common. +- **Prefetch/safety**: Clearer docs for cache prefetch and `unsafe` usage (valid read-only ref, no concurrent write). ### Documentation -- **Bilingual docs**: English + 中文 doc comments in `trading/core/execution.rs`, `trading/core/executor.rs`, `perf/hardware_optimizations.rs`, `perf/mod.rs`, `perf/syscall_bypass.rs`, `swqos/common.rs`. -- **README**: Version references and "What's new in 3.5.0" (EN) / "3.5.0 更新说明" (CN) updated. +- README (EN/CN): Version references updated to 3.5.0 for path and crates.io usage. --- @@ -30,7 +29,7 @@ Rust SDK for Solana DEX trading (Pump.fun, PumpSwap, Raydium, Bonk, Meteora, etc sol-trade-sdk = { git = "https://github.com/0xfnzero/sol-trade-sdk", tag = "v3.5.0" } ``` -**From crates.io** (when published): +**From crates.io:** ```toml sol-trade-sdk = "3.5.0" ``` diff --git a/src/common/fast_fn.rs b/src/common/fast_fn.rs index 81e64ae..f7e0a1b 100644 --- a/src/common/fast_fn.rs +++ b/src/common/fast_fn.rs @@ -153,10 +153,12 @@ pub fn _create_associated_token_account_idempotent_fast( pub enum PdaCacheKey { PumpFunUserVolume(Pubkey), PumpFunBondingCurve(Pubkey), + PumpFunBondingCurveV2(Pubkey), PumpFunCreatorVault(Pubkey), BonkPool(Pubkey, Pubkey), BonkVault(Pubkey, Pubkey), PumpSwapUserVolume(Pubkey), + PumpSwapPoolV2(Pubkey), } /// Global lock-free PDA cache for storing computation results diff --git a/src/instruction/pumpfun.rs b/src/instruction/pumpfun.rs index 475903c..72627e8 100755 --- a/src/instruction/pumpfun.rs +++ b/src/instruction/pumpfun.rs @@ -8,8 +8,9 @@ use crate::{ }; use crate::{ instruction::utils::pumpfun::{ - accounts, get_bonding_curve_pda, get_creator, get_user_volume_accumulator_pda, - global_constants::{self}, BUY_DISCRIMINATOR, BUY_EXACT_SOL_IN_DISCRIMINATOR, + accounts, get_bonding_curve_pda, get_bonding_curve_v2_pda, get_creator, + get_user_volume_accumulator_pda, global_constants::{self}, BUY_DISCRIMINATOR, + BUY_EXACT_SOL_IN_DISCRIMINATOR, }, utils::calc::{ common::{calculate_with_slippage_buy, calculate_with_slippage_sell}, @@ -143,7 +144,8 @@ impl InstructionBuilder for PumpFunInstructionBuilder { global_constants::FEE_RECIPIENT_META }; - let accounts: [AccountMeta; 16] = [ + let bonding_curve_v2 = get_bonding_curve_v2_pda(¶ms.output_mint).unwrap(); + let mut accounts: Vec = vec![ global_constants::GLOBAL_ACCOUNT_META, fee_recipient_meta, AccountMeta::new_readonly(params.output_mint, false), @@ -161,11 +163,12 @@ impl InstructionBuilder for PumpFunInstructionBuilder { accounts::FEE_CONFIG_META, accounts::FEE_PROGRAM_META, ]; + accounts.push(AccountMeta::new_readonly(bonding_curve_v2, false)); // bonding_curve_v2 (readonly) at end instructions.push(Instruction::new_with_bytes( accounts::PUMPFUN, &buy_data, - accounts.to_vec(), + accounts, )); Ok(instructions) @@ -286,6 +289,9 @@ impl InstructionBuilder for PumpFunInstructionBuilder { get_user_volume_accumulator_pda(¶ms.payer.pubkey()).unwrap(); accounts.push(AccountMeta::new(user_volume_accumulator, false)); } + // Program upgrade: bonding_curve_v2 (readonly) at end of account list + let bonding_curve_v2 = get_bonding_curve_v2_pda(¶ms.input_mint).unwrap(); + accounts.push(AccountMeta::new_readonly(bonding_curve_v2, false)); instructions.push(Instruction::new_with_bytes( accounts::PUMPFUN, diff --git a/src/instruction/pumpswap.rs b/src/instruction/pumpswap.rs index d2c7341..069c54c 100755 --- a/src/instruction/pumpswap.rs +++ b/src/instruction/pumpswap.rs @@ -1,7 +1,7 @@ use crate::{ constants::trade::trade::DEFAULT_SLIPPAGE, instruction::utils::pumpswap::{ - accounts, fee_recipient_ata, get_user_volume_accumulator_pda, + accounts, fee_recipient_ata, get_pool_v2_pda, get_user_volume_accumulator_pda, get_user_volume_accumulator_wsol_ata, BUY_DISCRIMINATOR, BUY_EXACT_QUOTE_IN_DISCRIMINATOR, SELL_DISCRIMINATOR, }, @@ -190,6 +190,11 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { accounts.push(AccountMeta::new(wsol_ata, false)); } } + // Program upgrade: pool_v2 (readonly) at end of account list + accounts.push(AccountMeta::new_readonly( + get_pool_v2_pda(&base_mint).unwrap(), + false, + )); // Create instruction data let mut data = [0u8; 24]; @@ -392,6 +397,11 @@ impl InstructionBuilder for PumpSwapInstructionBuilder { accounts.push(AccountMeta::new(accumulator, false)); } } + // Program upgrade: pool_v2 (readonly) at end of account list + accounts.push(AccountMeta::new_readonly( + get_pool_v2_pda(&base_mint).unwrap(), + false, + )); // Create instruction data let mut data = [0u8; 24]; diff --git a/src/instruction/utils/pumpfun.rs b/src/instruction/utils/pumpfun.rs index 55017b2..5431b4c 100644 --- a/src/instruction/utils/pumpfun.rs +++ b/src/instruction/utils/pumpfun.rs @@ -7,6 +7,8 @@ use std::sync::Arc; pub mod seeds { /// Seed for bonding curve PDAs pub const BONDING_CURVE_SEED: &[u8] = b"bonding-curve"; + /// Seed for bonding curve v2 PDA (required by program upgrade, readonly at end of account list) + pub const BONDING_CURVE_V2_SEED: &[u8] = b"bonding-curve-v2"; /// Seed for creator vault PDAs pub const CREATOR_VAULT_SEED: &[u8] = b"creator-vault"; @@ -178,6 +180,20 @@ pub fn get_bonding_curve_pda(mint: &Pubkey) -> Option { ) } +/// Bonding curve v2 PDA (seeds: ["bonding-curve-v2", mint]). Required at end of buy/sell/buy_exact_sol_in accounts. +#[inline] +pub fn get_bonding_curve_v2_pda(mint: &Pubkey) -> Option { + crate::common::fast_fn::get_cached_pda( + crate::common::fast_fn::PdaCacheKey::PumpFunBondingCurveV2(*mint), + || { + let seeds: &[&[u8]; 2] = &[seeds::BONDING_CURVE_V2_SEED, mint.as_ref()]; + let program_id: &Pubkey = &accounts::PUMPFUN; + let pda: Option<(Pubkey, u8)> = Pubkey::try_find_program_address(seeds, program_id); + pda.map(|pubkey| pubkey.0) + }, + ) +} + #[inline] pub fn get_creator(creator_vault_pda: &Pubkey) -> Pubkey { if creator_vault_pda.eq(&Pubkey::default()) { diff --git a/src/instruction/utils/pumpswap.rs b/src/instruction/utils/pumpswap.rs index 58b97fa..352be58 100644 --- a/src/instruction/utils/pumpswap.rs +++ b/src/instruction/utils/pumpswap.rs @@ -26,6 +26,9 @@ pub mod seeds { pub const USER_VOLUME_ACCUMULATOR_SEED: &[u8] = b"user_volume_accumulator"; pub const GLOBAL_VOLUME_ACCUMULATOR_SEED: &[u8] = b"global_volume_accumulator"; pub const FEE_CONFIG_SEED: &[u8] = b"fee_config"; + + /// Seed for pool v2 PDA (required by program upgrade, readonly at end of account list) + pub const POOL_V2_SEED: &[u8] = b"pool-v2"; } /// Constants related to program accounts and authorities @@ -139,6 +142,16 @@ pub const BUY_DISCRIMINATOR: [u8; 8] = [102, 6, 61, 18, 1, 218, 235, 234]; pub const BUY_EXACT_QUOTE_IN_DISCRIMINATOR: [u8; 8] = [198, 46, 21, 82, 180, 217, 232, 112]; pub const SELL_DISCRIMINATOR: [u8; 8] = [51, 230, 133, 164, 1, 127, 131, 173]; +/// Pool v2 PDA (seeds: ["pool-v2", base_mint]). Required at end of buy/sell/buy_exact_quote_in accounts. +#[inline] +pub fn get_pool_v2_pda(base_mint: &Pubkey) -> Option { + let (pda, _) = Pubkey::find_program_address( + &[seeds::POOL_V2_SEED, base_mint.as_ref()], + &accounts::AMM_PROGRAM, + ); + Some(pda) +} + // Find a pool for a specific mint pub async fn find_pool(rpc: &SolanaRpcClient, mint: &Pubkey) -> Result { let (pool_address, _) = find_by_mint(rpc, mint).await?;