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}