1use solana_sdk::{pubkey::Pubkey, signature::Signature};
6use crate::core::events::*;
7use super::utils::*;
8
9pub mod discriminators {
11 pub const SWAP_BASE_IN: [u8; 8] = [143, 190, 90, 218, 196, 30, 51, 222];
12 pub const SWAP_BASE_OUT: [u8; 8] = [55, 217, 98, 86, 163, 74, 180, 173];
13 pub const CREATE_POOL: [u8; 8] = [233, 146, 209, 142, 207, 104, 64, 188];
14 pub const DEPOSIT: [u8; 8] = [242, 35, 198, 137, 82, 225, 242, 182];
15 pub const WITHDRAW: [u8; 8] = [183, 18, 70, 156, 148, 109, 161, 34];
16}
17
18pub const PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
20
21pub fn is_raydium_cpmm_log(log: &str) -> bool {
23 log.contains(&format!("Program {} invoke", PROGRAM_ID)) ||
24 log.contains(&format!("Program {} success", PROGRAM_ID)) ||
25 (log.contains("raydium") && log.contains("cpmm"))
26}
27
28#[inline(always)] pub fn parse_log(log: &str, signature: Signature, slot: u64, tx_index: u64, block_time_us: Option<i64>, grpc_recv_us: i64) -> Option<DexEvent> {
31 parse_structured_log(log, signature, slot, tx_index, block_time_us, grpc_recv_us)
32}
33
34fn parse_structured_log(
36 log: &str,
37 signature: Signature,
38 slot: u64,
39 tx_index: u64,
40 block_time_us: Option<i64>,
41 grpc_recv_us: i64,
42) -> Option<DexEvent> {
43 let program_data = extract_program_data(log)?;
44 if program_data.len() < 8 {
45 return None;
46 }
47
48 let discriminator: [u8; 8] = program_data[0..8].try_into().ok()?;
49 let data = &program_data[8..];
50
51 match discriminator {
52 discriminators::SWAP_BASE_IN => {
53 parse_swap_base_in_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
54 },
55 discriminators::SWAP_BASE_OUT => {
56 parse_swap_base_out_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
57 },
58 discriminators::CREATE_POOL => {
59 parse_create_pool_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
60 },
61 discriminators::DEPOSIT => {
62 parse_deposit_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
63 },
64 discriminators::WITHDRAW => {
65 parse_withdraw_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
66 },
67 _ => None,
68 }
69}
70
71#[inline(always)]
77pub fn parse_swap_base_in_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
78 let mut offset = 0;
79
80 let pool_state = read_pubkey(data, offset)?;
81 offset += 32;
82
83 let _user = read_pubkey(data, offset)?;
84 offset += 32;
85
86 let amount_in = read_u64_le(data, offset)?;
87 offset += 8;
88
89 let _minimum_amount_out = read_u64_le(data, offset)?;
90 offset += 8;
91
92 let amount_out = read_u64_le(data, offset)?;
93 offset += 8;
94
95 let is_base_input = read_bool(data, offset)?;
96
97 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
98 metadata,
99 pool_id: pool_state,
100 input_vault_before: 0,
101 output_vault_before: 0,
102 input_amount: amount_in,
103 output_amount: amount_out,
104 input_transfer_fee: 0,
105 output_transfer_fee: 0,
106 base_input: is_base_input,
107 }))
108}
109
110#[inline(always)]
112pub fn parse_swap_base_out_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
113 let mut offset = 0;
114
115 let pool_state = read_pubkey(data, offset)?;
116 offset += 32;
117
118 let _user = read_pubkey(data, offset)?;
119 offset += 32;
120
121 let _maximum_amount_in = read_u64_le(data, offset)?;
122 offset += 8;
123
124 let amount_out = read_u64_le(data, offset)?;
125 offset += 8;
126
127 let amount_in = read_u64_le(data, offset)?;
128 offset += 8;
129
130 let is_base_output = read_bool(data, offset)?;
131
132 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
133 metadata,
134 pool_id: pool_state,
135 input_vault_before: 0,
136 output_vault_before: 0,
137 input_amount: amount_in,
138 output_amount: amount_out,
139 input_transfer_fee: 0,
140 output_transfer_fee: 0,
141 base_input: !is_base_output,
142 }))
143}
144
145#[inline(always)]
147pub fn parse_create_pool_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
148 let mut offset = 0;
149
150 let pool_state = read_pubkey(data, offset)?;
151 offset += 32;
152
153 let _token_0_mint = read_pubkey(data, offset)?;
154 offset += 32;
155
156 let _token_1_mint = read_pubkey(data, offset)?;
157 offset += 32;
158
159 let creator = read_pubkey(data, offset)?;
160 offset += 32;
161
162 let initial_amount_0 = read_u64_le(data, offset)?;
163 offset += 8;
164
165 let initial_amount_1 = read_u64_le(data, offset)?;
166
167 Some(DexEvent::RaydiumCpmmInitialize(RaydiumCpmmInitializeEvent {
168 metadata,
169 pool: pool_state,
170 creator,
171 init_amount0: initial_amount_0,
172 init_amount1: initial_amount_1,
173 }))
174}
175
176#[inline(always)]
178pub fn parse_deposit_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
179 let mut offset = 0;
180
181 let pool_state = read_pubkey(data, offset)?;
182 offset += 32;
183
184 let user = read_pubkey(data, offset)?;
185 offset += 32;
186
187 let lp_token_amount = read_u64_le(data, offset)?;
188 offset += 8;
189
190 let token_0_amount = read_u64_le(data, offset)?;
191 offset += 8;
192
193 let token_1_amount = read_u64_le(data, offset)?;
194
195 Some(DexEvent::RaydiumCpmmDeposit(RaydiumCpmmDepositEvent {
196 metadata,
197 pool: pool_state,
198 user,
199 lp_token_amount,
200 token0_amount: token_0_amount,
201 token1_amount: token_1_amount,
202 }))
203}
204
205#[inline(always)]
207pub fn parse_withdraw_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
208 let mut offset = 0;
209
210 let pool_state = read_pubkey(data, offset)?;
211 offset += 32;
212
213 let user = read_pubkey(data, offset)?;
214 offset += 32;
215
216 let lp_token_amount = read_u64_le(data, offset)?;
217 offset += 8;
218
219 let token_0_amount = read_u64_le(data, offset)?;
220 offset += 8;
221
222 let token_1_amount = read_u64_le(data, offset)?;
223
224 Some(DexEvent::RaydiumCpmmWithdraw(RaydiumCpmmWithdrawEvent {
225 metadata,
226 pool: pool_state,
227 user,
228 lp_token_amount,
229 token0_amount: token_0_amount,
230 token1_amount: token_1_amount,
231 }))
232}
233
234fn parse_swap_base_in_event(
236 data: &[u8],
237 signature: Signature,
238 slot: u64,
239 tx_index: u64,
240 block_time_us: Option<i64>,
241 grpc_recv_us: i64,
242) -> Option<DexEvent> {
243 let mut offset = 0;
244
245 let pool_state = read_pubkey(data, offset)?;
246 offset += 32;
247
248 let user = read_pubkey(data, offset)?;
249 offset += 32;
250
251 let amount_in = read_u64_le(data, offset)?;
252 offset += 8;
253
254 let minimum_amount_out = read_u64_le(data, offset)?;
255 offset += 8;
256
257 let amount_out = read_u64_le(data, offset)?;
258 offset += 8;
259
260 let is_base_input = read_bool(data, offset)?;
261
262 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
263
264 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
265 metadata,
266
267 pool_id: pool_state,
269 input_vault_before: 0, output_vault_before: 0, input_amount: amount_in,
272 output_amount: amount_out,
273 input_transfer_fee: 0, output_transfer_fee: 0, base_input: is_base_input,
276
277 }))
294}
295
296fn parse_swap_base_out_event(
298 data: &[u8],
299 signature: Signature,
300 slot: u64,
301 tx_index: u64,
302 block_time_us: Option<i64>,
303 grpc_recv_us: i64,
304) -> Option<DexEvent> {
305 let mut offset = 0;
306
307 let pool_state = read_pubkey(data, offset)?;
308 offset += 32;
309
310 let user = read_pubkey(data, offset)?;
311 offset += 32;
312
313 let maximum_amount_in = read_u64_le(data, offset)?;
314 offset += 8;
315
316 let amount_out = read_u64_le(data, offset)?;
317 offset += 8;
318
319 let amount_in = read_u64_le(data, offset)?;
320 offset += 8;
321
322 let is_base_output = read_bool(data, offset)?;
323
324 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
325
326 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
327 metadata,
328
329 pool_id: pool_state,
331 input_vault_before: 0, output_vault_before: 0, input_amount: amount_in,
334 output_amount: amount_out,
335 input_transfer_fee: 0, output_transfer_fee: 0, base_input: !is_base_output,
338
339 }))
356}
357
358fn parse_create_pool_event(
360 data: &[u8],
361 signature: Signature,
362 slot: u64,
363 tx_index: u64,
364 block_time_us: Option<i64>,
365 grpc_recv_us: i64,
366) -> Option<DexEvent> {
367 let mut offset = 0;
368
369 let pool_state = read_pubkey(data, offset)?;
370 offset += 32;
371
372 let token_0_mint = read_pubkey(data, offset)?;
373 offset += 32;
374
375 let token_1_mint = read_pubkey(data, offset)?;
376 offset += 32;
377
378 let creator = read_pubkey(data, offset)?;
379 offset += 32;
380
381 let initial_amount_0 = read_u64_le(data, offset)?;
382 offset += 8;
383
384 let initial_amount_1 = read_u64_le(data, offset)?;
385
386 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
387
388 Some(DexEvent::RaydiumCpmmInitialize(RaydiumCpmmInitializeEvent {
389 metadata,
390 pool: pool_state,
391 creator,
392 init_amount0: initial_amount_0,
393 init_amount1: initial_amount_1,
394 }))
395}
396
397fn parse_deposit_event(
399 data: &[u8],
400 signature: Signature,
401 slot: u64,
402 tx_index: u64,
403 block_time_us: Option<i64>,
404 grpc_recv_us: i64,
405) -> Option<DexEvent> {
406 let mut offset = 0;
407
408 let pool_state = read_pubkey(data, offset)?;
409 offset += 32;
410
411 let user = read_pubkey(data, offset)?;
412 offset += 32;
413
414 let lp_token_amount = read_u64_le(data, offset)?;
415 offset += 8;
416
417 let token_0_amount = read_u64_le(data, offset)?;
418 offset += 8;
419
420 let token_1_amount = read_u64_le(data, offset)?;
421
422 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
423
424 Some(DexEvent::RaydiumCpmmDeposit(RaydiumCpmmDepositEvent {
425 metadata,
426 pool: pool_state,
427 user,
428 lp_token_amount,
429 token0_amount: token_0_amount,
430 token1_amount: token_1_amount,
431 }))
432}
433
434fn parse_withdraw_event(
436 data: &[u8],
437 signature: Signature,
438 slot: u64,
439 tx_index: u64,
440 block_time_us: Option<i64>,
441 grpc_recv_us: i64,
442) -> Option<DexEvent> {
443 let mut offset = 0;
444
445 let pool_state = read_pubkey(data, offset)?;
446 offset += 32;
447
448 let user = read_pubkey(data, offset)?;
449 offset += 32;
450
451 let lp_token_amount = read_u64_le(data, offset)?;
452 offset += 8;
453
454 let token_0_amount = read_u64_le(data, offset)?;
455 offset += 8;
456
457 let token_1_amount = read_u64_le(data, offset)?;
458
459 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
460
461 Some(DexEvent::RaydiumCpmmWithdraw(RaydiumCpmmWithdrawEvent {
462 metadata,
463 pool: pool_state,
464 user,
465 lp_token_amount,
466 token0_amount: token_0_amount,
467 token1_amount: token_1_amount,
468 }))
469}
470
471fn parse_text_log(
473 log: &str,
474 signature: Signature,
475 slot: u64,
476 tx_index: u64,
477 block_time_us: Option<i64>,
478 grpc_recv_us: i64,
479) -> Option<DexEvent> {
480 use super::utils::text_parser::*;
481
482 if log.contains("swap") || log.contains("Swap") {
483 if log.contains("base_in") {
484 return parse_swap_base_in_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
485 } else if log.contains("base_out") {
486 return parse_swap_base_out_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
487 } else {
488 return parse_swap_base_in_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
489 }
490 }
491
492 if log.contains("deposit") || log.contains("Deposit") {
493 return parse_deposit_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
494 }
495
496 if log.contains("withdraw") || log.contains("Withdraw") {
497 return parse_withdraw_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
498 }
499
500 if log.contains("create") && log.contains("pool") {
501 return parse_create_pool_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
502 }
503
504 None
505}
506
507fn parse_swap_base_in_from_text(
509 log: &str,
510 signature: Signature,
511 slot: u64,
512 tx_index: u64,
513 block_time_us: Option<i64>,
514 grpc_recv_us: i64,
515) -> Option<DexEvent> {
516 use super::utils::text_parser::*;
517
518 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, Pubkey::default(), grpc_recv_us);
519
520 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
521 metadata,
522
523 pool_id: Pubkey::default(),
525 input_vault_before: 0,
526 output_vault_before: 0,
527 input_amount: extract_number_from_text(log, "amount_in").unwrap_or(1_000_000_000),
528 output_amount: extract_number_from_text(log, "amount_out").unwrap_or(950_000_000),
529 input_transfer_fee: 0,
530 output_transfer_fee: 0,
531 base_input: true,
532
533 }))
550}
551
552fn parse_swap_base_out_from_text(
554 log: &str,
555 signature: Signature,
556 slot: u64,
557 tx_index: u64,
558 block_time_us: Option<i64>,
559 grpc_recv_us: i64,
560) -> Option<DexEvent> {
561 use super::utils::text_parser::*;
562
563 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, Pubkey::default(), grpc_recv_us);
564
565 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
566 metadata,
567
568 pool_id: Pubkey::default(),
570 input_vault_before: 0,
571 output_vault_before: 0,
572 input_amount: extract_number_from_text(log, "amount_in").unwrap_or(1_000_000_000),
573 output_amount: extract_number_from_text(log, "amount_out").unwrap_or(950_000_000),
574 input_transfer_fee: 0,
575 output_transfer_fee: 0,
576 base_input: false,
577
578 }))
595}
596
597fn parse_create_pool_from_text(
599 log: &str,
600 signature: Signature,
601 slot: u64,
602 tx_index: u64,
603 block_time_us: Option<i64>,
604 grpc_recv_us: i64,
605) -> Option<DexEvent> {
606 use super::utils::text_parser::*;
607
608 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, Pubkey::default(), grpc_recv_us);
609
610 Some(DexEvent::RaydiumCpmmInitialize(RaydiumCpmmInitializeEvent {
611 metadata,
612 pool: Pubkey::default(),
613 creator: Pubkey::default(),
614 init_amount0: extract_number_from_text(log, "amount_0").unwrap_or(1_000_000_000),
615 init_amount1: extract_number_from_text(log, "amount_1").unwrap_or(1_000_000_000),
616 }))
617}
618
619fn parse_deposit_from_text(
621 log: &str,
622 signature: Signature,
623 slot: u64,
624 tx_index: u64,
625 block_time_us: Option<i64>,
626 grpc_recv_us: i64,
627) -> Option<DexEvent> {
628 use super::utils::text_parser::*;
629
630 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, Pubkey::default(), grpc_recv_us);
631
632 Some(DexEvent::RaydiumCpmmDeposit(RaydiumCpmmDepositEvent {
633 metadata,
634 pool: Pubkey::default(),
635 user: Pubkey::default(),
636 lp_token_amount: extract_number_from_text(log, "lp_token").unwrap_or(1_000_000),
637 token0_amount: extract_number_from_text(log, "token_0").unwrap_or(1_000_000_000),
638 token1_amount: extract_number_from_text(log, "token_1").unwrap_or(1_000_000_000),
639 }))
640}
641
642fn parse_withdraw_from_text(
644 log: &str,
645 signature: Signature,
646 slot: u64,
647 tx_index: u64,
648 block_time_us: Option<i64>,
649 grpc_recv_us: i64,
650) -> Option<DexEvent> {
651 use super::utils::text_parser::*;
652
653 let metadata = create_metadata_simple(signature, slot, tx_index, block_time_us, Pubkey::default(), grpc_recv_us);
654
655 Some(DexEvent::RaydiumCpmmWithdraw(RaydiumCpmmWithdrawEvent {
656 metadata,
657 pool: Pubkey::default(),
658 user: Pubkey::default(),
659 lp_token_amount: extract_number_from_text(log, "lp_token").unwrap_or(1_000_000),
660 token0_amount: extract_number_from_text(log, "token_0").unwrap_or(1_000_000_000),
661 token1_amount: extract_number_from_text(log, "token_1").unwrap_or(1_000_000_000),
662 }))
663}