Skip to main content

sol_parser_sdk/logs/
discriminator_lut.rs

1//! Discriminator Lookup Table (LUT) - Compile-time constant array
2//!
3//! Zero-latency optimization: Use const array with binary search for O(log n) discriminator -> event type mapping
4//! Expected latency reduction: 1-10ns (binary search on sorted array, better cache locality than match)
5
6use crate::core::events::{DexEvent, EventMetadata};
7use crate::grpc::types::EventType;
8
9/// Discriminator type alias for clarity
10pub type Discriminator = u64;
11
12/// Parser function type - takes decoded data and metadata, returns parsed event
13pub type ParserFn = fn(&[u8], EventMetadata) -> Option<DexEvent>;
14
15/// Event metadata for discriminator lookup
16#[derive(Debug, Clone, Copy)]
17pub struct DiscriminatorInfo {
18    pub discriminator: u64,
19    pub parser: ParserFn,
20    pub protocol: Protocol,
21    pub name: &'static str, // Human-readable name for debugging
22}
23
24/// Protocol enum for quick protocol identification
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum Protocol {
27    PumpFun,
28    PumpFees,
29    PumpSwap,
30    RaydiumClmm,
31    RaydiumCpmm,
32    RaydiumAmm,
33    OrcaWhirlpool,
34    MeteoraAmm,
35    MeteoraDamm,
36    MeteoraDlmm,
37}
38
39// ============================================================================
40// Parser function wrappers - delegate to protocol-specific parsers
41// ============================================================================
42
43// PumpFun parsers
44#[inline(always)]
45fn parse_pumpfun_create(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
46    crate::logs::pump::parse_create_from_data(data, metadata)
47}
48
49#[inline(always)]
50fn parse_pumpfun_trade(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
51    crate::logs::pump::parse_trade_from_data(data, metadata, false)
52}
53
54#[inline(always)]
55fn parse_pumpfun_migrate(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
56    crate::logs::pump::parse_migrate_from_data(data, metadata)
57}
58
59#[inline(always)]
60fn parse_pumpfun_migrate_bonding_curve_creator(
61    data: &[u8],
62    metadata: EventMetadata,
63) -> Option<DexEvent> {
64    crate::logs::pump::parse_migrate_bonding_curve_creator_from_data(data, metadata)
65}
66
67#[inline(always)]
68fn parse_pumpfees_initialize_fee_config(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
69    crate::logs::pump_fees::parse_initialize_fee_config_from_data(data, metadata)
70}
71
72#[inline(always)]
73fn parse_pumpfees_reset(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
74    crate::logs::pump_fees::parse_reset_fee_sharing_config_from_data(data, metadata)
75}
76
77#[inline(always)]
78fn parse_pumpfees_revoke(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
79    crate::logs::pump_fees::parse_revoke_fee_sharing_authority_from_data(data, metadata)
80}
81
82#[inline(always)]
83fn parse_pumpfees_transfer(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
84    crate::logs::pump_fees::parse_transfer_fee_sharing_authority_from_data(data, metadata)
85}
86
87#[inline(always)]
88fn parse_pumpfees_update_admin(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
89    crate::logs::pump_fees::parse_update_admin_from_data(data, metadata)
90}
91
92#[inline(always)]
93fn parse_pumpfees_update_fee_config(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
94    crate::logs::pump_fees::parse_update_fee_config_from_data(data, metadata)
95}
96
97#[inline(always)]
98fn parse_pumpfees_update_fee_shares(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
99    crate::logs::pump_fees::parse_update_fee_shares_from_data(data, metadata)
100}
101
102#[inline(always)]
103fn parse_pumpfees_upsert_fee_tiers(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
104    crate::logs::pump_fees::parse_upsert_fee_tiers_from_data(data, metadata)
105}
106
107#[inline(always)]
108fn parse_pumpfun_create_fee_sharing_config(
109    data: &[u8],
110    metadata: EventMetadata,
111) -> Option<DexEvent> {
112    crate::logs::pump_fees::parse_create_fee_sharing_config_from_data(data, metadata)
113}
114
115// PumpSwap parsers
116#[inline(always)]
117fn parse_pumpswap_buy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
118    crate::logs::pump_amm::parse_buy_from_data(data, metadata)
119}
120
121#[inline(always)]
122fn parse_pumpswap_sell(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
123    crate::logs::pump_amm::parse_sell_from_data(data, metadata)
124}
125
126#[inline(always)]
127fn parse_pumpswap_create_pool(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
128    crate::logs::pump_amm::parse_create_pool_from_data(data, metadata)
129}
130
131#[inline(always)]
132fn parse_pumpswap_add_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
133    crate::logs::pump_amm::parse_add_liquidity_from_data(data, metadata)
134}
135
136#[inline(always)]
137fn parse_pumpswap_remove_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
138    crate::logs::pump_amm::parse_remove_liquidity_from_data(data, metadata)
139}
140
141// Raydium CLMM parsers
142#[inline(always)]
143fn parse_raydium_clmm_swap(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
144    crate::logs::raydium_clmm::parse_swap_from_data(data, metadata)
145}
146
147#[inline(always)]
148fn parse_raydium_clmm_increase_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
149    crate::logs::raydium_clmm::parse_increase_liquidity_from_data(data, metadata)
150}
151
152#[inline(always)]
153fn parse_raydium_clmm_decrease_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
154    crate::logs::raydium_clmm::parse_decrease_liquidity_from_data(data, metadata)
155}
156
157#[inline(always)]
158fn parse_raydium_clmm_liquidity_change(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
159    crate::logs::raydium_clmm::parse_liquidity_change_from_data(data, metadata)
160}
161
162#[inline(always)]
163fn parse_raydium_clmm_config_change(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
164    crate::logs::raydium_clmm::parse_config_change_from_data(data, metadata)
165}
166
167#[inline(always)]
168fn parse_raydium_clmm_create_personal_position(
169    data: &[u8],
170    metadata: EventMetadata,
171) -> Option<DexEvent> {
172    crate::logs::raydium_clmm::parse_create_personal_position_from_data(data, metadata)
173}
174
175#[inline(always)]
176fn parse_raydium_clmm_liquidity_calculate(
177    data: &[u8],
178    metadata: EventMetadata,
179) -> Option<DexEvent> {
180    crate::logs::raydium_clmm::parse_liquidity_calculate_from_data(data, metadata)
181}
182
183#[inline(always)]
184fn parse_raydium_clmm_open_limit_order(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
185    crate::logs::raydium_clmm::parse_open_limit_order_from_data(data, metadata)
186}
187
188#[inline(always)]
189fn parse_raydium_clmm_increase_limit_order(
190    data: &[u8],
191    metadata: EventMetadata,
192) -> Option<DexEvent> {
193    crate::logs::raydium_clmm::parse_increase_limit_order_from_data(data, metadata)
194}
195
196#[inline(always)]
197fn parse_raydium_clmm_decrease_limit_order(
198    data: &[u8],
199    metadata: EventMetadata,
200) -> Option<DexEvent> {
201    crate::logs::raydium_clmm::parse_decrease_limit_order_from_data(data, metadata)
202}
203
204#[inline(always)]
205fn parse_raydium_clmm_settle_limit_order(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
206    crate::logs::raydium_clmm::parse_settle_limit_order_from_data(data, metadata)
207}
208
209#[inline(always)]
210fn parse_raydium_clmm_update_reward_infos(
211    data: &[u8],
212    metadata: EventMetadata,
213) -> Option<DexEvent> {
214    crate::logs::raydium_clmm::parse_update_reward_infos_from_data(data, metadata)
215}
216
217#[inline(always)]
218fn parse_raydium_clmm_create_pool(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
219    crate::logs::raydium_clmm::parse_create_pool_from_data(data, metadata)
220}
221
222#[inline(always)]
223fn parse_raydium_clmm_collect_personal_fee(
224    data: &[u8],
225    metadata: EventMetadata,
226) -> Option<DexEvent> {
227    crate::logs::raydium_clmm::parse_collect_personal_fee_from_data(data, metadata)
228}
229
230#[inline(always)]
231fn parse_raydium_clmm_collect_protocol_fee(
232    data: &[u8],
233    metadata: EventMetadata,
234) -> Option<DexEvent> {
235    crate::logs::raydium_clmm::parse_collect_protocol_fee_from_data(data, metadata)
236}
237
238// Raydium CPMM parsers
239#[inline(always)]
240fn parse_raydium_cpmm_swap_base_in(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
241    crate::logs::raydium_cpmm::parse_swap_base_in_from_data(data, metadata)
242}
243
244#[inline(always)]
245fn parse_raydium_cpmm_swap_base_out(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
246    crate::logs::raydium_cpmm::parse_swap_base_out_from_data(data, metadata)
247}
248
249#[inline(always)]
250fn parse_raydium_cpmm_create_pool(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
251    crate::logs::raydium_cpmm::parse_create_pool_from_data(data, metadata)
252}
253
254#[inline(always)]
255fn parse_raydium_cpmm_deposit(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
256    crate::logs::raydium_cpmm::parse_deposit_from_data(data, metadata)
257}
258
259#[inline(always)]
260fn parse_raydium_cpmm_withdraw(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
261    crate::logs::raydium_cpmm::parse_withdraw_from_data(data, metadata)
262}
263
264// Raydium AMM V4 parsers
265#[inline(always)]
266fn parse_raydium_amm_swap_base_in(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
267    crate::logs::raydium_amm::parse_swap_base_in_from_data(data, metadata)
268}
269
270#[inline(always)]
271fn parse_raydium_amm_swap_base_out(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
272    crate::logs::raydium_amm::parse_swap_base_out_from_data(data, metadata)
273}
274
275#[inline(always)]
276fn parse_raydium_amm_deposit(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
277    crate::logs::raydium_amm::parse_deposit_from_data(data, metadata)
278}
279
280#[inline(always)]
281fn parse_raydium_amm_withdraw(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
282    crate::logs::raydium_amm::parse_withdraw_from_data(data, metadata)
283}
284
285#[inline(always)]
286fn parse_raydium_amm_initialize2(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
287    crate::logs::raydium_amm::parse_initialize2_from_data(data, metadata)
288}
289
290// Orca Whirlpool parsers
291#[inline(always)]
292fn parse_orca_traded(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
293    crate::logs::orca_whirlpool::parse_traded_from_data(data, metadata)
294}
295
296#[inline(always)]
297fn parse_orca_liquidity_increased(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
298    crate::logs::orca_whirlpool::parse_liquidity_increased_from_data(data, metadata)
299}
300
301#[inline(always)]
302fn parse_orca_liquidity_decreased(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
303    crate::logs::orca_whirlpool::parse_liquidity_decreased_from_data(data, metadata)
304}
305
306#[inline(always)]
307fn parse_orca_pool_initialized(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
308    crate::logs::orca_whirlpool::parse_pool_initialized_from_data(data, metadata)
309}
310
311// Meteora AMM parsers
312#[inline(always)]
313fn parse_meteora_amm_swap(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
314    crate::logs::meteora_amm::parse_swap_from_data(data, metadata)
315}
316
317#[inline(always)]
318fn parse_meteora_amm_add_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
319    crate::logs::meteora_amm::parse_add_liquidity_from_data(data, metadata)
320}
321
322#[inline(always)]
323fn parse_meteora_amm_remove_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
324    crate::logs::meteora_amm::parse_remove_liquidity_from_data(data, metadata)
325}
326
327#[inline(always)]
328fn parse_meteora_amm_bootstrap_liquidity(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
329    crate::logs::meteora_amm::parse_bootstrap_liquidity_from_data(data, metadata)
330}
331
332#[inline(always)]
333fn parse_meteora_amm_pool_created(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
334    crate::logs::meteora_amm::parse_pool_created_from_data(data, metadata)
335}
336
337// ============================================================================
338// Const lookup table - Sorted by discriminator for binary search
339// ============================================================================
340
341macro_rules! disc_entry {
342    ($disc:expr, $name:expr, $parser:expr, $protocol:expr) => {
343        DiscriminatorInfo {
344            discriminator: $disc,
345            parser: $parser,
346            protocol: $protocol,
347            name: $name,
348        }
349    };
350}
351
352/// Compile-time constant array: discriminator -> parser info
353/// MUST be kept sorted by discriminator for binary search!
354///
355/// Expected latency: 3–8 ns (binary search on 33 discriminators ⇒ at most 6 comparisons)
356pub const DISCRIMINATOR_LUT: &[DiscriminatorInfo] = &[
357    disc_entry!(
358        0x0100000000000000,
359        "Raydium AMM Initialize2",
360        parse_raydium_amm_initialize2,
361        Protocol::RaydiumAmm
362    ),
363    disc_entry!(
364        0x0300000000000000,
365        "Raydium AMM Deposit",
366        parse_raydium_amm_deposit,
367        Protocol::RaydiumAmm
368    ),
369    disc_entry!(
370        0x03F36CD5DC68A79B_u64,
371        "PumpFun Migrate Bonding Curve Creator",
372        parse_pumpfun_migrate_bonding_curve_creator,
373        Protocol::PumpFun
374    ),
375    disc_entry!(
376        0x0400000000000000,
377        "Raydium AMM Withdraw",
378        parse_raydium_amm_withdraw,
379        Protocol::RaydiumAmm
380    ),
381    disc_entry!(619296439455019615, "PUMPFUN_COMPLETE", parse_pumpfun_complete, Protocol::PumpFun),
382    disc_entry!(
383        0x0900000000000000,
384        "Raydium AMM Swap Base In",
385        parse_raydium_amm_swap_base_in,
386        Protocol::RaydiumAmm
387    ),
388    disc_entry!(
389        0xABB5CA7047241A6,
390        "Orca Whirlpool Liquidity Decreased",
391        parse_orca_liquidity_decreased,
392        Protocol::OrcaWhirlpool
393    ),
394    disc_entry!(
395        0x0B00000000000000,
396        "Raydium AMM Swap Base Out",
397        parse_raydium_amm_swap_base_out,
398        Protocol::RaydiumAmm
399    ),
400    disc_entry!(
401        0x22A16D949C4612B7,
402        "Raydium CPMM Withdraw",
403        parse_raydium_cpmm_withdraw,
404        Protocol::RaydiumCpmm
405    ),
406    disc_entry!(0x2ADC03A50A372F3E, "PumpSwap Sell", parse_pumpswap_sell, Protocol::PumpSwap),
407    disc_entry!(
408        3118876958563052404,
409        "PUMPFUN_SWEEP_BONDING_CURVE_FEE",
410        parse_pumpfun_sweep_bonding_curve_fee,
411        Protocol::PumpFun
412    ),
413    disc_entry!(
414        0x385532443A56DE3A,
415        "Raydium CLMM Decrease Liquidity",
416        parse_raydium_clmm_decrease_liquidity,
417        Protocol::RaydiumClmm
418    ),
419    disc_entry!(
420        0x3A981F67E861F474,
421        "Meteora AMM Remove Liquidity",
422        parse_meteora_amm_remove_liquidity,
423        Protocol::MeteoraAmm
424    ),
425    disc_entry!(
426        0x3DD5292D4F1157CE,
427        "Raydium CLMM Collect Protocol Fee",
428        parse_raydium_clmm_collect_protocol_fee,
429        Protocol::RaydiumClmm
430    ),
431    disc_entry!(
432        0x3E99BE0E3C651772_u64,
433        "Pump Fees Revoke Fee Sharing Authority",
434        parse_pumpfees_revoke,
435        Protocol::PumpFees
436    ),
437    disc_entry!(
438        0x3F3563702F4B5E19,
439        "Raydium CLMM Create Pool",
440        parse_raydium_clmm_create_pool,
441        Protocol::RaydiumClmm
442    ),
443    disc_entry!(
444        0x529DDC6858292CCA,
445        "Meteora AMM Pool Created",
446        parse_meteora_amm_pool_created,
447        Protocol::MeteoraAmm
448    ),
449    disc_entry!(
450        0x541E2220D4694F31,
451        "Raydium CLMM Increase Liquidity",
452        parse_raydium_clmm_increase_liquidity,
453        Protocol::RaydiumClmm
454    ),
455    disc_entry!(
456        0x58FB74B8C8AA6985_u64,
457        "Pump Fees Create Fee Sharing Config",
458        parse_pumpfun_create_fee_sharing_config,
459        Protocol::PumpFees
460    ),
461    disc_entry!(
462        0x6953A151C069AEA6,
463        "Raydium CLMM Collect Personal Fee",
464        parse_raydium_clmm_collect_personal_fee,
465        Protocol::RaydiumClmm
466    ),
467    disc_entry!(
468        0x6B99589ECEAFF07E,
469        "Raydium CLMM Liquidity Change",
470        parse_raydium_clmm_liquidity_change,
471        Protocol::RaydiumClmm
472    ),
473    disc_entry!(
474        0x74A776A0D20C31B1,
475        "PumpSwap Create Pool",
476        parse_pumpswap_create_pool,
477        Protocol::PumpSwap
478    ),
479    disc_entry!(0x7663EBDE4DA91B1B, "PumpFun Create", parse_pumpfun_create, Protocol::PumpFun),
480    disc_entry!(0x7777F52C1F52F467, "PumpSwap Buy", parse_pumpswap_buy, Protocol::PumpSwap),
481    disc_entry!(
482        0x7EE2380AE6F48A59_u64,
483        "Pump Fees Initialize Fee Config",
484        parse_pumpfees_initialize_fee_config,
485        Protocol::PumpFees
486    ),
487    disc_entry!(
488        0x906B8E1F533DF878,
489        "PumpSwap Add Liquidity",
490        parse_pumpswap_add_liquidity,
491        Protocol::PumpSwap
492    ),
493    disc_entry!(0x94EA945DB95DE9BD, "PumpFun Migrate", parse_pumpfun_migrate, Protocol::PumpFun),
494    disc_entry!(
495        0x96A02B93AF49CAE1,
496        "Orca Whirlpool Traded",
497        parse_orca_traded,
498        Protocol::OrcaWhirlpool
499    ),
500    disc_entry!(
501        0x975F706A7707BDF7,
502        "Raydium CLMM Config Change",
503        parse_raydium_clmm_config_change,
504        Protocol::RaydiumClmm
505    ),
506    disc_entry!(
507        0xA19BFE6690071E1E,
508        "Orca Whirlpool Liquidity Increased",
509        parse_orca_liquidity_increased,
510        Protocol::OrcaWhirlpool
511    ),
512    disc_entry!(
513        0xA2B45439E69470ED,
514        "Raydium CLMM Liquidity Calculate",
515        parse_raydium_clmm_liquidity_calculate,
516        Protocol::RaydiumClmm
517    ),
518    disc_entry!(
519        0xA3D4EDDBDD283046,
520        "Raydium CLMM Decrease Limit Order",
521        parse_raydium_clmm_decrease_limit_order,
522        Protocol::RaydiumClmm
523    ),
524    disc_entry!(
525        11927646055507993730,
526        "PUMPSWAP_SWEEP_POOL_FEE",
527        parse_pumpswap_sweep_pool_fee,
528        Protocol::PumpSwap
529    ),
530    disc_entry!(
531        0xADB44AA35662D937,
532        "Raydium CPMM Swap Base Out",
533        parse_raydium_cpmm_swap_base_out,
534        Protocol::RaydiumCpmm
535    ),
536    disc_entry!(
537        0xB6F2E15289C623F2,
538        "Raydium CPMM Deposit",
539        parse_raydium_cpmm_deposit,
540        Protocol::RaydiumCpmm
541    ),
542    disc_entry!(
543        0xBA3D34E35A7D5E1F,
544        "Meteora AMM Add Liquidity",
545        parse_meteora_amm_add_liquidity,
546        Protocol::MeteoraAmm
547    ),
548    disc_entry!(
549        0xC0472CA01A850916,
550        "PumpSwap Remove Liquidity",
551        parse_pumpswap_remove_liquidity,
552        Protocol::PumpSwap
553    ),
554    disc_entry!(
555        0xC20A7C7DA44D7758,
556        "Raydium CLMM Settle Limit Order",
557        parse_raydium_clmm_settle_limit_order,
558        Protocol::RaydiumClmm
559    ),
560    disc_entry!(
561        0xC40AD0CDBE6CE351,
562        "Meteora AMM Swap",
563        parse_meteora_amm_swap,
564        Protocol::MeteoraAmm
565    ),
566    disc_entry!(
567        0xC81357C7CC0D780B,
568        "Raydium CLMM Increase Limit Order",
569        parse_raydium_clmm_increase_limit_order,
570        Protocol::RaydiumClmm
571    ),
572    disc_entry!(
573        0xCBE1E45BB8C4BA15_u64,
574        "Pump Fees Update Fee Shares",
575        parse_pumpfees_update_fee_shares,
576        Protocol::PumpFees
577    ),
578    disc_entry!(
579        0xCC21BA7ABBA959AB_u64,
580        "Pump Fees Upsert Fee Tiers",
581        parse_pumpfees_upsert_fee_tiers,
582        Protocol::PumpFees
583    ),
584    disc_entry!(
585        0xCE9ADFC4F9571E64,
586        "Raydium CLMM Create Personal Position",
587        parse_raydium_clmm_create_personal_position,
588        Protocol::RaydiumClmm
589    ),
590    disc_entry!(
591        0xD0BCF43E2341175A_u64,
592        "Pump Fees Update Fee Config",
593        parse_pumpfees_update_fee_config,
594        Protocol::PumpFees
595    ),
596    disc_entry!(
597        0xD89EA9395547186A,
598        "Raydium CLMM Open Limit Order",
599        parse_raydium_clmm_open_limit_order,
600        Protocol::RaydiumClmm
601    ),
602    disc_entry!(
603        0xDE331EC4DA5ABE8F,
604        "Raydium CPMM Swap Base In",
605        parse_raydium_cpmm_swap_base_in,
606        Protocol::RaydiumCpmm
607    ),
608    disc_entry!(
609        0xE2710826E8CDC640,
610        "Raydium CLMM Swap",
611        parse_raydium_clmm_swap,
612        Protocol::RaydiumClmm
613    ),
614    disc_entry!(
615        0xE5FEC60C57AD7664,
616        "Orca Whirlpool Initialize",
617        parse_orca_pool_initialized,
618        Protocol::OrcaWhirlpool
619    ),
620    disc_entry!(
621        0xEA423FF657AB98E1_u64,
622        "Pump Fees Update Admin",
623        parse_pumpfees_update_admin,
624        Protocol::PumpFees
625    ),
626    disc_entry!(
627        0xEC08B84DF5C68F7C_u64,
628        "Pump Fees Transfer Fee Sharing Authority",
629        parse_pumpfees_transfer,
630        Protocol::PumpFees
631    ),
632    disc_entry!(
633        0xEC2541724EBA7F6D,
634        "Raydium CLMM Update Reward Infos",
635        parse_raydium_clmm_update_reward_infos,
636        Protocol::RaydiumClmm
637    ),
638    disc_entry!(0xEE61E64ED37FDBBD, "PumpFun Trade", parse_pumpfun_trade, Protocol::PumpFun),
639    disc_entry!(
640        0xF3D63778E297CCCB_u64,
641        "Pump Fees Reset Fee Sharing Config",
642        parse_pumpfees_reset,
643        Protocol::PumpFees
644    ),
645    disc_entry!(
646        0xF70E375C88267F79,
647        "Meteora AMM Bootstrap Liquidity",
648        parse_meteora_amm_bootstrap_liquidity,
649        Protocol::MeteoraAmm
650    ),
651    disc_entry!(
652        18146529233607700591,
653        "PUMPFUN_POST_COMPLETE_BUY",
654        parse_pumpfun_post_complete_buy,
655        Protocol::PumpFun
656    ),
657];
658
659/// Fast lookup by discriminator - O(log n) binary search
660///
661/// With 33 entries, this requires at most 6 comparisons
662#[inline(always)]
663pub fn lookup_discriminator(discriminator: u64) -> Option<&'static DiscriminatorInfo> {
664    DISCRIMINATOR_LUT
665        .binary_search_by_key(&discriminator, |info| info.discriminator)
666        .ok()
667        .map(|idx| &DISCRIMINATOR_LUT[idx])
668}
669
670/// Get event name from discriminator
671#[inline(always)]
672pub fn discriminator_to_name(discriminator: u64) -> Option<&'static str> {
673    lookup_discriminator(discriminator).map(|info| info.name)
674}
675
676/// Get protocol from discriminator
677#[inline(always)]
678pub fn discriminator_to_protocol(discriminator: u64) -> Option<Protocol> {
679    lookup_discriminator(discriminator).map(|info| info.protocol)
680}
681
682/// Parse event using discriminator lookup
683#[inline(always)]
684pub fn parse_with_discriminator(
685    discriminator: u64,
686    data: &[u8],
687    metadata: EventMetadata,
688) -> Option<DexEvent> {
689    let info = lookup_discriminator(discriminator)?;
690    (info.parser)(data, metadata)
691}
692
693#[cfg(test)]
694mod tests {
695    use super::*;
696
697    #[test]
698    fn test_lut_is_sorted() {
699        // Verify the LUT is sorted (required for binary search)
700        for i in 1..DISCRIMINATOR_LUT.len() {
701            assert!(
702                DISCRIMINATOR_LUT[i - 1].discriminator < DISCRIMINATOR_LUT[i].discriminator,
703                "LUT not sorted at index {}: {:x} >= {:x}",
704                i,
705                DISCRIMINATOR_LUT[i - 1].discriminator,
706                DISCRIMINATOR_LUT[i].discriminator
707            );
708        }
709    }
710
711    #[test]
712    fn test_discriminator_lookup() {
713        // PumpFun Create
714        let disc = 0x7663EBDE4DA91B1B;
715        let info = lookup_discriminator(disc).unwrap();
716        assert_eq!(info.name, "PumpFun Create");
717        assert_eq!(info.protocol, Protocol::PumpFun);
718
719        // Raydium CLMM Swap
720        let disc = 0xE2710826E8CDC640;
721        let info = lookup_discriminator(disc).unwrap();
722        assert_eq!(info.name, "Raydium CLMM Swap");
723        assert_eq!(info.protocol, Protocol::RaydiumClmm);
724
725        // Unknown discriminator
726        let disc = 0xFFFFFFFFFFFFFFFF;
727        assert!(lookup_discriminator(disc).is_none());
728    }
729
730    #[test]
731    fn test_event_name_lookup() {
732        // PumpSwap Buy
733        let disc = 0x7777F52C1F52F467;
734        assert_eq!(discriminator_to_name(disc), Some("PumpSwap Buy"));
735
736        // Raydium AMM Swap Base In
737        let disc = 0x0900000000000000;
738        assert_eq!(discriminator_to_name(disc), Some("Raydium AMM Swap Base In"));
739    }
740
741    #[test]
742    fn test_protocol_lookup() {
743        assert_eq!(discriminator_to_protocol(0x7663EBDE4DA91B1B), Some(Protocol::PumpFun));
744        assert_eq!(discriminator_to_protocol(0xE2710826E8CDC640), Some(Protocol::RaydiumClmm));
745        assert_eq!(discriminator_to_protocol(0x96A02B93AF49CAE1), Some(Protocol::OrcaWhirlpool));
746    }
747}
748
749fn parse_pumpfun_post_complete_buy(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
750    crate::logs::pump_upgrade::parse(18146529233607700591, data, metadata, None)
751}
752
753fn parse_pumpfun_sweep_bonding_curve_fee(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
754    crate::logs::pump_upgrade::parse(3118876958563052404, data, metadata, None)
755}
756
757fn parse_pumpfun_complete(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
758    crate::logs::pump_upgrade::parse(619296439455019615, data, metadata, None)
759}
760
761fn parse_pumpswap_sweep_pool_fee(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
762    crate::logs::pump_upgrade::parse(11927646055507993730, data, metadata, None)
763}