fix: correct parameter order for buy_exact_sol_in and align Raydium CPMM field names with IDL

This commit addresses two critical issues:

1. PumpFun buy_exact_sol_in Parameter Order Fix
   - Fixed incorrect parameter parsing in buy_exact_sol_in instruction
   - Created dedicated parse_buy_exact_sol_in_instruction function
   - Correct order: spendable_sol_in (SOL) first, min_tokens_out (token) second
   - Previous bug: reused parse_buy_instruction which has reversed order
   - Impact: Fixes ~4-5% of PumpFun trades that were being parsed incorrectly
   - Issue reported by community: SOL and token amounts were swapped

2. Raydium CPMM Field Naming Alignment
   - Updated PoolState struct field names to match IDL specification exactly
   - Changed token0_vault -> token_0_vault (and similar for all token fields)
   - Changed mint0_decimals -> mint_0_decimals
   - Changed protocol_fees_token0 -> protocol_fees_token_0
   - Ensures consistency with official IDL from solana-program-idls repo
   - Improves code maintainability and readability

3. IDL Files Sync
   - Added latest IDL files from https://github.com/0xfnzero/solana-program-idls
   - Includes: pumpfun, pump_amm, raydium_cpmm, raydium_clmm, raydium_pool_v4
   - Also added: meteora_amm, meteora_damm_v2, meteora_dlmm, orca_whirlpool, raydium_launchpad
   - All IDL files stored in idl/ directory for reference

Files Modified:
- src/streaming/event_parser/protocols/pumpfun/parser.rs
- src/streaming/event_parser/protocols/raydium_cpmm/types.rs
- src/streaming/event_parser/protocols/raydium_cpmm/events.rs
- src/streaming/event_parser/protocols/raydium_cpmm/parser.rs

