Skip to main content

sol_parser_sdk/logs/
pump.rs

1//! PumpFun 极限优化解析器 - 微秒/纳秒级性能
2//!
3//! 优化策略:
4//! - 零拷贝解析 (zero-copy)
5//! - 栈分配替代堆分配
6//! - unsafe 消除边界检查
7//! - 编译器自动向量化 (target-cpu=native)
8//! - 内联所有热路径
9//! - 编译时计算
10//! - 内存预取 (CPU cache optimization)
11
12use crate::core::events::*;
13use memchr::memmem;
14use once_cell::sync::Lazy;
15use solana_sdk::{pubkey::Pubkey, signature::Signature};
16
17#[cfg(feature = "perf-stats")]
18use std::sync::atomic::{AtomicUsize, Ordering};
19
20// ============================================================================
21// 性能计数器 (可选,用于性能分析)
22// ============================================================================
23
24#[cfg(feature = "perf-stats")]
25pub static PARSE_COUNT: AtomicUsize = AtomicUsize::new(0);
26#[cfg(feature = "perf-stats")]
27pub static PARSE_TIME_NS: AtomicUsize = AtomicUsize::new(0);
28
29// ============================================================================
30// 编译时常量和查找表
31// ============================================================================
32
33/// PumpFun discriminator 常量 (编译时计算)
34pub mod discriminators {
35    pub const CREATE_EVENT: u64 = u64::from_le_bytes([27, 114, 169, 77, 222, 235, 99, 118]);
36    pub const TRADE_EVENT: u64 = u64::from_le_bytes([189, 219, 127, 211, 78, 230, 97, 238]);
37    pub const MIGRATE_EVENT: u64 = u64::from_le_bytes([189, 233, 93, 185, 92, 148, 234, 148]);
38}
39
40/// Base64 查找表预计算 (用于快速解码)
41static BASE64_FINDER: Lazy<memmem::Finder> = Lazy::new(|| memmem::Finder::new(b"Program data: "));
42
43// ============================================================================
44// 零拷贝解析核心 - 使用栈分配
45// ============================================================================
46
47/// 零拷贝提取 program data (栈分配,无堆分配)
48///
49/// 优化: 使用固定大小栈缓冲区,避免 Vec 分配
50/// 缓冲区大小增加到 2KB 以防止 base64-simd 缓冲区溢出panic
51#[inline(always)]
52fn extract_program_data_zero_copy<'a>(log: &'a str, buf: &'a mut [u8; 2048]) -> Option<&'a [u8]> {
53    let log_bytes = log.as_bytes();
54    let pos = BASE64_FINDER.find(log_bytes)?;
55
56    let data_part = &log[pos + 14..];
57    let trimmed = data_part.trim();
58
59    // Validate input size before decoding (base64: 4 chars -> 3 bytes, so max input = (2048/3)*4 = ~2730 chars)
60    // Add safety margin to prevent base64-simd assertion failures
61    if trimmed.len() > 2700 {
62        return None;
63    }
64
65    // SIMD-accelerated base64 decoding (AVX2/SSE4/NEON)
66    use base64_simd::AsOut;
67    let decoded_slice = base64_simd::STANDARD
68        .decode(trimmed.as_bytes(), buf.as_mut().as_out())
69        .ok()?;
70
71    Some(decoded_slice)
72}
73
74/// 快速 discriminator 提取 (SIMD 优化)
75#[inline(always)]
76fn extract_discriminator_simd(log: &str) -> Option<u64> {
77    let log_bytes = log.as_bytes();
78    let pos = BASE64_FINDER.find(log_bytes)?;
79
80    let data_part = &log[pos + 14..];
81    let trimmed = data_part.trim();
82
83    if trimmed.len() < 12 {
84        return None;
85    }
86
87    // 只解码前16字节以获取 discriminator (SIMD-accelerated)
88    use base64_simd::AsOut;
89    let mut buf = [0u8; 12];
90    base64_simd::STANDARD
91        .decode(&trimmed.as_bytes()[..16], buf.as_mut().as_out())
92        .ok()?;
93
94    // 使用 unsafe 读取 u64 (零拷贝,无边界检查)
95    unsafe {
96        let ptr = buf.as_ptr() as *const u64;
97        Some(ptr.read_unaligned())
98    }
99}
100
101// ============================================================================
102// Unsafe 读取函数 - 消除边界检查
103// ============================================================================
104
105/// 读取 u64 (unsafe, 无边界检查)
106#[inline(always)]
107unsafe fn read_u64_unchecked(data: &[u8], offset: usize) -> u64 {
108    let ptr = data.as_ptr().add(offset) as *const u64;
109    u64::from_le(ptr.read_unaligned())
110}
111
112/// 读取 i64 (unsafe, 无边界检查)
113#[inline(always)]
114unsafe fn read_i64_unchecked(data: &[u8], offset: usize) -> i64 {
115    let ptr = data.as_ptr().add(offset) as *const i64;
116    i64::from_le(ptr.read_unaligned())
117}
118
119/// 读取 bool (unsafe, 无边界检查)
120#[inline(always)]
121unsafe fn read_bool_unchecked(data: &[u8], offset: usize) -> bool {
122    *data.get_unchecked(offset) == 1
123}
124
125/// 读取 Pubkey (unsafe, 无边界检查)
126///
127/// 优化: 添加内存预取,假设连续读取多个 Pubkey
128#[inline(always)]
129unsafe fn read_pubkey_unchecked(data: &[u8], offset: usize) -> Pubkey {
130    // 预取下一个可能的 Pubkey 位置 (假设连续读取)
131    // 使用 T0 提示 (最高优先级) 将数据预取到 L1 cache
132    #[cfg(target_arch = "x86_64")]
133    {
134        use std::arch::x86_64::_mm_prefetch;
135        use std::arch::x86_64::_MM_HINT_T0;
136        if offset + 64 < data.len() {
137            _mm_prefetch((data.as_ptr().add(offset + 32)) as *const i8, _MM_HINT_T0);
138        }
139    }
140
141    let ptr = data.as_ptr().add(offset);
142    let mut bytes = [0u8; 32];
143    std::ptr::copy_nonoverlapping(ptr, bytes.as_mut_ptr(), 32);
144    Pubkey::new_from_array(bytes)
145}
146
147/// 读取 u32 长度前缀的字符串 (零拷贝,返回 &str)
148///
149/// 优化: 直接返回 &str,避免 String 分配
150#[inline(always)]
151unsafe fn read_str_unchecked(data: &[u8], offset: usize) -> Option<(&str, usize)> {
152    if data.len() < offset + 4 {
153        return None;
154    }
155
156    let len = read_u32_unchecked(data, offset) as usize;
157    if data.len() < offset + 4 + len {
158        return None;
159    }
160
161    let string_bytes = &data[offset + 4..offset + 4 + len];
162    let s = std::str::from_utf8_unchecked(string_bytes);
163    Some((s, 4 + len))
164}
165
166/// 读取 u32 (unsafe, 无边界检查)
167#[inline(always)]
168unsafe fn read_u32_unchecked(data: &[u8], offset: usize) -> u32 {
169    let ptr = data.as_ptr().add(offset) as *const u32;
170    u32::from_le(ptr.read_unaligned())
171}
172
173// ============================================================================
174// 极限优化的事件解析函数
175// ============================================================================
176
177/// 主解析函数 (极限优化版本)
178///
179/// 性能目标: <100ns
180#[inline(always)]
181pub fn parse_log(
182    log: &str,
183    signature: Signature,
184    slot: u64,
185    tx_index: u64,
186    block_time_us: Option<i64>,
187    grpc_recv_us: i64,
188    is_created_buy: bool,
189) -> Option<DexEvent> {
190    #[cfg(feature = "perf-stats")]
191    let start = std::time::Instant::now();
192
193    // 使用栈分配的缓冲区 (增加到 2KB 以防止 base64-simd 缓冲区溢出)
194    let mut buf = [0u8; 2048];
195    let program_data = extract_program_data_zero_copy(log, &mut buf)?;
196
197    if program_data.len() < 8 {
198        return None;
199    }
200
201    // 使用 unsafe 读取 discriminator (SIMD 优化)
202    let discriminator = unsafe { read_u64_unchecked(program_data, 0) };
203    let data = &program_data[8..];
204
205    let result = match discriminator {
206        discriminators::CREATE_EVENT => {
207            parse_create_event_optimized(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
208        }
209        discriminators::TRADE_EVENT => {
210            parse_trade_event_optimized(data, signature, slot, tx_index, block_time_us, grpc_recv_us, is_created_buy)
211        }
212        discriminators::MIGRATE_EVENT => {
213            parse_migrate_event_optimized(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
214        }
215        _ => None,
216    };
217
218    #[cfg(feature = "perf-stats")]
219    {
220        PARSE_COUNT.fetch_add(1, Ordering::Relaxed);
221        PARSE_TIME_NS.fetch_add(start.elapsed().as_nanos() as usize, Ordering::Relaxed);
222    }
223
224    result
225}
226
227/// 解析 CreateEvent (极限优化)
228///
229/// 优化:
230/// - 使用 unsafe 消除所有边界检查
231/// - 零拷贝字符串解析
232/// - 内联所有调用
233#[inline(always)]
234fn parse_create_event_optimized(
235    data: &[u8],
236    signature: Signature,
237    slot: u64,
238    tx_index: u64,
239    block_time_us: Option<i64>,
240    grpc_recv_us: i64,
241) -> Option<DexEvent> {
242    unsafe {
243        let mut offset = 0;
244
245        // 读取字符串字段 (零拷贝)
246        let (name, name_len) = read_str_unchecked(data, offset)?;
247        offset += name_len;
248
249        let (symbol, symbol_len) = read_str_unchecked(data, offset)?;
250        offset += symbol_len;
251
252        let (uri, uri_len) = read_str_unchecked(data, offset)?;
253        offset += uri_len;
254
255        // 快速边界检查
256        if data.len() < offset + 32 + 32 + 32 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 1 {
257            return None;
258        }
259
260        // 读取 Pubkey 字段
261        let mint = read_pubkey_unchecked(data, offset);
262        offset += 32;
263
264        let bonding_curve = read_pubkey_unchecked(data, offset);
265        offset += 32;
266
267        let user = read_pubkey_unchecked(data, offset);
268        offset += 32;
269
270        let creator = read_pubkey_unchecked(data, offset);
271        offset += 32;
272
273        // 读取数值字段
274        let timestamp = read_i64_unchecked(data, offset);
275        offset += 8;
276
277        let virtual_token_reserves = read_u64_unchecked(data, offset);
278        offset += 8;
279
280        let virtual_sol_reserves = read_u64_unchecked(data, offset);
281        offset += 8;
282
283        let real_token_reserves = read_u64_unchecked(data, offset);
284        offset += 8;
285
286        let token_total_supply = read_u64_unchecked(data, offset);
287        offset += 8;
288
289        let token_program = if offset + 32 <= data.len() {
290            read_pubkey_unchecked(data, offset)
291        } else {
292            Pubkey::default()
293        };
294        offset += 32;
295
296        let is_mayhem_mode = if offset < data.len() {
297            read_bool_unchecked(data, offset)
298        } else {
299            false
300        };
301        offset += 1;
302        let is_cashback_enabled = if offset < data.len() {
303            read_bool_unchecked(data, offset)
304        } else {
305            false
306        };
307
308        let metadata = EventMetadata {
309            signature,
310            slot,
311            tx_index,
312            block_time_us: block_time_us.unwrap_or(0),
313            grpc_recv_us,
314        };
315
316        // 将 &str 转换为 String (这是唯一的堆分配)
317        // 优化: 可以考虑使用 SmallString 或 Cow<'static, str> 进一步优化
318        Some(DexEvent::PumpFunCreate(PumpFunCreateTokenEvent {
319            metadata,
320            name: name.to_string(),
321            symbol: symbol.to_string(),
322            uri: uri.to_string(),
323            mint,
324            bonding_curve,
325            user,
326            creator,
327            timestamp,
328            virtual_token_reserves,
329            virtual_sol_reserves,
330            real_token_reserves,
331            token_total_supply,
332            token_program,
333            is_mayhem_mode,
334            is_cashback_enabled,
335        }))
336    }
337}
338
339/// 解析 TradeEvent (极限优化)
340///
341/// 根据 ix_name 返回不同的事件类型:
342/// - "buy" -> DexEvent::PumpFunBuy
343/// - "sell" -> DexEvent::PumpFunSell
344/// - "buy_exact_sol_in" -> DexEvent::PumpFunBuyExactSolIn
345/// - 其他/空 -> DexEvent::PumpFunTrade (兼容旧版本)
346#[inline(always)]
347fn parse_trade_event_optimized(
348    data: &[u8],
349    signature: Signature,
350    slot: u64,
351    tx_index: u64,
352    block_time_us: Option<i64>,
353    grpc_recv_us: i64,
354    is_created_buy: bool,
355) -> Option<DexEvent> {
356    unsafe {
357        // 快速边界检查
358        if data.len() < 32 + 8 + 8 + 1 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 8 + 8 + 32 + 8 + 8 {
359            return None;
360        }
361
362        let mut offset = 0;
363
364        let mint = read_pubkey_unchecked(data, offset);
365        offset += 32;
366
367        let sol_amount = read_u64_unchecked(data, offset);
368        offset += 8;
369
370        let token_amount = read_u64_unchecked(data, offset);
371        offset += 8;
372
373        let is_buy = read_bool_unchecked(data, offset);
374        offset += 1;
375
376        let user = read_pubkey_unchecked(data, offset);
377        offset += 32;
378
379        let timestamp = read_i64_unchecked(data, offset);
380        offset += 8;
381
382        let virtual_sol_reserves = read_u64_unchecked(data, offset);
383        offset += 8;
384
385        let virtual_token_reserves = read_u64_unchecked(data, offset);
386        offset += 8;
387
388        let real_sol_reserves = read_u64_unchecked(data, offset);
389        offset += 8;
390
391        let real_token_reserves = read_u64_unchecked(data, offset);
392        offset += 8;
393
394        let fee_recipient = read_pubkey_unchecked(data, offset);
395        offset += 32;
396
397        let fee_basis_points = read_u64_unchecked(data, offset);
398        offset += 8;
399
400        let fee = read_u64_unchecked(data, offset);
401        offset += 8;
402
403        let creator = read_pubkey_unchecked(data, offset);
404        offset += 32;
405
406        let creator_fee_basis_points = read_u64_unchecked(data, offset);
407        offset += 8;
408
409        let creator_fee = read_u64_unchecked(data, offset);
410        offset += 8;
411
412        // 可选字段
413        let track_volume = if offset < data.len() {
414            read_bool_unchecked(data, offset)
415        } else {
416            false
417        };
418        offset += 1;
419
420        let total_unclaimed_tokens = if offset + 8 <= data.len() {
421            read_u64_unchecked(data, offset)
422        } else {
423            0
424        };
425        offset += 8;
426
427        let total_claimed_tokens = if offset + 8 <= data.len() {
428            read_u64_unchecked(data, offset)
429        } else {
430            0
431        };
432        offset += 8;
433
434        let current_sol_volume = if offset + 8 <= data.len() {
435            read_u64_unchecked(data, offset)
436        } else {
437            0
438        };
439        offset += 8;
440
441        let last_update_timestamp = if offset + 8 <= data.len() {
442            read_i64_unchecked(data, offset)
443        } else {
444            0
445        };
446        offset += 8;
447
448        // ix_name: String (4-byte length prefix + content)
449        // Values: "buy" | "sell" | "buy_exact_sol_in"
450        let ix_name = if offset + 4 <= data.len() {
451            if let Some((s, len)) = read_str_unchecked(data, offset) {
452                offset += len;
453                s.to_string()
454            } else {
455                String::new()
456            }
457        } else {
458            String::new()
459        };
460
461        // mayhem_mode: bool (1 byte), cashback_fee_basis_points (8), cashback (8) - PUMP_CASHBACK_README
462        let mayhem_mode = if offset < data.len() {
463            read_bool_unchecked(data, offset)
464        } else {
465            false
466        };
467        offset += 1;
468        let cashback_fee_basis_points = if offset + 8 <= data.len() {
469            read_u64_unchecked(data, offset)
470        } else {
471            0
472        };
473        offset += 8;
474        let cashback = if offset + 8 <= data.len() {
475            read_u64_unchecked(data, offset)
476        } else {
477            0
478        };
479
480        let metadata = EventMetadata {
481            signature,
482            slot,
483            tx_index,
484            block_time_us: block_time_us.unwrap_or(0),
485            grpc_recv_us,
486        };
487
488        let trade_event = PumpFunTradeEvent {
489            metadata,
490            mint,
491            sol_amount,
492            token_amount,
493            is_buy,
494            is_created_buy,
495            user,
496            timestamp,
497            virtual_sol_reserves,
498            virtual_token_reserves,
499            real_sol_reserves,
500            real_token_reserves,
501            fee_recipient,
502            fee_basis_points,
503            fee,
504            creator,
505            creator_fee_basis_points,
506            creator_fee,
507            track_volume,
508            total_unclaimed_tokens,
509            total_claimed_tokens,
510            current_sol_volume,
511            last_update_timestamp,
512            ix_name: ix_name.clone(),
513            mayhem_mode,
514            cashback_fee_basis_points,
515            cashback,
516            is_cashback_coin: cashback_fee_basis_points > 0,
517            bonding_curve: Pubkey::default(),
518            associated_bonding_curve: Pubkey::default(),
519            creator_vault: Pubkey::default(),
520            token_program: Pubkey::default(),
521        };
522
523        // 根据 ix_name 返回不同的事件类型,支持用户过滤特定交易类型
524        match ix_name.as_str() {
525            "buy" => Some(DexEvent::PumpFunBuy(trade_event)),
526            "sell" => Some(DexEvent::PumpFunSell(trade_event)),
527            "buy_exact_sol_in" => Some(DexEvent::PumpFunBuyExactSolIn(trade_event)),
528            _ => Some(DexEvent::PumpFunTrade(trade_event)), // 兼容旧版本或未知类型
529        }
530    }
531}
532
533/// 解析 MigrateEvent (极限优化)
534#[inline(always)]
535fn parse_migrate_event_optimized(
536    data: &[u8],
537    signature: Signature,
538    slot: u64,
539    tx_index: u64,
540    block_time_us: Option<i64>,
541    grpc_recv_us: i64,
542) -> Option<DexEvent> {
543    unsafe {
544        // 快速边界检查
545        if data.len() < 32 + 32 + 8 + 8 + 8 + 32 + 8 + 32 {
546            return None;
547        }
548
549        let mut offset = 0;
550
551        let user = read_pubkey_unchecked(data, offset);
552        offset += 32;
553
554        let mint = read_pubkey_unchecked(data, offset);
555        offset += 32;
556
557        let mint_amount = read_u64_unchecked(data, offset);
558        offset += 8;
559
560        let sol_amount = read_u64_unchecked(data, offset);
561        offset += 8;
562
563        let pool_migration_fee = read_u64_unchecked(data, offset);
564        offset += 8;
565
566        let bonding_curve = read_pubkey_unchecked(data, offset);
567        offset += 32;
568
569        let timestamp = read_i64_unchecked(data, offset);
570        offset += 8;
571
572        let pool = read_pubkey_unchecked(data, offset);
573
574        let metadata = EventMetadata {
575            signature,
576            slot,
577            tx_index,
578            block_time_us: block_time_us.unwrap_or(0),
579            grpc_recv_us,
580        };
581
582        Some(DexEvent::PumpFunMigrate(PumpFunMigrateEvent {
583            metadata,
584            user,
585            mint,
586            mint_amount,
587            sol_amount,
588            pool_migration_fee,
589            bonding_curve,
590            timestamp,
591            pool,
592        }))
593    }
594}
595
596// ============================================================================
597// 快速过滤 API (用于事件过滤场景)
598// ============================================================================
599
600/// 快速判断事件类型 (只解析 discriminator)
601///
602/// 性能: <50ns
603#[inline(always)]
604pub fn get_event_type_fast(log: &str) -> Option<u64> {
605    extract_discriminator_simd(log)
606}
607
608/// 检查是否为特定事件类型 (SIMD 优化)
609#[inline(always)]
610pub fn is_event_type(log: &str, discriminator: u64) -> bool {
611    extract_discriminator_simd(log) == Some(discriminator)
612}
613
614// ============================================================================
615// Public API for optimized parsing from pre-decoded data
616// These functions accept already-decoded data (without discriminator)
617// ============================================================================
618
619/// Parse PumpFun Trade event from pre-decoded data
620/// 
621/// `data` should be the decoded bytes AFTER the 8-byte discriminator
622/// 
623/// Returns different event types based on ix_name:
624/// - "buy" -> DexEvent::PumpFunBuy
625/// - "sell" -> DexEvent::PumpFunSell
626/// - "buy_exact_sol_in" -> DexEvent::PumpFunBuyExactSolIn
627/// - other/empty -> DexEvent::PumpFunTrade (backward compatible)
628#[inline(always)]
629pub fn parse_trade_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
630    unsafe {
631        // 快速边界检查
632        if data.len() < 32 + 8 + 8 + 1 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 8 + 8 + 32 + 8 + 8 {
633            return None;
634        }
635
636        let mut offset = 0;
637
638        let mint = read_pubkey_unchecked(data, offset);
639        offset += 32;
640
641        let sol_amount = read_u64_unchecked(data, offset);
642        offset += 8;
643
644        let token_amount = read_u64_unchecked(data, offset);
645        offset += 8;
646
647        let is_buy = read_bool_unchecked(data, offset);
648        offset += 1;
649
650        let user = read_pubkey_unchecked(data, offset);
651        offset += 32;
652
653        let timestamp = read_i64_unchecked(data, offset);
654        offset += 8;
655
656        let virtual_sol_reserves = read_u64_unchecked(data, offset);
657        offset += 8;
658
659        let virtual_token_reserves = read_u64_unchecked(data, offset);
660        offset += 8;
661
662        let real_sol_reserves = read_u64_unchecked(data, offset);
663        offset += 8;
664
665        let real_token_reserves = read_u64_unchecked(data, offset);
666        offset += 8;
667
668        let fee_recipient = read_pubkey_unchecked(data, offset);
669        offset += 32;
670
671        let fee_basis_points = read_u64_unchecked(data, offset);
672        offset += 8;
673
674        let fee = read_u64_unchecked(data, offset);
675        offset += 8;
676
677        let creator = read_pubkey_unchecked(data, offset);
678        offset += 32;
679
680        let creator_fee_basis_points = read_u64_unchecked(data, offset);
681        offset += 8;
682
683        let creator_fee = read_u64_unchecked(data, offset);
684        offset += 8;
685
686        // 可选字段
687        let track_volume = if offset < data.len() {
688            read_bool_unchecked(data, offset)
689        } else {
690            false
691        };
692        offset += 1;
693
694        let total_unclaimed_tokens = if offset + 8 <= data.len() {
695            read_u64_unchecked(data, offset)
696        } else {
697            0
698        };
699        offset += 8;
700
701        let total_claimed_tokens = if offset + 8 <= data.len() {
702            read_u64_unchecked(data, offset)
703        } else {
704            0
705        };
706        offset += 8;
707
708        let current_sol_volume = if offset + 8 <= data.len() {
709            read_u64_unchecked(data, offset)
710        } else {
711            0
712        };
713        offset += 8;
714
715        let last_update_timestamp = if offset + 8 <= data.len() {
716            read_i64_unchecked(data, offset)
717        } else {
718            0
719        };
720        offset += 8;
721
722        let ix_name = if offset + 4 <= data.len() {
723            if let Some((s, len)) = read_str_unchecked(data, offset) {
724                offset += len;
725                s.to_string()
726            } else {
727                String::new()
728            }
729        } else {
730            String::new()
731        };
732
733        // mayhem_mode (1), cashback_fee_basis_points (8), cashback (8) - PUMP_CASHBACK_README
734        let mayhem_mode = if offset < data.len() {
735            read_bool_unchecked(data, offset)
736        } else {
737            false
738        };
739        offset += 1;
740        let cashback_fee_basis_points = if offset + 8 <= data.len() {
741            read_u64_unchecked(data, offset)
742        } else {
743            0
744        };
745        offset += 8;
746        let cashback = if offset + 8 <= data.len() {
747            read_u64_unchecked(data, offset)
748        } else {
749            0
750        };
751
752        let trade_event = PumpFunTradeEvent {
753            metadata,
754            mint,
755            sol_amount,
756            token_amount,
757            is_buy,
758            is_created_buy,
759            user,
760            timestamp,
761            virtual_sol_reserves,
762            virtual_token_reserves,
763            real_sol_reserves,
764            real_token_reserves,
765            fee_recipient,
766            fee_basis_points,
767            fee,
768            creator,
769            creator_fee_basis_points,
770            creator_fee,
771            track_volume,
772            total_unclaimed_tokens,
773            total_claimed_tokens,
774            current_sol_volume,
775            last_update_timestamp,
776            ix_name: ix_name.clone(),
777            mayhem_mode,
778            cashback_fee_basis_points,
779            cashback,
780            is_cashback_coin: cashback_fee_basis_points > 0,
781            bonding_curve: Pubkey::default(),
782            associated_bonding_curve: Pubkey::default(),
783            creator_vault: Pubkey::default(),
784            token_program: Pubkey::default(),
785        };
786
787        // 根据 ix_name 返回不同的事件类型
788        match ix_name.as_str() {
789            "buy" => Some(DexEvent::PumpFunBuy(trade_event)),
790            "sell" => Some(DexEvent::PumpFunSell(trade_event)),
791            "buy_exact_sol_in" => Some(DexEvent::PumpFunBuyExactSolIn(trade_event)),
792            _ => Some(DexEvent::PumpFunTrade(trade_event)),
793        }
794    }
795}
796
797/// Parse only PumpFun Buy events from pre-decoded data
798/// 
799/// Returns None if the event is not a buy event
800#[inline(always)]
801pub fn parse_buy_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
802    let event = parse_trade_from_data(data, metadata, is_created_buy)?;
803    match &event {
804        DexEvent::PumpFunBuy(_) => Some(event),
805        _ => None,
806    }
807}
808
809/// Parse only PumpFun Sell events from pre-decoded data
810/// 
811/// Returns None if the event is not a sell event
812#[inline(always)]
813pub fn parse_sell_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
814    let event = parse_trade_from_data(data, metadata, is_created_buy)?;
815    match &event {
816        DexEvent::PumpFunSell(_) => Some(event),
817        _ => None,
818    }
819}
820
821/// Parse only PumpFun BuyExactSolIn events from pre-decoded data
822/// 
823/// Returns None if the event is not a buy_exact_sol_in event
824#[inline(always)]
825pub fn parse_buy_exact_sol_in_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
826    let event = parse_trade_from_data(data, metadata, is_created_buy)?;
827    match &event {
828        DexEvent::PumpFunBuyExactSolIn(_) => Some(event),
829        _ => None,
830    }
831}
832
833/// Parse PumpFun Create event from pre-decoded data
834#[inline(always)]
835pub fn parse_create_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
836    unsafe {
837        let mut offset = 0;
838
839        let (name, name_len) = read_str_unchecked(data, offset)?;
840        offset += name_len;
841
842        let (symbol, symbol_len) = read_str_unchecked(data, offset)?;
843        offset += symbol_len;
844
845        let (uri, uri_len) = read_str_unchecked(data, offset)?;
846        offset += uri_len;
847
848        if data.len() < offset + 32 + 32 + 32 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 1 {
849            return None;
850        }
851
852        let mint = read_pubkey_unchecked(data, offset);
853        offset += 32;
854
855        let bonding_curve = read_pubkey_unchecked(data, offset);
856        offset += 32;
857
858        let user = read_pubkey_unchecked(data, offset);
859        offset += 32;
860
861        let creator = read_pubkey_unchecked(data, offset);
862        offset += 32;
863
864        let timestamp = read_i64_unchecked(data, offset);
865        offset += 8;
866
867        let virtual_token_reserves = read_u64_unchecked(data, offset);
868        offset += 8;
869
870        let virtual_sol_reserves = read_u64_unchecked(data, offset);
871        offset += 8;
872
873        let real_token_reserves = read_u64_unchecked(data, offset);
874        offset += 8;
875
876        let token_total_supply = read_u64_unchecked(data, offset);
877        offset += 8;
878
879        let token_program = if offset + 32 <= data.len() {
880            read_pubkey_unchecked(data, offset)
881        } else {
882            Pubkey::default()
883        };
884        offset += 32;
885
886        let is_mayhem_mode = if offset < data.len() {
887            read_bool_unchecked(data, offset)
888        } else {
889            false
890        };
891        offset += 1;
892        let is_cashback_enabled = if offset < data.len() {
893            read_bool_unchecked(data, offset)
894        } else {
895            false
896        };
897
898        Some(DexEvent::PumpFunCreate(PumpFunCreateTokenEvent {
899            metadata,
900            name: name.to_string(),
901            symbol: symbol.to_string(),
902            uri: uri.to_string(),
903            mint,
904            bonding_curve,
905            user,
906            creator,
907            timestamp,
908            virtual_token_reserves,
909            virtual_sol_reserves,
910            real_token_reserves,
911            token_total_supply,
912            token_program,
913            is_mayhem_mode,
914            is_cashback_enabled,
915        }))
916    }
917}
918
919/// Parse PumpFun Migrate event from pre-decoded data
920#[inline(always)]
921pub fn parse_migrate_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
922    unsafe {
923        if data.len() < 32 + 32 + 8 + 8 + 8 + 32 + 8 + 32 {
924            return None;
925        }
926
927        let mut offset = 0;
928
929        let user = read_pubkey_unchecked(data, offset);
930        offset += 32;
931
932        let mint = read_pubkey_unchecked(data, offset);
933        offset += 32;
934
935        let mint_amount = read_u64_unchecked(data, offset);
936        offset += 8;
937
938        let sol_amount = read_u64_unchecked(data, offset);
939        offset += 8;
940
941        let pool_migration_fee = read_u64_unchecked(data, offset);
942        offset += 8;
943
944        let bonding_curve = read_pubkey_unchecked(data, offset);
945        offset += 32;
946
947        let timestamp = read_i64_unchecked(data, offset);
948        offset += 8;
949
950        let pool = read_pubkey_unchecked(data, offset);
951
952        Some(DexEvent::PumpFunMigrate(PumpFunMigrateEvent {
953            metadata,
954            user,
955            mint,
956            mint_amount,
957            sol_amount,
958            pool_migration_fee,
959            bonding_curve,
960            timestamp,
961            pool,
962        }))
963    }
964}
965
966// ============================================================================
967// 性能统计 API (可选)
968// ============================================================================
969
970#[cfg(feature = "perf-stats")]
971pub fn get_perf_stats() -> (usize, usize) {
972    let count = PARSE_COUNT.load(Ordering::Relaxed);
973    let total_ns = PARSE_TIME_NS.load(Ordering::Relaxed);
974    (count, total_ns)
975}
976
977#[cfg(feature = "perf-stats")]
978pub fn reset_perf_stats() {
979    PARSE_COUNT.store(0, Ordering::Relaxed);
980    PARSE_TIME_NS.store(0, Ordering::Relaxed);
981}
982
983#[cfg(test)]
984mod tests {
985    use super::*;
986
987    #[test]
988    fn test_discriminator_simd() {
989        // 测试 SIMD discriminator 提取
990        let log = "Program data: G3Kp5Dfe605nAAAAAAAAAAA=";
991        let disc = extract_discriminator_simd(log);
992        assert!(disc.is_some());
993    }
994
995    #[test]
996    fn test_parse_performance() {
997        // 性能测试
998        let log = "Program data: G3Kp5Dfe605nAAAAAAAAAAA=";
999        let sig = Signature::default();
1000
1001        let start = std::time::Instant::now();
1002        for _ in 0..1000 {
1003            let _ = parse_log(log, sig, 0, 0, Some(0), 0, false);
1004        }
1005        let elapsed = start.elapsed();
1006
1007        println!("Average parse time: {} ns", elapsed.as_nanos() / 1000);
1008    }
1009}