sol_parser_sdk/core/
account_filler.rs

1//! 账户填充模块
2//!
3//! 负责从指令账户数据填充DEX事件中缺失的账户字段
4//! 每个平台的每个事件类型都有专门的填充函数
5//! 只填充那些会变化的账户,排除系统程序等常量账户
6
7use solana_sdk::pubkey::Pubkey;
8use crate::core::events::*;
9
10/// 账户获取辅助函数类型
11type AccountGetter<'a> = dyn Fn(usize) -> Pubkey + 'a;
12
13/// 主要的账户填充调度函数
14pub fn fill_accounts_from_instruction_data(
15    event: &mut DexEvent,
16    instruction_accounts: &[Pubkey],
17) {
18    // 获取账户的辅助函数
19    let get_account = |index: usize| -> Pubkey {
20        instruction_accounts.get(index).cloned().unwrap_or_default()
21    };
22
23    match event {
24        // PumpFun 事件填充
25        DexEvent::PumpFunTrade(ref mut trade_event) => {
26            pumpfun::fill_trade_accounts(trade_event, &get_account);
27        },
28        DexEvent::PumpFunCreate(ref mut create_event) => {
29            pumpfun::fill_create_accounts(create_event, &get_account);
30        },
31        DexEvent::PumpFunMigrate(ref mut migrate_event) => {
32            pumpfun::fill_migrate_accounts(migrate_event, &get_account);
33        },
34
35        // Raydium 事件填充
36        DexEvent::RaydiumClmmSwap(ref mut swap_event) => {
37            raydium::fill_clmm_swap_accounts(swap_event, &get_account);
38        },
39        DexEvent::RaydiumCpmmSwap(ref mut swap_event) => {
40            raydium::fill_cpmm_swap_accounts(swap_event, &get_account);
41        },
42        DexEvent::RaydiumAmmV4Swap(ref mut swap_event) => {
43            raydium::fill_amm_v4_swap_accounts(swap_event, &get_account);
44        },
45
46        // Orca 事件填充
47        DexEvent::OrcaWhirlpoolSwap(ref mut swap_event) => {
48            orca::fill_whirlpool_swap_accounts(swap_event, &get_account);
49        },
50
51        // Meteora 事件填充
52        DexEvent::MeteoraPoolsSwap(ref mut swap_event) => {
53            meteora::fill_pools_swap_accounts(swap_event, &get_account);
54        },
55        DexEvent::MeteoraDammV2Swap(ref mut swap_event) => {
56            meteora::fill_damm_v2_swap_accounts(swap_event, &get_account);
57        },
58        DexEvent::MeteoraDlmmSwap(ref mut swap_event) => {
59            meteora::fill_dlmm_swap_accounts(swap_event, &get_account);
60        },
61        DexEvent::MeteoraDlmmAddLiquidity(ref mut event) => {
62            meteora::fill_dlmm_add_liquidity_accounts(event, &get_account);
63        },
64        DexEvent::MeteoraDlmmRemoveLiquidity(ref mut event) => {
65            meteora::fill_dlmm_remove_liquidity_accounts(event, &get_account);
66        },
67
68        // Bonk 事件填充
69        DexEvent::BonkTrade(ref mut trade_event) => {
70            bonk::fill_trade_accounts(trade_event, &get_account);
71        },
72
73        // 其他事件类型暂时不处理
74        _ => {}
75    }
76}
77
78/// PumpFun 账户填充模块
79pub mod pumpfun {
80    use super::*;
81
82    /// 填充 PumpFun Trade 事件账户
83    /// 基于PumpFun IDL的buy/sell指令账户映射
84    pub fn fill_trade_accounts(
85        trade_event: &mut PumpFunTradeEvent,
86        get_account: &AccountGetter<'_>,
87    ) {
88        // PumpFun buy/sell指令的共同账户映射 (基于IDL):
89        // 0: global - 全局配置
90        // 1: fee_recipient - 费用接收方
91        // 2: mint - 代币mint
92        // 3: bonding_curve - 绑定曲线
93        // 4: associated_bonding_curve - 关联绑定曲线
94        // 5: associated_user - 关联用户账户
95        // 6: user - 用户账户
96
97        // 基于最新IDL buy/sell指令账户映射:
98        // 0: global - 全局配置PDA
99        // 1: fee_recipient - 费用接收方 (现在是事件字段,不再从账户填充)
100        // 2: mint - 代币mint
101        // 3: bonding_curve - 绑定曲线PDA
102        // 4: associated_bonding_curve - 关联绑定曲线PDA
103        // 5: associated_user - 关联用户PDA
104        // 6: user - 用户账户
105
106        // 暂时注释,以后会用,AI禁止改动
107        // if trade_event.global == Pubkey::default() {
108        //     trade_event.global = get_account(0);
109        // }
110        // if trade_event.mint == Pubkey::default() {
111        //     trade_event.mint = get_account(2);
112        // }
113        // if trade_event.bonding_curve == Pubkey::default() {
114        //     trade_event.bonding_curve = get_account(3);
115        // }
116        // if trade_event.associated_bonding_curve == Pubkey::default() {
117        //     trade_event.associated_bonding_curve = get_account(4);
118        // }
119        // if trade_event.associated_user == Pubkey::default() {
120        //     trade_event.associated_user = get_account(5);
121        // }
122        if trade_event.user == Pubkey::default() {
123            trade_event.user = get_account(6);
124        }
125    }
126
127    /// 填充 PumpFun Create 事件账户
128    /// 基于PumpFun IDL create指令账户映射:
129    /// 0: mint
130    /// 1: mint_authority
131    /// 2: bonding_curve
132    /// 3: associated_bonding_curve
133    /// 4: global
134    /// 5: mpl_token_metadata
135    /// 6: metadata
136    /// 7: user
137    pub fn fill_create_accounts(
138        create_event: &mut PumpFunCreateTokenEvent,
139        get_account: &AccountGetter<'_>,
140    ) {
141        if create_event.mint == Pubkey::default() {
142            create_event.mint = get_account(0);
143        }
144        if create_event.bonding_curve == Pubkey::default() {
145            create_event.bonding_curve = get_account(2);
146        }
147        if create_event.user == Pubkey::default() {
148            create_event.user = get_account(7);
149        }
150    }
151
152    /// 填充 PumpFun Migrate 事件账户
153    /// 基于PumpFun IDL migrate指令账户映射:
154    /// 0: global
155    /// 1: withdraw_authority
156    /// 2: mint
157    /// 3: bonding_curve
158    /// 4: associated_bonding_curve
159    /// 5: user
160    /// 8: pump_amm
161    /// 9: pool
162    /// 10: pool_authority
163    /// 11: pool_authority_mint_account
164    /// 12: pool_authority_wsol_account
165    /// 13: amm_global_config
166    /// 14: wsol_mint
167    /// 15: lp_mint
168    /// 16: user_pool_token_account
169    /// 17: pool_base_token_account
170    /// 18: pool_quote_token_account
171    pub fn fill_migrate_accounts(
172        migrate_event: &mut PumpFunMigrateEvent,
173        get_account: &AccountGetter<'_>,
174    ) {
175        // 暂时注释,以后会用,AI禁止改动
176        // if migrate_event.global == Pubkey::default() {
177        //     migrate_event.global = get_account(0);
178        // }
179        // if migrate_event.withdraw_authority == Pubkey::default() {
180        //     migrate_event.withdraw_authority = get_account(1);
181        // }
182        // if migrate_event.mint == Pubkey::default() {
183        //     migrate_event.mint = get_account(2);
184        // }
185        // if migrate_event.bonding_curve == Pubkey::default() {
186        //     migrate_event.bonding_curve = get_account(3);
187        // }
188        // if migrate_event.associated_bonding_curve == Pubkey::default() {
189        //     migrate_event.associated_bonding_curve = get_account(4);
190        // }
191        // if migrate_event.user == Pubkey::default() {
192        //     migrate_event.user = get_account(5);
193        // }
194        // if migrate_event.pump_amm == Pubkey::default() {
195        //     migrate_event.pump_amm = get_account(8);
196        // }
197        // if migrate_event.pool == Pubkey::default() {
198        //     migrate_event.pool = get_account(9);
199        // }
200        // if migrate_event.pool_authority == Pubkey::default() {
201        //     migrate_event.pool_authority = get_account(10);
202        // }
203        // if migrate_event.pool_authority_mint_account == Pubkey::default() {
204        //     migrate_event.pool_authority_mint_account = get_account(11);
205        // }
206        // if migrate_event.pool_authority_wsol_account == Pubkey::default() {
207        //     migrate_event.pool_authority_wsol_account = get_account(12);
208        // }
209        // if migrate_event.amm_global_config == Pubkey::default() {
210        //     migrate_event.amm_global_config = get_account(13);
211        // }
212        // if migrate_event.wsol_mint == Pubkey::default() {
213        //     migrate_event.wsol_mint = get_account(14);
214        // }
215        // if migrate_event.lp_mint == Pubkey::default() {
216        //     migrate_event.lp_mint = get_account(15);
217        // }
218        // if migrate_event.user_pool_token_account == Pubkey::default() {
219        //     migrate_event.user_pool_token_account = get_account(16);
220        // }
221        // if migrate_event.pool_base_token_account == Pubkey::default() {
222        //     migrate_event.pool_base_token_account = get_account(17);
223        // }
224        // if migrate_event.pool_quote_token_account == Pubkey::default() {
225        //     migrate_event.pool_quote_token_account = get_account(18);
226        // }
227    }
228}
229
230/// Raydium 账户填充模块
231pub mod raydium {
232    use super::*;
233
234    /// 填充 Raydium CLMM Swap 事件账户
235    pub fn fill_clmm_swap_accounts(
236        swap_event: &mut RaydiumClmmSwapEvent,
237        get_account: &AccountGetter<'_>,
238    ) {
239        // 基于Raydium CLMM IDL swap指令账户映射
240        if swap_event.pool_state == Pubkey::default() {
241            swap_event.pool_state = get_account(1);
242        }
243        if swap_event.sender == Pubkey::default() {
244            swap_event.sender = get_account(0);
245        }
246    }
247
248    /// 填充 Raydium CPMM Swap 事件账户
249    /// 基于Raydium CPMM swapBaseInput/swapBaseOutput指令IDL定义账户映射
250    pub fn fill_cpmm_swap_accounts(
251        swap_event: &mut RaydiumCpmmSwapEvent,
252        get_account: &AccountGetter<'_>,
253    ) {
254        // Raydium CPMM swap指令账户映射 (基于IDL):
255        // 0: payer - 用户执行交换
256        // 1: authority - 权限账户
257        // 2: ammConfig - AMM配置
258        // 3: poolState - 池状态
259        // 4: inputTokenAccount - 输入代币账户
260        // 5: outputTokenAccount - 输出代币账户
261        // 6: inputVault - 输入库存
262        // 7: outputVault - 输出库存
263        // 8: inputTokenProgram - 输入代币程序
264        // 9: outputTokenProgram - 输出代币程序
265        // 10: inputTokenMint - 输入代币mint
266        // 11: outputTokenMint - 输出代币mint
267        // 12: observationState - 观察状态
268
269        // 基于最新IDL swapBaseInput指令账户映射:
270        // 0: payer - 用户执行交换
271        // 1: authority - 权限账户
272        // 2: ammConfig - AMM配置
273        // 3: poolState - 池状态
274        // 4: inputTokenAccount - 用户输入代币账户
275        // 5: outputTokenAccount - 用户输出代币账户
276        // 6: inputVault - 输入库存
277        // 7: outputVault - 输出库存
278        // 10: inputTokenMint - 输入代币mint
279        // 11: outputTokenMint - 输出代币mint
280
281        // 暂时注释,以后会用,AI禁止改动
282        // if swap_event.payer == Pubkey::default() {
283        //     swap_event.payer = get_account(0);
284        // }
285        // if swap_event.authority == Pubkey::default() {
286        //     swap_event.authority = get_account(1);
287        // }
288        // if swap_event.amm_config == Pubkey::default() {
289        //     swap_event.amm_config = get_account(2);
290        // }
291        // if swap_event.pool_state == Pubkey::default() {
292        //     swap_event.pool_state = get_account(3);
293        // }
294        // if swap_event.input_token_account == Pubkey::default() {
295        //     swap_event.input_token_account = get_account(4);
296        // }
297        // if swap_event.output_token_account == Pubkey::default() {
298        //     swap_event.output_token_account = get_account(5);
299        // }
300        // if swap_event.input_vault == Pubkey::default() {
301        //     swap_event.input_vault = get_account(6);
302        // }
303        // if swap_event.output_vault == Pubkey::default() {
304        //     swap_event.output_vault = get_account(7);
305        // }
306        // if swap_event.input_token_mint == Pubkey::default() {
307        //     swap_event.input_token_mint = get_account(10);
308        // }
309        // if swap_event.output_token_mint == Pubkey::default() {
310        //     swap_event.output_token_mint = get_account(11);
311        // }
312
313    }
314
315    /// 填充 Raydium AMM V4 Swap 事件账户
316    pub fn fill_amm_v4_swap_accounts(
317        swap_event: &mut RaydiumAmmV4SwapEvent,
318        get_account: &AccountGetter<'_>,
319    ) {
320        // TODO: 基于Raydium AMM V4 IDL定义账户映射
321        if swap_event.amm == Pubkey::default() {
322            swap_event.amm = get_account(1);
323        }
324        // RaydiumAmmV4SwapEvent 没有user字段,需要后续添加
325    }
326}
327
328/// Orca 账户填充模块
329pub mod orca {
330    use super::*;
331
332    /// 填充 Orca Whirlpool Swap 事件账户
333    pub fn fill_whirlpool_swap_accounts(
334        swap_event: &mut OrcaWhirlpoolSwapEvent,
335        get_account: &AccountGetter<'_>,
336    ) {
337        // 基于Orca Whirlpool swap指令IDL账户映射:
338        // 0: tokenProgram - SPL代币程序 (常量)
339        // 1: tokenAuthority - 代币权限
340        // 2: whirlpool - 池状态
341        // 3: tokenOwnerAccountA - 用户代币A账户
342        // 4: tokenVaultA - 池代币A库存
343        // 5: tokenOwnerAccountB - 用户代币B账户
344        // 6: tokenVaultB - 池代币B库存
345        // 7: tickArray0 - tick数组0
346        // 8: tickArray1 - tick数组1
347        // 9: tickArray2 - tick数组2
348
349        // 暂时注释,以后会用,AI禁止改动
350        // if swap_event.token_authority == Pubkey::default() {
351        //     swap_event.token_authority = get_account(1);
352        // }
353        // if swap_event.whirlpool == Pubkey::default() {
354        //     swap_event.whirlpool = get_account(2);
355        // }
356        // if swap_event.token_owner_account_a == Pubkey::default() {
357        //     swap_event.token_owner_account_a = get_account(3);
358        // }
359        // if swap_event.token_vault_a == Pubkey::default() {
360        //     swap_event.token_vault_a = get_account(4);
361        // }
362        // if swap_event.token_owner_account_b == Pubkey::default() {
363        //     swap_event.token_owner_account_b = get_account(5);
364        // }
365        // if swap_event.token_vault_b == Pubkey::default() {
366        //     swap_event.token_vault_b = get_account(6);
367        // }
368        // if swap_event.tick_array_0 == Pubkey::default() {
369        //     swap_event.tick_array_0 = get_account(7);
370        // }
371        // if swap_event.tick_array_1 == Pubkey::default() {
372        //     swap_event.tick_array_1 = get_account(8);
373        // }
374        // if swap_event.tick_array_2 == Pubkey::default() {
375        //     swap_event.tick_array_2 = get_account(9);
376        // }
377    }
378}
379
380/// Meteora 账户填充模块
381pub mod meteora {
382    use super::*;
383
384    /// 填充 Meteora Pools Swap 事件账户
385    /// 基于Meteora AMM IDL swap指令账户映射:
386    /// 0: pool
387    /// 1: userSourceToken
388    /// 2: userDestinationToken
389    /// 3: aVault
390    /// 4: bVault
391    /// 5: aTokenVault
392    /// 6: bTokenVault
393    /// 7: aVaultLpMint
394    /// 8: bVaultLpMint
395    /// 9: aVaultLp
396    /// 10: bVaultLp
397    /// 11: adminTokenFee
398    /// 12: user
399    pub fn fill_pools_swap_accounts(
400        swap_event: &mut MeteoraPoolsSwapEvent,
401        get_account: &AccountGetter<'_>,
402    ) {
403        // MeteoraPoolsSwapEvent只有IDL事件字段,无指令账户字段
404    }
405
406    /// 填充 Meteora DAMM V2 Swap 事件账户
407    pub fn fill_damm_v2_swap_accounts(
408        swap_event: &mut MeteoraDammV2SwapEvent,
409        get_account: &AccountGetter<'_>,
410    ) {
411        if swap_event.lb_pair == Pubkey::default() {
412            swap_event.lb_pair = get_account(1);
413        }
414        if swap_event.from == Pubkey::default() {
415            swap_event.from = get_account(0);
416        }
417    }
418
419    /// 填充 Meteora DLMM Swap 事件账户
420    /// 基于Meteora DLMM IDL swap指令账户映射:
421    /// 0: lbPair
422    /// 5: userTokenOut
423    /// 10: user
424    pub fn fill_dlmm_swap_accounts(
425        swap_event: &mut MeteoraDlmmSwapEvent,
426        get_account: &AccountGetter<'_>,
427    ) {
428        if swap_event.pool == Pubkey::default() {
429            swap_event.pool = get_account(0);
430        }
431        if swap_event.from == Pubkey::default() {
432            swap_event.from = get_account(10);
433        }
434    }
435
436    /// 填充 Meteora DLMM Add Liquidity 事件账户
437    /// 基于Meteora DLMM IDL addLiquidity指令账户映射:
438    /// 0: position
439    /// 1: lbPair
440    /// 11: sender
441    pub fn fill_dlmm_add_liquidity_accounts(
442        event: &mut MeteoraDlmmAddLiquidityEvent,
443        get_account: &AccountGetter<'_>,
444    ) {
445        if event.position == Pubkey::default() {
446            event.position = get_account(0);
447        }
448        if event.pool == Pubkey::default() {
449            event.pool = get_account(1);
450        }
451        if event.from == Pubkey::default() {
452            event.from = get_account(11);
453        }
454    }
455
456    /// 填充 Meteora DLMM Remove Liquidity 事件账户
457    /// 基于Meteora DLMM IDL removeLiquidity指令账户映射:
458    /// 0: position
459    /// 1: lbPair
460    /// 11: sender
461    pub fn fill_dlmm_remove_liquidity_accounts(
462        event: &mut MeteoraDlmmRemoveLiquidityEvent,
463        get_account: &AccountGetter<'_>,
464    ) {
465        if event.position == Pubkey::default() {
466            event.position = get_account(0);
467        }
468        if event.pool == Pubkey::default() {
469            event.pool = get_account(1);
470        }
471        if event.from == Pubkey::default() {
472            event.from = get_account(11);
473        }
474    }
475}
476
477/// Bonk 账户填充模块
478pub mod bonk {
479    use super::*;
480
481    /// 填充 Bonk Trade 事件账户
482    pub fn fill_trade_accounts(
483        trade_event: &mut BonkTradeEvent,
484        get_account: &AccountGetter<'_>,
485    ) {
486        // 基于Bonk IDL swap指令账户映射
487        if trade_event.user == Pubkey::default() {
488            trade_event.user = get_account(0);
489        }
490        if trade_event.pool_state == Pubkey::default() {
491            trade_event.pool_state = get_account(1);
492        }
493    }
494}