Testing:
-  Compiles successfully (cargo build --release)
-  All field name updates verified
-  Parameter order matches IDL specification

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Wood
2026-01-23 16:47:55 +08:00
parent ce2931046d
commit da550e0c3a
15 changed files with 53535 additions and 53 deletions
+2483
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5878
View File
File diff suppressed because it is too large Load Diff
+6836
View File
File diff suppressed because it is too large Load Diff
+2291
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -27,7 +27,8 @@ pub fn parse_pumpfun_instruction_data(
discriminators::CREATE_V2_TOKEN_IX => {
parse_create_v2_token_instruction(data, accounts, metadata)
}
discriminators::BUY_IX | discriminators::BUY_EXACT_SOL_IN_IX => parse_buy_instruction(data, accounts, metadata),
discriminators::BUY_IX => parse_buy_instruction(data, accounts, metadata),
discriminators::BUY_EXACT_SOL_IN_IX => parse_buy_exact_sol_in_instruction(data, accounts, metadata),
discriminators::SELL_IX => parse_sell_instruction(data, accounts, metadata),
discriminators::MIGRATE_IX => parse_migrate_instruction(data, accounts, metadata),
_ => None,
@@ -273,6 +274,49 @@ fn parse_buy_instruction(
}))
}
/// 解析 buy_exact_sol_in 指令事件
/// 注意:参数顺序与 buy 指令不同
/// buy_exact_sol_in: spendable_sol_in (SOL), min_tokens_out (token)
/// buy: amount (token), max_sol_cost (SOL)
fn parse_buy_exact_sol_in_instruction(
data: &[u8], accounts: &[Pubkey],
mut metadata: EventMetadata,
) -> Option<DexEvent> {
metadata.event_type = EventType::PumpFunBuy;
if data.len() < 16 || accounts.len() < 16 {
return None;
}
// 注意:buy_exact_sol_in 的参数顺序是先 SOL 再 token
let spendable_sol_in = u64::from_le_bytes(data[0..8].try_into().unwrap());
let min_tokens_out = u64::from_le_bytes(data[8..16].try_into().unwrap());
Some(DexEvent::PumpFunTradeEvent(PumpFunTradeEvent {
metadata,
global: accounts[0],
fee_recipient: accounts[1],
mint: accounts[2],
bonding_curve: accounts[3],
associated_bonding_curve: accounts[4],
associated_user: accounts[5],
user: accounts[6],
system_program: accounts[7],
token_program: accounts[8],
creator_vault: accounts[9],
event_authority: accounts[10],
program: accounts[11],
global_volume_accumulator: accounts[12],
user_volume_accumulator: accounts[13],
fee_config: accounts[14],
fee_program: accounts[15],
max_sol_cost: spendable_sol_in, // Map spendable_sol_in to max_sol_cost
amount: min_tokens_out, // Map min_tokens_out to amount
is_buy: true,
..Default::default()
}))
}
// 解析卖出指令事件
fn parse_sell_instruction(
data: &[u8],
@@ -45,14 +45,14 @@ pub struct RaydiumCpmmDepositEvent {
pub authority: Pubkey,
pub pool_state: Pubkey,
pub owner_lp_token: Pubkey,
pub token0_account: Pubkey,
pub token1_account: Pubkey,
pub token0_vault: Pubkey,
pub token1_vault: Pubkey,
pub token_0_account: Pubkey,
pub token_1_account: Pubkey,
pub token_0_vault: Pubkey,
pub token_1_vault: Pubkey,
pub token_program: Pubkey,
pub token_program2022: Pubkey,
pub vault0_mint: Pubkey,
pub vault1_mint: Pubkey,
pub vault_0_mint: Pubkey,
pub vault_1_mint: Pubkey,
pub lp_mint: Pubkey,
}
@@ -69,19 +69,19 @@ pub struct RaydiumCpmmInitializeEvent {
pub amm_config: Pubkey,
pub authority: Pubkey,
pub pool_state: Pubkey,
pub token0_mint: Pubkey,
pub token1_mint: Pubkey,
pub token_0_mint: Pubkey,
pub token_1_mint: Pubkey,
pub lp_mint: Pubkey,
pub creator_token0: Pubkey,
pub creator_token1: Pubkey,
pub creator_token_0: Pubkey,
pub creator_token_1: Pubkey,
pub creator_lp_token: Pubkey,
pub token0_vault: Pubkey,
pub token1_vault: Pubkey,
pub token_0_vault: Pubkey,
pub token_1_vault: Pubkey,
pub create_pool_fee: Pubkey,
pub observation_state: Pubkey,
pub token_program: Pubkey,
pub token0_program: Pubkey,
pub token1_program: Pubkey,
pub token_0_program: Pubkey,
pub token_1_program: Pubkey,
pub associated_token_program: Pubkey,
pub system_program: Pubkey,
pub rent: Pubkey,
@@ -100,14 +100,14 @@ pub struct RaydiumCpmmWithdrawEvent {
pub authority: Pubkey,
pub pool_state: Pubkey,
pub owner_lp_token: Pubkey,
pub token0_account: Pubkey,
pub token1_account: Pubkey,
pub token0_vault: Pubkey,
pub token1_vault: Pubkey,
pub token_0_account: Pubkey,
pub token_1_account: Pubkey,
pub token_0_vault: Pubkey,
pub token_1_vault: Pubkey,
pub token_program: Pubkey,
pub token_program2022: Pubkey,
pub vault0_mint: Pubkey,
pub vault1_mint: Pubkey,
pub vault_0_mint: Pubkey,
pub vault_1_mint: Pubkey,
pub lp_mint: Pubkey,
pub memo_program: Pubkey,
}
@@ -88,14 +88,14 @@ fn parse_withdraw_instruction(
authority: accounts[1],
pool_state: accounts[2],
owner_lp_token: accounts[3],
token0_account: accounts[4],
token1_account: accounts[5],
token0_vault: accounts[6],
token1_vault: accounts[7],
token_0_account: accounts[4],
token_1_account: accounts[5],
token_0_vault: accounts[6],
token_1_vault: accounts[7],
token_program: accounts[8],
token_program2022: accounts[9],
vault0_mint: accounts[10],
vault1_mint: accounts[11],
vault_0_mint: accounts[10],
vault_1_mint: accounts[11],
lp_mint: accounts[12],
memo_program: accounts[13],
}))
@@ -121,19 +121,19 @@ fn parse_initialize_instruction(
amm_config: accounts[1],
authority: accounts[2],
pool_state: accounts[3],
token0_mint: accounts[4],
token1_mint: accounts[5],
token_0_mint: accounts[4],
token_1_mint: accounts[5],
lp_mint: accounts[6],
creator_token0: accounts[7],
creator_token1: accounts[8],
creator_token_0: accounts[7],
creator_token_1: accounts[8],
creator_lp_token: accounts[9],
token0_vault: accounts[10],
token1_vault: accounts[11],
token_0_vault: accounts[10],
token_1_vault: accounts[11],
create_pool_fee: accounts[12],
observation_state: accounts[13],
token_program: accounts[14],
token0_program: accounts[15],
token1_program: accounts[16],
token_0_program: accounts[15],
token_1_program: accounts[16],
associated_token_program: accounts[17],
system_program: accounts[18],
rent: accounts[19],
@@ -160,14 +160,14 @@ fn parse_deposit_instruction(
authority: accounts[1],
pool_state: accounts[2],
owner_lp_token: accounts[3],
token0_account: accounts[4],
token1_account: accounts[5],
token0_vault: accounts[6],
token1_vault: accounts[7],
token_0_account: accounts[4],
token_1_account: accounts[5],
token_0_vault: accounts[6],
token_1_vault: accounts[7],
token_program: accounts[8],
token_program2022: accounts[9],
vault0_mint: accounts[10],
vault1_mint: accounts[11],
vault_0_mint: accounts[10],
vault_1_mint: accounts[11],
lp_mint: accounts[12],
}))
}
@@ -62,24 +62,24 @@ pub fn amm_config_parser(account: &AccountPretty, mut metadata: EventMetadata) -
pub struct PoolState {
pub amm_config: Pubkey,
pub pool_creator: Pubkey,
pub token0_vault: Pubkey,
pub token1_vault: Pubkey,
pub token_0_vault: Pubkey,
pub token_1_vault: Pubkey,
pub lp_mint: Pubkey,
pub token0_mint: Pubkey,
pub token1_mint: Pubkey,
pub token0_program: Pubkey,
pub token1_program: Pubkey,
pub token_0_mint: Pubkey,
pub token_1_mint: Pubkey,
pub token_0_program: Pubkey,
pub token_1_program: Pubkey,
pub observation_key: Pubkey,
pub auth_bump: u8,
pub status: u8,
pub lp_mint_decimals: u8,
pub mint0_decimals: u8,
pub mint1_decimals: u8,
pub mint_0_decimals: u8,
pub mint_1_decimals: u8,
pub lp_supply: u64,
pub protocol_fees_token0: u64,
pub protocol_fees_token1: u64,
pub fund_fees_token0: u64,
pub fund_fees_token1: u64,
pub protocol_fees_token_0: u64,
pub protocol_fees_token_1: u64,
pub fund_fees_token_0: u64,
pub fund_fees_token_1: u64,
pub open_time: u64,
pub recent_epoch: u64,
pub creator_fee_on: u8,