sol_parser_sdk/instr/
raydium_launchpad.rs

1//! Bonk 指令解析器
2//!
3//! 使用 match discriminator 模式解析 Bonk 指令
4
5use solana_sdk::{pubkey::Pubkey, signature::Signature};
6use crate::core::events::*;
7use super::utils::*;
8use super::program_ids;
9
10/// Bonk discriminator 常量
11pub mod discriminators {
12    pub const TRADE: [u8; 8] = [2, 3, 4, 5, 6, 7, 8, 9];
13    pub const POOL_CREATE: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
14    pub const MIGRATE_AMM: [u8; 8] = [3, 4, 5, 6, 7, 8, 9, 10];
15}
16
17/// Raydium Launchpad 程序 ID
18pub const PROGRAM_ID_PUBKEY: Pubkey = program_ids::BONK_PROGRAM_ID;
19
20/// 主要的 Bonk 指令解析函数
21pub fn parse_instruction(
22    instruction_data: &[u8],
23    accounts: &[Pubkey],
24    signature: Signature,
25    slot: u64,
26    tx_index: u64,
27    block_time: Option<i64>,
28) -> Option<DexEvent> {
29    if instruction_data.len() < 8 {
30        return None;
31    }
32
33    let discriminator: [u8; 8] = instruction_data[0..8].try_into().ok()?;
34    let data = &instruction_data[8..];
35
36    match discriminator {
37        discriminators::TRADE => {
38            parse_trade_instruction(data, accounts, signature, slot, tx_index, block_time)
39        },
40        discriminators::POOL_CREATE => {
41            parse_pool_create_instruction(data, accounts, signature, slot, tx_index, block_time)
42        },
43        discriminators::MIGRATE_AMM => {
44            parse_migrate_amm_instruction(data, accounts, signature, slot, tx_index, block_time)
45        },
46        _ => None,
47    }
48}
49
50/// 解析交易指令
51fn parse_trade_instruction(
52    data: &[u8],
53    accounts: &[Pubkey],
54    signature: Signature,
55    slot: u64,
56    tx_index: u64,
57    block_time: Option<i64>,
58) -> Option<DexEvent> {
59    let mut offset = 0;
60
61    let amount_in = read_u64_le(data, offset)?;
62    offset += 8;
63
64    let amount_out_min = read_u64_le(data, offset)?;
65
66    let pool_state = get_account(accounts, 0)?;
67    let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state);
68
69    Some(DexEvent::BonkTrade(BonkTradeEvent {
70        metadata,
71        pool_state,
72        user: get_account(accounts, 1).unwrap_or_default(),
73        amount_in,
74        amount_out: amount_out_min, // 先用指令中的最小值,日志会覆盖实际值
75        is_buy: true, // 默认为买入,实际值从日志确定
76        trade_direction: TradeDirection::Buy,
77        exact_in: true,
78    }))
79}
80
81/// 解析池创建指令
82fn parse_pool_create_instruction(
83    data: &[u8],
84    accounts: &[Pubkey],
85    signature: Signature,
86    slot: u64,
87    tx_index: u64,
88    block_time: Option<i64>,
89) -> Option<DexEvent> {
90    let pool_state = get_account(accounts, 0)?;
91    let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state);
92
93    Some(DexEvent::BonkPoolCreate(BonkPoolCreateEvent {
94        metadata,
95        base_mint_param: BaseMintParam {
96            symbol: "BONK".to_string(),
97            name: "Bonk Pool".to_string(),
98            uri: "https://bonk.com".to_string(),
99            decimals: 5,
100        },
101        pool_state,
102        creator: get_account(accounts, 1).unwrap_or_default(),
103    }))
104}
105
106/// 解析 AMM 迁移指令
107fn parse_migrate_amm_instruction(
108    data: &[u8],
109    accounts: &[Pubkey],
110    signature: Signature,
111    slot: u64,
112    tx_index: u64,
113    block_time: Option<i64>,
114) -> Option<DexEvent> {
115    let mut offset = 0;
116
117    let liquidity_amount = read_u64_le(data, offset)?;
118
119    let old_pool = get_account(accounts, 0)?;
120    let metadata = create_metadata_simple(signature, slot, tx_index, block_time, old_pool);
121
122    Some(DexEvent::BonkMigrateAmm(BonkMigrateAmmEvent {
123        metadata,
124        old_pool,
125        new_pool: get_account(accounts, 1).unwrap_or_default(),
126        user: get_account(accounts, 2).unwrap_or_default(),
127        liquidity_amount,
128    }))
129}