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            recent_blockhash: None,
315        };
316
317        // 将 &str 转换为 String (这是唯一的堆分配)
318        // 优化: 可以考虑使用 SmallString 或 Cow<'static, str> 进一步优化
319        Some(DexEvent::PumpFunCreate(PumpFunCreateTokenEvent {
320            metadata,
321            name: name.to_string(),
322            symbol: symbol.to_string(),
323            uri: uri.to_string(),
324            mint,
325            bonding_curve,
326            user,
327            creator,
328            timestamp,
329            virtual_token_reserves,
330            virtual_sol_reserves,
331            real_token_reserves,
332            token_total_supply,
333            token_program,
334            is_mayhem_mode,
335            is_cashback_enabled,
336        }))
337    }
338}
339
340/// 解析 TradeEvent (极限优化)
341///
342/// 根据 ix_name 返回不同的事件类型:
343/// - "buy" -> DexEvent::PumpFunBuy
344/// - "sell" -> DexEvent::PumpFunSell
345/// - "buy_exact_sol_in" -> DexEvent::PumpFunBuyExactSolIn
346/// - 其他/空 -> DexEvent::PumpFunTrade (兼容旧版本)
347#[inline(always)]
348fn parse_trade_event_optimized(
349    data: &[u8],
350    signature: Signature,
351    slot: u64,
352    tx_index: u64,
353    block_time_us: Option<i64>,
354    grpc_recv_us: i64,
355    is_created_buy: bool,
356) -> Option<DexEvent> {
357    unsafe {
358        // 快速边界检查
359        if data.len() < 32 + 8 + 8 + 1 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 8 + 8 + 32 + 8 + 8 {
360            return None;
361        }
362
363        let mut offset = 0;
364
365        let mint = read_pubkey_unchecked(data, offset);
366        offset += 32;
367
368        let sol_amount = read_u64_unchecked(data, offset);
369        offset += 8;
370
371        let token_amount = read_u64_unchecked(data, offset);
372        offset += 8;
373
374        let is_buy = read_bool_unchecked(data, offset);
375        offset += 1;
376
377        let user = read_pubkey_unchecked(data, offset);
378        offset += 32;
379
380        let timestamp = read_i64_unchecked(data, offset);
381        offset += 8;
382
383        let virtual_sol_reserves = read_u64_unchecked(data, offset);
384        offset += 8;
385
386        let virtual_token_reserves = read_u64_unchecked(data, offset);
387        offset += 8;
388
389        let real_sol_reserves = read_u64_unchecked(data, offset);
390        offset += 8;
391
392        let real_token_reserves = read_u64_unchecked(data, offset);
393        offset += 8;
394
395        let fee_recipient = read_pubkey_unchecked(data, offset);
396        offset += 32;
397
398        let fee_basis_points = read_u64_unchecked(data, offset);
399        offset += 8;
400
401        let fee = read_u64_unchecked(data, offset);
402        offset += 8;
403
404        let creator = read_pubkey_unchecked(data, offset);
405        offset += 32;
406
407        let creator_fee_basis_points = read_u64_unchecked(data, offset);
408        offset += 8;
409
410        let creator_fee = read_u64_unchecked(data, offset);
411        offset += 8;
412
413        // 可选字段
414        let track_volume = if offset < data.len() {
415            read_bool_unchecked(data, offset)
416        } else {
417            false
418        };
419        offset += 1;
420
421        let total_unclaimed_tokens = if offset + 8 <= data.len() {
422            read_u64_unchecked(data, offset)
423        } else {
424            0
425        };
426        offset += 8;
427
428        let total_claimed_tokens = if offset + 8 <= data.len() {
429            read_u64_unchecked(data, offset)
430        } else {
431            0
432        };
433        offset += 8;
434
435        let current_sol_volume = if offset + 8 <= data.len() {
436            read_u64_unchecked(data, offset)
437        } else {
438            0
439        };
440        offset += 8;
441
442        let last_update_timestamp = if offset + 8 <= data.len() {
443            read_i64_unchecked(data, offset)
444        } else {
445            0
446        };
447        offset += 8;
448
449        // ix_name: String (4-byte length prefix + content)
450        // Values: "buy" | "sell" | "buy_exact_sol_in"
451        let ix_name = if offset + 4 <= data.len() {
452            if let Some((s, len)) = read_str_unchecked(data, offset) {
453                offset += len;
454                s.to_string()
455            } else {
456                String::new()
457            }
458        } else {
459            String::new()
460        };
461
462        // mayhem_mode: bool (1 byte), cashback_fee_basis_points (8), cashback (8) - PUMP_CASHBACK_README
463        let mayhem_mode = if offset < data.len() {
464            read_bool_unchecked(data, offset)
465        } else {
466            false
467        };
468        offset += 1;
469        let cashback_fee_basis_points = if offset + 8 <= data.len() {
470            read_u64_unchecked(data, offset)
471        } else {
472            0
473        };
474        offset += 8;
475        let cashback = if offset + 8 <= data.len() {
476            read_u64_unchecked(data, offset)
477        } else {
478            0
479        };
480
481        let metadata = EventMetadata {
482            signature,
483            slot,
484            tx_index,
485            block_time_us: block_time_us.unwrap_or(0),
486            grpc_recv_us,
487            recent_blockhash: None,
488        };
489
490        let trade_event = PumpFunTradeEvent {
491            metadata,
492            mint,
493            sol_amount,
494            token_amount,
495            is_buy,
496            is_created_buy,
497            user,
498            timestamp,
499            virtual_sol_reserves,
500            virtual_token_reserves,
501            real_sol_reserves,
502            real_token_reserves,
503            fee_recipient,
504            fee_basis_points,
505            fee,
506            creator,
507            creator_fee_basis_points,
508            creator_fee,
509            track_volume,
510            total_unclaimed_tokens,
511            total_claimed_tokens,
512            current_sol_volume,
513            last_update_timestamp,
514            ix_name: ix_name.clone(),
515            mayhem_mode,
516            cashback_fee_basis_points,
517            cashback,
518            is_cashback_coin: cashback_fee_basis_points > 0,
519            bonding_curve: Pubkey::default(),
520            associated_bonding_curve: Pubkey::default(),
521            creator_vault: Pubkey::default(),
522            token_program: Pubkey::default(),
523            account: None,
524        };
525
526        // 根据 ix_name 返回不同的事件类型,支持用户过滤特定交易类型
527        match ix_name.as_str() {
528            "buy" => Some(DexEvent::PumpFunBuy(trade_event)),
529            "sell" => Some(DexEvent::PumpFunSell(trade_event)),
530            "buy_exact_sol_in" => Some(DexEvent::PumpFunBuyExactSolIn(trade_event)),
531            _ => Some(DexEvent::PumpFunTrade(trade_event)), // 兼容旧版本或未知类型
532        }
533    }
534}
535
536/// 解析 MigrateEvent (极限优化)
537#[inline(always)]
538fn parse_migrate_event_optimized(
539    data: &[u8],
540    signature: Signature,
541    slot: u64,
542    tx_index: u64,
543    block_time_us: Option<i64>,
544    grpc_recv_us: i64,
545) -> Option<DexEvent> {
546    unsafe {
547        // 快速边界检查
548        if data.len() < 32 + 32 + 8 + 8 + 8 + 32 + 8 + 32 {
549            return None;
550        }
551
552        let mut offset = 0;
553
554        let user = read_pubkey_unchecked(data, offset);
555        offset += 32;
556
557        let mint = read_pubkey_unchecked(data, offset);
558        offset += 32;
559
560        let mint_amount = read_u64_unchecked(data, offset);
561        offset += 8;
562
563        let sol_amount = read_u64_unchecked(data, offset);
564        offset += 8;
565
566        let pool_migration_fee = read_u64_unchecked(data, offset);
567        offset += 8;
568
569        let bonding_curve = read_pubkey_unchecked(data, offset);
570        offset += 32;
571
572        let timestamp = read_i64_unchecked(data, offset);
573        offset += 8;
574
575        let pool = read_pubkey_unchecked(data, offset);
576
577        let metadata = EventMetadata {
578            signature,
579            slot,
580            tx_index,
581            block_time_us: block_time_us.unwrap_or(0),
582            grpc_recv_us,
583            recent_blockhash: None,
584        };
585
586        Some(DexEvent::PumpFunMigrate(PumpFunMigrateEvent {
587            metadata,
588            user,
589            mint,
590            mint_amount,
591            sol_amount,
592            pool_migration_fee,
593            bonding_curve,
594            timestamp,
595            pool,
596        }))
597    }
598}
599
600// ============================================================================
601// 快速过滤 API (用于事件过滤场景)
602// ============================================================================
603
604/// 快速判断事件类型 (只解析 discriminator)
605///
606/// 性能: <50ns
607#[inline(always)]
608pub fn get_event_type_fast(log: &str) -> Option<u64> {
609    extract_discriminator_simd(log)
610}
611
612/// 检查是否为特定事件类型 (SIMD 优化)
613#[inline(always)]
614pub fn is_event_type(log: &str, discriminator: u64) -> bool {
615    extract_discriminator_simd(log) == Some(discriminator)
616}
617
618// ============================================================================
619// Public API for optimized parsing from pre-decoded data
620// These functions accept already-decoded data (without discriminator)
621// ============================================================================
622
623/// Parse PumpFun Trade event from pre-decoded data
624/// 
625/// `data` should be the decoded bytes AFTER the 8-byte discriminator
626/// 
627/// Returns different event types based on ix_name:
628/// - "buy" -> DexEvent::PumpFunBuy
629/// - "sell" -> DexEvent::PumpFunSell
630/// - "buy_exact_sol_in" -> DexEvent::PumpFunBuyExactSolIn
631/// - other/empty -> DexEvent::PumpFunTrade (backward compatible)
632#[inline(always)]
633pub fn parse_trade_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
634    unsafe {
635        // 快速边界检查
636        if data.len() < 32 + 8 + 8 + 1 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 8 + 8 + 32 + 8 + 8 {
637            return None;
638        }
639
640        let mut offset = 0;
641
642        let mint = read_pubkey_unchecked(data, offset);
643        offset += 32;
644
645        let sol_amount = read_u64_unchecked(data, offset);
646        offset += 8;
647
648        let token_amount = read_u64_unchecked(data, offset);
649        offset += 8;
650
651        let is_buy = read_bool_unchecked(data, offset);
652        offset += 1;
653
654        let user = read_pubkey_unchecked(data, offset);
655        offset += 32;
656
657        let timestamp = read_i64_unchecked(data, offset);
658        offset += 8;
659
660        let virtual_sol_reserves = read_u64_unchecked(data, offset);
661        offset += 8;
662
663        let virtual_token_reserves = read_u64_unchecked(data, offset);
664        offset += 8;
665
666        let real_sol_reserves = read_u64_unchecked(data, offset);
667        offset += 8;
668
669        let real_token_reserves = read_u64_unchecked(data, offset);
670        offset += 8;
671
672        let fee_recipient = read_pubkey_unchecked(data, offset);
673        offset += 32;
674
675        let fee_basis_points = read_u64_unchecked(data, offset);
676        offset += 8;
677
678        let fee = read_u64_unchecked(data, offset);
679        offset += 8;
680
681        let creator = read_pubkey_unchecked(data, offset);
682        offset += 32;
683
684        let creator_fee_basis_points = read_u64_unchecked(data, offset);
685        offset += 8;
686
687        let creator_fee = read_u64_unchecked(data, offset);
688        offset += 8;
689
690        // 可选字段
691        let track_volume = if offset < data.len() {
692            read_bool_unchecked(data, offset)
693        } else {
694            false
695        };
696        offset += 1;
697
698        let total_unclaimed_tokens = if offset + 8 <= data.len() {
699            read_u64_unchecked(data, offset)
700        } else {
701            0
702        };
703        offset += 8;
704
705        let total_claimed_tokens = if offset + 8 <= data.len() {
706            read_u64_unchecked(data, offset)
707        } else {
708            0
709        };
710        offset += 8;
711
712        let current_sol_volume = if offset + 8 <= data.len() {
713            read_u64_unchecked(data, offset)
714        } else {
715            0
716        };
717        offset += 8;
718
719        let last_update_timestamp = if offset + 8 <= data.len() {
720            read_i64_unchecked(data, offset)
721        } else {
722            0
723        };
724        offset += 8;
725
726        let ix_name = if offset + 4 <= data.len() {
727            if let Some((s, len)) = read_str_unchecked(data, offset) {
728                offset += len;
729                s.to_string()
730            } else {
731                String::new()
732            }
733        } else {
734            String::new()
735        };
736
737        // mayhem_mode (1), cashback_fee_basis_points (8), cashback (8) - PUMP_CASHBACK_README
738        let mayhem_mode = if offset < data.len() {
739            read_bool_unchecked(data, offset)
740        } else {
741            false
742        };
743        offset += 1;
744        let cashback_fee_basis_points = if offset + 8 <= data.len() {
745            read_u64_unchecked(data, offset)
746        } else {
747            0
748        };
749        offset += 8;
750        let cashback = if offset + 8 <= data.len() {
751            read_u64_unchecked(data, offset)
752        } else {
753            0
754        };
755
756        let trade_event = PumpFunTradeEvent {
757            metadata,
758            mint,
759            sol_amount,
760            token_amount,
761            is_buy,
762            is_created_buy,
763            user,
764            timestamp,
765            virtual_sol_reserves,
766            virtual_token_reserves,
767            real_sol_reserves,
768            real_token_reserves,
769            fee_recipient,
770            fee_basis_points,
771            fee,
772            creator,
773            creator_fee_basis_points,
774            creator_fee,
775            track_volume,
776            total_unclaimed_tokens,
777            total_claimed_tokens,
778            current_sol_volume,
779            last_update_timestamp,
780            ix_name: ix_name.clone(),
781            mayhem_mode,
782            cashback_fee_basis_points,
783            cashback,
784            is_cashback_coin: cashback_fee_basis_points > 0,
785            bonding_curve: Pubkey::default(),
786            associated_bonding_curve: Pubkey::default(),
787            creator_vault: Pubkey::default(),
788            token_program: Pubkey::default(),
789            account: None,
790        };
791
792        // 根据 ix_name 返回不同的事件类型
793        match ix_name.as_str() {
794            "buy" => Some(DexEvent::PumpFunBuy(trade_event)),
795            "sell" => Some(DexEvent::PumpFunSell(trade_event)),
796            "buy_exact_sol_in" => Some(DexEvent::PumpFunBuyExactSolIn(trade_event)),
797            _ => Some(DexEvent::PumpFunTrade(trade_event)),
798        }
799    }
800}
801
802/// Parse only PumpFun Buy events from pre-decoded data
803/// 
804/// Returns None if the event is not a buy event
805#[inline(always)]
806pub fn parse_buy_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
807    let event = parse_trade_from_data(data, metadata, is_created_buy)?;
808    match &event {
809        DexEvent::PumpFunBuy(_) => Some(event),
810        _ => None,
811    }
812}
813
814/// Parse only PumpFun Sell events from pre-decoded data
815/// 
816/// Returns None if the event is not a sell event
817#[inline(always)]
818pub fn parse_sell_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
819    let event = parse_trade_from_data(data, metadata, is_created_buy)?;
820    match &event {
821        DexEvent::PumpFunSell(_) => Some(event),
822        _ => None,
823    }
824}
825
826/// Parse only PumpFun BuyExactSolIn events from pre-decoded data
827/// 
828/// Returns None if the event is not a buy_exact_sol_in event
829#[inline(always)]
830pub fn parse_buy_exact_sol_in_from_data(data: &[u8], metadata: EventMetadata, is_created_buy: bool) -> Option<DexEvent> {
831    let event = parse_trade_from_data(data, metadata, is_created_buy)?;
832    match &event {
833        DexEvent::PumpFunBuyExactSolIn(_) => Some(event),
834        _ => None,
835    }
836}
837
838/// Parse PumpFun Create event from pre-decoded data
839#[inline(always)]
840pub fn parse_create_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
841    unsafe {
842        let mut offset = 0;
843
844        let (name, name_len) = read_str_unchecked(data, offset)?;
845        offset += name_len;
846
847        let (symbol, symbol_len) = read_str_unchecked(data, offset)?;
848        offset += symbol_len;
849
850        let (uri, uri_len) = read_str_unchecked(data, offset)?;
851        offset += uri_len;
852
853        if data.len() < offset + 32 + 32 + 32 + 32 + 8 + 8 + 8 + 8 + 8 + 32 + 1 {
854            return None;
855        }
856
857        let mint = read_pubkey_unchecked(data, offset);
858        offset += 32;
859
860        let bonding_curve = read_pubkey_unchecked(data, offset);
861        offset += 32;
862
863        let user = read_pubkey_unchecked(data, offset);
864        offset += 32;
865
866        let creator = read_pubkey_unchecked(data, offset);
867        offset += 32;
868
869        let timestamp = read_i64_unchecked(data, offset);
870        offset += 8;
871
872        let virtual_token_reserves = read_u64_unchecked(data, offset);
873        offset += 8;
874
875        let virtual_sol_reserves = read_u64_unchecked(data, offset);
876        offset += 8;
877
878        let real_token_reserves = read_u64_unchecked(data, offset);
879        offset += 8;
880
881        let token_total_supply = read_u64_unchecked(data, offset);
882        offset += 8;
883
884        let token_program = if offset + 32 <= data.len() {
885            read_pubkey_unchecked(data, offset)
886        } else {
887            Pubkey::default()
888        };
889        offset += 32;
890
891        let is_mayhem_mode = if offset < data.len() {
892            read_bool_unchecked(data, offset)
893        } else {
894            false
895        };
896        offset += 1;
897        let is_cashback_enabled = if offset < data.len() {
898            read_bool_unchecked(data, offset)
899        } else {
900            false
901        };
902
903        Some(DexEvent::PumpFunCreate(PumpFunCreateTokenEvent {
904            metadata,
905            name: name.to_string(),
906            symbol: symbol.to_string(),
907            uri: uri.to_string(),
908            mint,
909            bonding_curve,
910            user,
911            creator,
912            timestamp,
913            virtual_token_reserves,
914            virtual_sol_reserves,
915            real_token_reserves,
916            token_total_supply,
917            token_program,
918            is_mayhem_mode,
919            is_cashback_enabled,
920        }))
921    }
922}
923
924/// Parse PumpFun Migrate event from pre-decoded data
925#[inline(always)]
926pub fn parse_migrate_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
927    unsafe {
928        if data.len() < 32 + 32 + 8 + 8 + 8 + 32 + 8 + 32 {
929            return None;
930        }
931
932        let mut offset = 0;
933
934        let user = read_pubkey_unchecked(data, offset);
935        offset += 32;
936
937        let mint = read_pubkey_unchecked(data, offset);
938        offset += 32;
939
940        let mint_amount = read_u64_unchecked(data, offset);
941        offset += 8;
942
943        let sol_amount = read_u64_unchecked(data, offset);
944        offset += 8;
945
946        let pool_migration_fee = read_u64_unchecked(data, offset);
947        offset += 8;
948
949        let bonding_curve = read_pubkey_unchecked(data, offset);
950        offset += 32;
951
952        let timestamp = read_i64_unchecked(data, offset);
953        offset += 8;
954
955        let pool = read_pubkey_unchecked(data, offset);
956
957        Some(DexEvent::PumpFunMigrate(PumpFunMigrateEvent {
958            metadata,
959            user,
960            mint,
961            mint_amount,
962            sol_amount,
963            pool_migration_fee,
964            bonding_curve,
965            timestamp,
966            pool,
967        }))
968    }
969}
970
971// ============================================================================
972// 性能统计 API (可选)
973// ============================================================================
974
975#[cfg(feature = "perf-stats")]
976pub fn get_perf_stats() -> (usize, usize) {
977    let count = PARSE_COUNT.load(Ordering::Relaxed);
978    let total_ns = PARSE_TIME_NS.load(Ordering::Relaxed);
979    (count, total_ns)
980}
981
982#[cfg(feature = "perf-stats")]
983pub fn reset_perf_stats() {
984    PARSE_COUNT.store(0, Ordering::Relaxed);
985    PARSE_TIME_NS.store(0, Ordering::Relaxed);
986}
987
988#[cfg(test)]
989mod tests {
990    use super::*;
991
992    #[test]
993    fn test_discriminator_simd() {
994        // 测试 SIMD discriminator 提取
995        let log = "Program data: G3Kp5Dfe605nAAAAAAAAAAA=";
996        let disc = extract_discriminator_simd(log);
997        assert!(disc.is_some());
998    }
999
1000    #[test]
1001    fn test_parse_performance() {
1002        // 性能测试
1003        let log = "Program data: G3Kp5Dfe605nAAAAAAAAAAA=";
1004        let sig = Signature::default();
1005
1006        let start = std::time::Instant::now();
1007        for _ in 0..1000 {
1008            let _ = parse_log(log, sig, 0, 0, Some(0), 0, false);
1009        }
1010        let elapsed = start.elapsed();
1011
1012        println!("Average parse time: {} ns", elapsed.as_nanos() / 1000);
1013    }
1014}