1use super::utils::*;
6use crate::core::events::*;
7use solana_sdk::{pubkey::Pubkey, signature::Signature};
8
9pub mod discriminators {
11 pub const SWAP: [u8; 8] = [64, 198, 205, 232, 38, 8, 113, 226];
12 pub const INCREASE_LIQUIDITY: [u8; 8] = [49, 79, 105, 212, 32, 34, 30, 84];
13 pub const DECREASE_LIQUIDITY: [u8; 8] = [58, 222, 86, 58, 68, 50, 85, 56];
14 pub const LIQUIDITY_CHANGE: [u8; 8] = [126, 240, 175, 206, 158, 88, 153, 107];
15 pub const CONFIG_CHANGE: [u8; 8] = [247, 189, 7, 119, 106, 112, 95, 151];
16 pub const CREATE_PERSONAL_POSITION: [u8; 8] = [100, 30, 87, 249, 196, 223, 154, 206];
17 pub const LIQUIDITY_CALCULATE: [u8; 8] = [237, 112, 148, 230, 57, 84, 180, 162];
18 pub const OPEN_LIMIT_ORDER: [u8; 8] = [106, 24, 71, 85, 57, 169, 158, 216];
19 pub const INCREASE_LIMIT_ORDER: [u8; 8] = [11, 120, 13, 204, 199, 87, 19, 200];
20 pub const DECREASE_LIMIT_ORDER: [u8; 8] = [70, 48, 40, 221, 219, 237, 212, 163];
21 pub const SETTLE_LIMIT_ORDER: [u8; 8] = [88, 119, 77, 164, 125, 124, 10, 194];
22 pub const UPDATE_REWARD_INFOS: [u8; 8] = [109, 127, 186, 78, 114, 65, 37, 236];
23 pub const CREATE_POOL: [u8; 8] = [25, 94, 75, 47, 112, 99, 53, 63];
24 pub const COLLECT_PERSONAL_FEE: [u8; 8] = [166, 174, 105, 192, 81, 161, 83, 105];
25 pub const COLLECT_PROTOCOL_FEE: [u8; 8] = [206, 87, 17, 79, 45, 41, 213, 61];
26}
27
28pub const PROGRAM_ID: &str = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK";
30
31pub fn is_raydium_clmm_log(log: &str) -> bool {
33 log.contains(&format!("Program {} invoke", PROGRAM_ID))
34 || log.contains(&format!("Program {} success", PROGRAM_ID))
35 || log.contains("raydium")
36 || log.contains("Raydium")
37}
38
39#[inline]
41pub fn parse_log(
42 log: &str,
43 signature: Signature,
44 slot: u64,
45 tx_index: u64,
46 block_time_us: Option<i64>,
47 grpc_recv_us: i64,
48) -> Option<DexEvent> {
49 parse_structured_log(log, signature, slot, tx_index, block_time_us, grpc_recv_us)
50}
51
52fn parse_structured_log(
54 log: &str,
55 signature: Signature,
56 slot: u64,
57 tx_index: u64,
58 block_time_us: Option<i64>,
59 grpc_recv_us: i64,
60) -> Option<DexEvent> {
61 let program_data = extract_program_data(log)?;
62 if program_data.len() < 8 {
63 return None;
64 }
65
66 let discriminator: [u8; 8] = program_data[0..8].try_into().ok()?;
67 let data = &program_data[8..];
68
69 match discriminator {
70 discriminators::SWAP => {
71 parse_swap_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
72 }
73 discriminators::INCREASE_LIQUIDITY => parse_increase_liquidity_event(
74 data,
75 signature,
76 slot,
77 tx_index,
78 block_time_us,
79 grpc_recv_us,
80 ),
81 discriminators::DECREASE_LIQUIDITY => parse_decrease_liquidity_event(
82 data,
83 signature,
84 slot,
85 tx_index,
86 block_time_us,
87 grpc_recv_us,
88 ),
89 discriminators::LIQUIDITY_CHANGE => parse_liquidity_change_event(
90 data,
91 signature,
92 slot,
93 tx_index,
94 block_time_us,
95 grpc_recv_us,
96 ),
97 discriminators::CONFIG_CHANGE => {
98 parse_config_change_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
99 }
100 discriminators::CREATE_PERSONAL_POSITION => parse_create_personal_position_event(
101 data,
102 signature,
103 slot,
104 tx_index,
105 block_time_us,
106 grpc_recv_us,
107 ),
108 discriminators::LIQUIDITY_CALCULATE => parse_liquidity_calculate_event(
109 data,
110 signature,
111 slot,
112 tx_index,
113 block_time_us,
114 grpc_recv_us,
115 ),
116 discriminators::OPEN_LIMIT_ORDER => parse_open_limit_order_event(
117 data,
118 signature,
119 slot,
120 tx_index,
121 block_time_us,
122 grpc_recv_us,
123 ),
124 discriminators::INCREASE_LIMIT_ORDER => parse_increase_limit_order_event(
125 data,
126 signature,
127 slot,
128 tx_index,
129 block_time_us,
130 grpc_recv_us,
131 ),
132 discriminators::DECREASE_LIMIT_ORDER => parse_decrease_limit_order_event(
133 data,
134 signature,
135 slot,
136 tx_index,
137 block_time_us,
138 grpc_recv_us,
139 ),
140 discriminators::SETTLE_LIMIT_ORDER => parse_settle_limit_order_event(
141 data,
142 signature,
143 slot,
144 tx_index,
145 block_time_us,
146 grpc_recv_us,
147 ),
148 discriminators::UPDATE_REWARD_INFOS => parse_update_reward_infos_event(
149 data,
150 signature,
151 slot,
152 tx_index,
153 block_time_us,
154 grpc_recv_us,
155 ),
156 discriminators::CREATE_POOL => {
157 parse_create_pool_event(data, signature, slot, tx_index, block_time_us, grpc_recv_us)
158 }
159 discriminators::COLLECT_PERSONAL_FEE => parse_collect_personal_fee_event(
160 data,
161 signature,
162 slot,
163 tx_index,
164 block_time_us,
165 grpc_recv_us,
166 ),
167 discriminators::COLLECT_PROTOCOL_FEE => parse_collect_protocol_fee_event(
168 data,
169 signature,
170 slot,
171 tx_index,
172 block_time_us,
173 grpc_recv_us,
174 ),
175 _ => None,
176 }
177}
178
179fn parse_swap_event(
181 data: &[u8],
182 signature: Signature,
183 slot: u64,
184 tx_index: u64,
185 block_time_us: Option<i64>,
186 grpc_recv_us: i64,
187) -> Option<DexEvent> {
188 let mut offset = 0;
189
190 let pool_state = read_pubkey(data, offset)?;
191 offset += 32;
192
193 let sender = read_pubkey(data, offset)?;
194 offset += 32;
195
196 let token_account_0 = read_pubkey(data, offset)?;
197 offset += 32;
198
199 let token_account_1 = read_pubkey(data, offset)?;
200 offset += 32;
201
202 let amount_0 = read_u64_le(data, offset)?;
203 offset += 8;
204
205 let transfer_fee_0 = read_u64_le(data, offset)?;
206 offset += 8;
207
208 let amount_1 = read_u64_le(data, offset)?;
209 offset += 8;
210
211 let transfer_fee_1 = read_u64_le(data, offset)?;
212 offset += 8;
213
214 let zero_for_one = read_bool(data, offset)?;
215 offset += 1;
216
217 let sqrt_price_x64 = read_u128_le(data, offset)?;
218 offset += 16;
219
220 let liquidity = read_u128_le(data, offset)?;
221 offset += 16;
222
223 let tick = read_i32_le(data, offset)?;
224
225 let metadata =
226 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
227
228 Some(DexEvent::RaydiumClmmSwap(RaydiumClmmSwapEvent {
229 metadata,
230 pool_state,
231 sender,
232 token_account_0,
233 token_account_1,
234 amount_0,
235 transfer_fee_0,
236 amount_1,
237 transfer_fee_1,
238 zero_for_one,
239 sqrt_price_x64,
240 liquidity,
241 tick,
242 amm_config: Pubkey::default(),
243 input_vault: Pubkey::default(),
244 output_vault: Pubkey::default(),
245 observation_state: Pubkey::default(),
246 input_mint: Pubkey::default(),
247 output_mint: Pubkey::default(),
248 tick_array_bitmap_extension: None,
249 tick_arrays: Vec::new(),
250
251 ..Default::default()
252 }))
253}
254
255fn parse_increase_liquidity_event(
257 data: &[u8],
258 signature: Signature,
259 slot: u64,
260 tx_index: u64,
261 block_time_us: Option<i64>,
262 grpc_recv_us: i64,
263) -> Option<DexEvent> {
264 let mut offset = 0;
265
266 let position_nft_mint = read_pubkey(data, offset)?;
267 offset += 32;
268
269 let liquidity = read_u128_le(data, offset)?;
270 offset += 16;
271
272 let amount_0 = read_u64_le(data, offset)?;
273 offset += 8;
274
275 let amount_1 = read_u64_le(data, offset)?;
276 offset += 8;
277
278 let amount_0_transfer_fee = read_u64_le(data, offset)?;
279 offset += 8;
280
281 let amount_1_transfer_fee = read_u64_le(data, offset)?;
282
283 let metadata = create_metadata_simple(
284 signature,
285 slot,
286 tx_index,
287 block_time_us,
288 Pubkey::default(),
289 grpc_recv_us,
290 );
291
292 Some(DexEvent::RaydiumClmmIncreaseLiquidity(RaydiumClmmIncreaseLiquidityEvent {
293 personal_position: Pubkey::default(),
294 metadata,
295 position_nft_mint,
296 liquidity,
297 amount_0,
298 amount_1,
299 amount_0_transfer_fee,
300 amount_1_transfer_fee,
301 pool: Pubkey::default(),
302 user: Pubkey::default(), amount0_max: 0,
304 amount1_max: 0,
305 }))
306}
307
308fn parse_decrease_liquidity_event(
310 data: &[u8],
311 signature: Signature,
312 slot: u64,
313 tx_index: u64,
314 block_time_us: Option<i64>,
315 grpc_recv_us: i64,
316) -> Option<DexEvent> {
317 let mut offset = 0;
318
319 let position_nft_mint = read_pubkey(data, offset)?;
320 offset += 32;
321
322 let liquidity = read_u128_le(data, offset)?;
323 offset += 16;
324
325 let decrease_amount_0 = read_u64_le(data, offset)?;
326 offset += 8;
327
328 let decrease_amount_1 = read_u64_le(data, offset)?;
329 offset += 8;
330
331 let fee_amount_0 = read_u64_le(data, offset)?;
332 offset += 8;
333
334 let fee_amount_1 = read_u64_le(data, offset)?;
335 offset += 8;
336
337 let mut reward_amounts = [0u64; 3];
338 for reward_amount in &mut reward_amounts {
339 *reward_amount = read_u64_le(data, offset)?;
340 offset += 8;
341 }
342
343 let transfer_fee_0 = read_u64_le(data, offset)?;
344 offset += 8;
345
346 let transfer_fee_1 = read_u64_le(data, offset)?;
347
348 let metadata = create_metadata_simple(
349 signature,
350 slot,
351 tx_index,
352 block_time_us,
353 Pubkey::default(),
354 grpc_recv_us,
355 );
356
357 Some(DexEvent::RaydiumClmmDecreaseLiquidity(RaydiumClmmDecreaseLiquidityEvent {
358 personal_position: Pubkey::default(),
359 metadata,
360 position_nft_mint,
361 liquidity,
362 decrease_amount_0,
363 decrease_amount_1,
364 fee_amount_0,
365 fee_amount_1,
366 reward_amounts,
367 transfer_fee_0,
368 transfer_fee_1,
369 pool: Pubkey::default(),
370 user: Pubkey::default(), amount0_min: 0,
372 amount1_min: 0,
373 }))
374}
375
376fn parse_liquidity_change_event(
378 data: &[u8],
379 signature: Signature,
380 slot: u64,
381 tx_index: u64,
382 block_time_us: Option<i64>,
383 grpc_recv_us: i64,
384) -> Option<DexEvent> {
385 let mut offset = 0;
386
387 let pool_state = read_pubkey(data, offset)?;
388 offset += 32;
389
390 let tick = read_i32_le(data, offset)?;
391 offset += 4;
392
393 let tick_lower = read_i32_le(data, offset)?;
394 offset += 4;
395
396 let tick_upper = read_i32_le(data, offset)?;
397 offset += 4;
398
399 let liquidity_before = read_u128_le(data, offset)?;
400 offset += 16;
401
402 let liquidity_after = read_u128_le(data, offset)?;
403
404 let metadata =
405 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
406
407 Some(DexEvent::RaydiumClmmLiquidityChange(RaydiumClmmLiquidityChangeEvent {
408 metadata,
409 pool_state,
410 tick,
411 tick_lower,
412 tick_upper,
413 liquidity_before,
414 liquidity_after,
415 }))
416}
417
418fn parse_config_change_event(
419 data: &[u8],
420 signature: Signature,
421 slot: u64,
422 tx_index: u64,
423 block_time_us: Option<i64>,
424 grpc_recv_us: i64,
425) -> Option<DexEvent> {
426 let metadata = create_metadata_simple(
427 signature,
428 slot,
429 tx_index,
430 block_time_us,
431 Pubkey::default(),
432 grpc_recv_us,
433 );
434 parse_config_change_from_data(data, metadata)
435}
436
437fn parse_create_personal_position_event(
438 data: &[u8],
439 signature: Signature,
440 slot: u64,
441 tx_index: u64,
442 block_time_us: Option<i64>,
443 grpc_recv_us: i64,
444) -> Option<DexEvent> {
445 let pool_state = read_pubkey(data, 0).unwrap_or_default();
446 let metadata =
447 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
448 parse_create_personal_position_from_data(data, metadata)
449}
450
451fn parse_liquidity_calculate_event(
452 data: &[u8],
453 signature: Signature,
454 slot: u64,
455 tx_index: u64,
456 block_time_us: Option<i64>,
457 grpc_recv_us: i64,
458) -> Option<DexEvent> {
459 let metadata = create_metadata_simple(
460 signature,
461 slot,
462 tx_index,
463 block_time_us,
464 Pubkey::default(),
465 grpc_recv_us,
466 );
467 parse_liquidity_calculate_from_data(data, metadata)
468}
469
470fn parse_open_limit_order_event(
471 data: &[u8],
472 signature: Signature,
473 slot: u64,
474 tx_index: u64,
475 block_time_us: Option<i64>,
476 grpc_recv_us: i64,
477) -> Option<DexEvent> {
478 let pool_id = read_pubkey(data, 0).unwrap_or_default();
479 let metadata =
480 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_id, grpc_recv_us);
481 parse_open_limit_order_from_data(data, metadata)
482}
483
484fn parse_increase_limit_order_event(
485 data: &[u8],
486 signature: Signature,
487 slot: u64,
488 tx_index: u64,
489 block_time_us: Option<i64>,
490 grpc_recv_us: i64,
491) -> Option<DexEvent> {
492 let pool_id = read_pubkey(data, 0).unwrap_or_default();
493 let metadata =
494 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_id, grpc_recv_us);
495 parse_increase_limit_order_from_data(data, metadata)
496}
497
498fn parse_decrease_limit_order_event(
499 data: &[u8],
500 signature: Signature,
501 slot: u64,
502 tx_index: u64,
503 block_time_us: Option<i64>,
504 grpc_recv_us: i64,
505) -> Option<DexEvent> {
506 let pool_id = read_pubkey(data, 0).unwrap_or_default();
507 let metadata =
508 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_id, grpc_recv_us);
509 parse_decrease_limit_order_from_data(data, metadata)
510}
511
512fn parse_settle_limit_order_event(
513 data: &[u8],
514 signature: Signature,
515 slot: u64,
516 tx_index: u64,
517 block_time_us: Option<i64>,
518 grpc_recv_us: i64,
519) -> Option<DexEvent> {
520 let pool_id = read_pubkey(data, 0).unwrap_or_default();
521 let metadata =
522 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_id, grpc_recv_us);
523 parse_settle_limit_order_from_data(data, metadata)
524}
525
526fn parse_update_reward_infos_event(
527 data: &[u8],
528 signature: Signature,
529 slot: u64,
530 tx_index: u64,
531 block_time_us: Option<i64>,
532 grpc_recv_us: i64,
533) -> Option<DexEvent> {
534 let metadata = create_metadata_simple(
535 signature,
536 slot,
537 tx_index,
538 block_time_us,
539 Pubkey::default(),
540 grpc_recv_us,
541 );
542 parse_update_reward_infos_from_data(data, metadata)
543}
544
545fn parse_create_pool_event(
547 data: &[u8],
548 signature: Signature,
549 slot: u64,
550 tx_index: u64,
551 block_time_us: Option<i64>,
552 grpc_recv_us: i64,
553) -> Option<DexEvent> {
554 let mut offset = 0;
555
556 let token_0_mint = read_pubkey(data, offset)?;
557 offset += 32;
558
559 let token_1_mint = read_pubkey(data, offset)?;
560 offset += 32;
561
562 let tick_spacing = read_u16_le(data, offset)?;
563 offset += 2;
564
565 let pool_state = read_pubkey(data, offset)?;
566 offset += 32;
567
568 let sqrt_price_x64 = read_u128_le(data, offset)?;
569 offset += 16;
570
571 let tick = read_i32_le(data, offset)?;
572 offset += 4;
573
574 let token_vault_0 = read_pubkey(data, offset)?;
575 offset += 32;
576
577 let token_vault_1 = read_pubkey(data, offset)?;
578
579 let metadata =
580 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
581
582 Some(DexEvent::RaydiumClmmCreatePool(RaydiumClmmCreatePoolEvent {
583 metadata,
584 pool: pool_state,
585 token_0_mint,
586 token_1_mint,
587 tick_spacing,
588 sqrt_price_x64,
589 tick,
590 token_vault_0,
591 token_vault_1,
592 fee_rate: 0,
593 creator: Pubkey::default(),
594 open_time: 0,
595 }))
596}
597
598fn parse_collect_personal_fee_event(
600 data: &[u8],
601 signature: Signature,
602 slot: u64,
603 tx_index: u64,
604 block_time_us: Option<i64>,
605 grpc_recv_us: i64,
606) -> Option<DexEvent> {
607 let mut offset = 0;
608
609 let position_nft_mint = read_pubkey(data, offset)?;
610 offset += 32;
611
612 let recipient_token_account_0 = read_pubkey(data, offset)?;
613 offset += 32;
614
615 let recipient_token_account_1 = read_pubkey(data, offset)?;
616 offset += 32;
617
618 let amount_0 = read_u64_le(data, offset)?;
619 offset += 8;
620
621 let amount_1 = read_u64_le(data, offset)?;
622
623 let metadata = create_metadata_simple(
624 signature,
625 slot,
626 tx_index,
627 block_time_us,
628 Pubkey::default(),
629 grpc_recv_us,
630 );
631
632 Some(DexEvent::RaydiumClmmCollectFee(RaydiumClmmCollectFeeEvent {
633 metadata,
634 pool_state: Pubkey::default(),
635 position_nft_mint,
636 recipient_token_account_0,
637 recipient_token_account_1,
638 amount_0,
639 amount_1,
640 }))
641}
642
643fn parse_collect_protocol_fee_event(
645 data: &[u8],
646 signature: Signature,
647 slot: u64,
648 tx_index: u64,
649 block_time_us: Option<i64>,
650 grpc_recv_us: i64,
651) -> Option<DexEvent> {
652 let mut offset = 0;
653
654 let pool_state = read_pubkey(data, offset)?;
655 offset += 32;
656
657 let recipient_token_account_0 = read_pubkey(data, offset)?;
658 offset += 32;
659
660 let recipient_token_account_1 = read_pubkey(data, offset)?;
661 offset += 32;
662
663 let amount_0 = read_u64_le(data, offset)?;
664 offset += 8;
665
666 let amount_1 = read_u64_le(data, offset)?;
667
668 let metadata =
669 create_metadata_simple(signature, slot, tx_index, block_time_us, pool_state, grpc_recv_us);
670
671 Some(DexEvent::RaydiumClmmCollectFee(RaydiumClmmCollectFeeEvent {
672 metadata,
673 pool_state,
674 position_nft_mint: Pubkey::default(),
675 recipient_token_account_0,
676 recipient_token_account_1,
677 amount_0,
678 amount_1,
679 }))
680}
681
682fn parse_text_log(
684 log: &str,
685 signature: Signature,
686 slot: u64,
687 tx_index: u64,
688 block_time_us: Option<i64>,
689 grpc_recv_us: i64,
690) -> Option<DexEvent> {
691 use super::utils::text_parser::*;
692
693 if log.contains("swap") || log.contains("Swap") {
694 return parse_swap_from_text(log, signature, slot, tx_index, block_time_us, grpc_recv_us);
695 }
696
697 if log.contains("increase") && log.contains("liquidity") {
698 return parse_increase_liquidity_from_text(
699 log,
700 signature,
701 slot,
702 tx_index,
703 block_time_us,
704 grpc_recv_us,
705 );
706 }
707
708 if log.contains("decrease") && log.contains("liquidity") {
709 return parse_decrease_liquidity_from_text(
710 log,
711 signature,
712 slot,
713 tx_index,
714 block_time_us,
715 grpc_recv_us,
716 );
717 }
718
719 if log.contains("create") && log.contains("pool") {
720 return parse_create_pool_from_text(
721 log,
722 signature,
723 slot,
724 tx_index,
725 block_time_us,
726 grpc_recv_us,
727 );
728 }
729
730 if log.contains("collect") && log.contains("fee") {
731 return parse_collect_fee_from_text(
732 log,
733 signature,
734 slot,
735 tx_index,
736 block_time_us,
737 grpc_recv_us,
738 );
739 }
740
741 None
742}
743
744fn parse_swap_from_text(
746 log: &str,
747 signature: Signature,
748 slot: u64,
749 tx_index: u64,
750 block_time_us: Option<i64>,
751 grpc_recv_us: i64,
752) -> Option<DexEvent> {
753 use super::utils::text_parser::*;
754
755 let metadata = create_metadata_simple(
756 signature,
757 slot,
758 tx_index,
759 block_time_us,
760 Pubkey::default(),
761 grpc_recv_us,
762 );
763 let is_base_input = detect_trade_type(log).unwrap_or(true);
764
765 Some(DexEvent::RaydiumClmmSwap(RaydiumClmmSwapEvent {
766 metadata,
767
768 pool_state: Pubkey::default(),
770 sender: Pubkey::default(),
771 token_account_0: Pubkey::default(),
772 token_account_1: Pubkey::default(),
773 amount_0: 0,
774 transfer_fee_0: 0,
775 amount_1: 0,
776 transfer_fee_1: 0,
777 zero_for_one: is_base_input,
778 sqrt_price_x64: 0,
779 liquidity: 0,
781 tick: 0,
782 ..Default::default()
788 }))
789}
790
791fn parse_increase_liquidity_from_text(
793 log: &str,
794 signature: Signature,
795 slot: u64,
796 tx_index: u64,
797 block_time_us: Option<i64>,
798 grpc_recv_us: i64,
799) -> Option<DexEvent> {
800 use super::utils::text_parser::*;
801
802 let metadata = create_metadata_simple(
803 signature,
804 slot,
805 tx_index,
806 block_time_us,
807 Pubkey::default(),
808 grpc_recv_us,
809 );
810
811 Some(DexEvent::RaydiumClmmIncreaseLiquidity(RaydiumClmmIncreaseLiquidityEvent {
812 personal_position: Pubkey::default(),
813 metadata,
814 position_nft_mint: Pubkey::default(),
815 liquidity: extract_number_from_text(log, "liquidity").unwrap_or(1_000_000) as u128,
816 amount_0: 0,
817 amount_1: 0,
818 amount_0_transfer_fee: 0,
819 amount_1_transfer_fee: 0,
820 pool: Pubkey::default(),
821 amount0_max: extract_number_from_text(log, "amount0_max").unwrap_or(1_000_000),
822 amount1_max: extract_number_from_text(log, "amount1_max").unwrap_or(1_000_000),
823 user: Pubkey::default(),
824 }))
825}
826
827fn parse_decrease_liquidity_from_text(
829 log: &str,
830 signature: Signature,
831 slot: u64,
832 tx_index: u64,
833 block_time_us: Option<i64>,
834 grpc_recv_us: i64,
835) -> Option<DexEvent> {
836 use super::utils::text_parser::*;
837
838 let metadata = create_metadata_simple(
839 signature,
840 slot,
841 tx_index,
842 block_time_us,
843 Pubkey::default(),
844 grpc_recv_us,
845 );
846
847 Some(DexEvent::RaydiumClmmDecreaseLiquidity(RaydiumClmmDecreaseLiquidityEvent {
848 personal_position: Pubkey::default(),
849 metadata,
850 position_nft_mint: Pubkey::default(),
851 liquidity: extract_number_from_text(log, "liquidity").unwrap_or(1_000_000) as u128,
852 decrease_amount_0: 0,
853 decrease_amount_1: 0,
854 fee_amount_0: 0,
855 fee_amount_1: 0,
856 reward_amounts: [0; 3],
857 transfer_fee_0: 0,
858 transfer_fee_1: 0,
859 pool: Pubkey::default(),
860 amount0_min: extract_number_from_text(log, "amount0_min").unwrap_or(1_000_000),
861 amount1_min: extract_number_from_text(log, "amount1_min").unwrap_or(1_000_000),
862 user: Pubkey::default(),
863 }))
864}
865
866fn parse_create_pool_from_text(
868 log: &str,
869 signature: Signature,
870 slot: u64,
871 tx_index: u64,
872 block_time_us: Option<i64>,
873 grpc_recv_us: i64,
874) -> Option<DexEvent> {
875 use super::utils::text_parser::*;
876
877 let metadata = create_metadata_simple(
878 signature,
879 slot,
880 tx_index,
881 block_time_us,
882 Pubkey::default(),
883 grpc_recv_us,
884 );
885
886 Some(DexEvent::RaydiumClmmCreatePool(RaydiumClmmCreatePoolEvent {
887 metadata,
888 pool: Pubkey::default(),
889 token_0_mint: Pubkey::default(),
890 token_1_mint: Pubkey::default(),
891 tick_spacing: 0,
892 sqrt_price_x64: 0,
893 tick: 0,
894 token_vault_0: Pubkey::default(),
895 token_vault_1: Pubkey::default(),
896 fee_rate: 0,
897 creator: Pubkey::default(),
898 open_time: 0,
899 }))
900}
901
902fn parse_collect_fee_from_text(
904 log: &str,
905 signature: Signature,
906 slot: u64,
907 tx_index: u64,
908 block_time_us: Option<i64>,
909 grpc_recv_us: i64,
910) -> Option<DexEvent> {
911 use super::utils::text_parser::*;
912
913 let metadata = create_metadata_simple(
914 signature,
915 slot,
916 tx_index,
917 block_time_us,
918 Pubkey::default(),
919 grpc_recv_us,
920 );
921
922 Some(DexEvent::RaydiumClmmCollectFee(RaydiumClmmCollectFeeEvent {
923 metadata,
924 pool_state: Pubkey::default(),
925 position_nft_mint: Pubkey::default(),
926 recipient_token_account_0: Pubkey::default(),
927 recipient_token_account_1: Pubkey::default(),
928 amount_0: extract_number_from_text(log, "amount_0").unwrap_or(10_000),
929 amount_1: extract_number_from_text(log, "amount_1").unwrap_or(10_000),
930 }))
931}
932
933#[inline(always)]
940pub fn parse_swap_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
941 let mut offset = 0;
942
943 let pool_state = read_pubkey(data, offset)?;
944 offset += 32;
945
946 let sender = read_pubkey(data, offset)?;
947 offset += 32;
948
949 let token_account_0 = read_pubkey(data, offset)?;
950 offset += 32;
951
952 let token_account_1 = read_pubkey(data, offset)?;
953 offset += 32;
954
955 let amount_0 = read_u64_le(data, offset)?;
956 offset += 8;
957
958 let transfer_fee_0 = read_u64_le(data, offset)?;
959 offset += 8;
960
961 let amount_1 = read_u64_le(data, offset)?;
962 offset += 8;
963
964 let transfer_fee_1 = read_u64_le(data, offset)?;
965 offset += 8;
966
967 let zero_for_one = read_bool(data, offset)?;
968 offset += 1;
969
970 let sqrt_price_x64 = read_u128_le(data, offset)?;
971 offset += 16;
972
973 let liquidity = read_u128_le(data, offset)?;
974 offset += 16;
975
976 let tick = read_i32_le(data, offset)?;
977
978 Some(DexEvent::RaydiumClmmSwap(RaydiumClmmSwapEvent {
979 metadata,
980 pool_state,
981 sender,
982 token_account_0,
983 token_account_1,
984 amount_0,
985 transfer_fee_0,
986 amount_1,
987 transfer_fee_1,
988 zero_for_one,
989 sqrt_price_x64,
990 liquidity,
991 tick,
992 amm_config: Pubkey::default(),
993 input_vault: Pubkey::default(),
994 output_vault: Pubkey::default(),
995 observation_state: Pubkey::default(),
996 input_mint: Pubkey::default(),
997 output_mint: Pubkey::default(),
998 tick_array_bitmap_extension: None,
999 tick_arrays: Vec::new(),
1000
1001 ..Default::default()
1002 }))
1003}
1004
1005#[inline(always)]
1007pub fn parse_increase_liquidity_from_data(
1008 data: &[u8],
1009 metadata: EventMetadata,
1010) -> Option<DexEvent> {
1011 let mut offset = 0;
1012
1013 let position_nft_mint = read_pubkey(data, offset)?;
1014 offset += 32;
1015
1016 let liquidity = read_u128_le(data, offset)?;
1017 offset += 16;
1018
1019 let amount_0 = read_u64_le(data, offset)?;
1020 offset += 8;
1021
1022 let amount_1 = read_u64_le(data, offset)?;
1023 offset += 8;
1024
1025 let amount_0_transfer_fee = read_u64_le(data, offset)?;
1026 offset += 8;
1027
1028 let amount_1_transfer_fee = read_u64_le(data, offset)?;
1029
1030 Some(DexEvent::RaydiumClmmIncreaseLiquidity(RaydiumClmmIncreaseLiquidityEvent {
1031 personal_position: Pubkey::default(),
1032 metadata,
1033 position_nft_mint,
1034 liquidity,
1035 amount_0,
1036 amount_1,
1037 amount_0_transfer_fee,
1038 amount_1_transfer_fee,
1039 pool: Pubkey::default(),
1040 amount0_max: 0,
1041 amount1_max: 0,
1042 user: Pubkey::default(),
1043 }))
1044}
1045
1046#[inline(always)]
1048pub fn parse_decrease_liquidity_from_data(
1049 data: &[u8],
1050 metadata: EventMetadata,
1051) -> Option<DexEvent> {
1052 let mut offset = 0;
1053
1054 let position_nft_mint = read_pubkey(data, offset)?;
1055 offset += 32;
1056
1057 let liquidity = read_u128_le(data, offset)?;
1058 offset += 16;
1059
1060 let decrease_amount_0 = read_u64_le(data, offset)?;
1061 offset += 8;
1062
1063 let decrease_amount_1 = read_u64_le(data, offset)?;
1064 offset += 8;
1065
1066 let fee_amount_0 = read_u64_le(data, offset)?;
1067 offset += 8;
1068
1069 let fee_amount_1 = read_u64_le(data, offset)?;
1070 offset += 8;
1071
1072 let mut reward_amounts = [0u64; 3];
1073 for reward_amount in &mut reward_amounts {
1074 *reward_amount = read_u64_le(data, offset)?;
1075 offset += 8;
1076 }
1077
1078 let transfer_fee_0 = read_u64_le(data, offset)?;
1079 offset += 8;
1080
1081 let transfer_fee_1 = read_u64_le(data, offset)?;
1082
1083 Some(DexEvent::RaydiumClmmDecreaseLiquidity(RaydiumClmmDecreaseLiquidityEvent {
1084 personal_position: Pubkey::default(),
1085 metadata,
1086 position_nft_mint,
1087 liquidity,
1088 decrease_amount_0,
1089 decrease_amount_1,
1090 fee_amount_0,
1091 fee_amount_1,
1092 reward_amounts,
1093 transfer_fee_0,
1094 transfer_fee_1,
1095 pool: Pubkey::default(),
1096 amount0_min: 0,
1097 amount1_min: 0,
1098 user: Pubkey::default(),
1099 }))
1100}
1101
1102#[inline(always)]
1104pub fn parse_liquidity_change_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
1105 let mut offset = 0;
1106
1107 let pool_state = read_pubkey(data, offset)?;
1108 offset += 32;
1109
1110 let tick = read_i32_le(data, offset)?;
1111 offset += 4;
1112
1113 let tick_lower = read_i32_le(data, offset)?;
1114 offset += 4;
1115
1116 let tick_upper = read_i32_le(data, offset)?;
1117 offset += 4;
1118
1119 let liquidity_before = read_u128_le(data, offset)?;
1120 offset += 16;
1121
1122 let liquidity_after = read_u128_le(data, offset)?;
1123
1124 Some(DexEvent::RaydiumClmmLiquidityChange(RaydiumClmmLiquidityChangeEvent {
1125 metadata,
1126 pool_state,
1127 tick,
1128 tick_lower,
1129 tick_upper,
1130 liquidity_before,
1131 liquidity_after,
1132 }))
1133}
1134
1135#[inline(always)]
1137pub fn parse_config_change_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
1138 let mut offset = 0;
1139
1140 let index = read_u16_le(data, offset)?;
1141 offset += 2;
1142
1143 let owner = read_pubkey(data, offset)?;
1144 offset += 32;
1145
1146 let protocol_fee_rate = read_u32_le(data, offset)?;
1147 offset += 4;
1148
1149 let trade_fee_rate = read_u32_le(data, offset)?;
1150 offset += 4;
1151
1152 let tick_spacing = read_u16_le(data, offset)?;
1153 offset += 2;
1154
1155 let fund_fee_rate = read_u32_le(data, offset)?;
1156 offset += 4;
1157
1158 let fund_owner = read_pubkey(data, offset)?;
1159
1160 Some(DexEvent::RaydiumClmmConfigChange(RaydiumClmmConfigChangeEvent {
1161 metadata,
1162 index,
1163 owner,
1164 protocol_fee_rate,
1165 trade_fee_rate,
1166 tick_spacing,
1167 fund_fee_rate,
1168 fund_owner,
1169 }))
1170}
1171
1172#[inline(always)]
1174pub fn parse_create_personal_position_from_data(
1175 data: &[u8],
1176 metadata: EventMetadata,
1177) -> Option<DexEvent> {
1178 let mut offset = 0;
1179
1180 let pool_state = read_pubkey(data, offset)?;
1181 offset += 32;
1182
1183 let minter = read_pubkey(data, offset)?;
1184 offset += 32;
1185
1186 let nft_owner = read_pubkey(data, offset)?;
1187 offset += 32;
1188
1189 let tick_lower_index = read_i32_le(data, offset)?;
1190 offset += 4;
1191
1192 let tick_upper_index = read_i32_le(data, offset)?;
1193 offset += 4;
1194
1195 let liquidity = read_u128_le(data, offset)?;
1196 offset += 16;
1197
1198 let deposit_amount_0 = read_u64_le(data, offset)?;
1199 offset += 8;
1200
1201 let deposit_amount_1 = read_u64_le(data, offset)?;
1202 offset += 8;
1203
1204 let deposit_amount_0_transfer_fee = read_u64_le(data, offset)?;
1205 offset += 8;
1206
1207 let deposit_amount_1_transfer_fee = read_u64_le(data, offset)?;
1208
1209 Some(DexEvent::RaydiumClmmCreatePersonalPosition(RaydiumClmmCreatePersonalPositionEvent {
1210 metadata,
1211 pool_state,
1212 minter,
1213 nft_owner,
1214 tick_lower_index,
1215 tick_upper_index,
1216 liquidity,
1217 deposit_amount_0,
1218 deposit_amount_1,
1219 deposit_amount_0_transfer_fee,
1220 deposit_amount_1_transfer_fee,
1221 }))
1222}
1223
1224#[inline(always)]
1226pub fn parse_liquidity_calculate_from_data(
1227 data: &[u8],
1228 metadata: EventMetadata,
1229) -> Option<DexEvent> {
1230 let mut offset = 0;
1231
1232 let pool_liquidity = read_u128_le(data, offset)?;
1233 offset += 16;
1234
1235 let pool_sqrt_price_x64 = read_u128_le(data, offset)?;
1236 offset += 16;
1237
1238 let pool_tick = read_i32_le(data, offset)?;
1239 offset += 4;
1240
1241 let calc_amount_0 = read_u64_le(data, offset)?;
1242 offset += 8;
1243
1244 let calc_amount_1 = read_u64_le(data, offset)?;
1245 offset += 8;
1246
1247 let trade_fee_owed_0 = read_u64_le(data, offset)?;
1248 offset += 8;
1249
1250 let trade_fee_owed_1 = read_u64_le(data, offset)?;
1251 offset += 8;
1252
1253 let transfer_fee_0 = read_u64_le(data, offset)?;
1254 offset += 8;
1255
1256 let transfer_fee_1 = read_u64_le(data, offset)?;
1257
1258 Some(DexEvent::RaydiumClmmLiquidityCalculate(RaydiumClmmLiquidityCalculateEvent {
1259 metadata,
1260 pool_liquidity,
1261 pool_sqrt_price_x64,
1262 pool_tick,
1263 calc_amount_0,
1264 calc_amount_1,
1265 trade_fee_owed_0,
1266 trade_fee_owed_1,
1267 transfer_fee_0,
1268 transfer_fee_1,
1269 }))
1270}
1271
1272#[inline(always)]
1274pub fn parse_open_limit_order_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
1275 let mut offset = 0;
1276
1277 let pool_id = read_pubkey(data, offset)?;
1278 offset += 32;
1279
1280 let limit_order = read_pubkey(data, offset)?;
1281 offset += 32;
1282
1283 let zero_for_one = read_bool(data, offset)?;
1284 offset += 1;
1285
1286 let tick_index = read_i32_le(data, offset)?;
1287 offset += 4;
1288
1289 let total_amount = read_u64_le(data, offset)?;
1290 offset += 8;
1291
1292 let transfer_fee = read_u64_le(data, offset)?;
1293
1294 Some(DexEvent::RaydiumClmmOpenLimitOrder(RaydiumClmmOpenLimitOrderEvent {
1295 metadata,
1296 pool_id,
1297 limit_order,
1298 zero_for_one,
1299 tick_index,
1300 total_amount,
1301 transfer_fee,
1302 }))
1303}
1304
1305#[inline(always)]
1307pub fn parse_increase_limit_order_from_data(
1308 data: &[u8],
1309 metadata: EventMetadata,
1310) -> Option<DexEvent> {
1311 let mut offset = 0;
1312
1313 let pool_id = read_pubkey(data, offset)?;
1314 offset += 32;
1315
1316 let limit_order = read_pubkey(data, offset)?;
1317 offset += 32;
1318
1319 let zero_for_one = read_bool(data, offset)?;
1320 offset += 1;
1321
1322 let tick_index = read_i32_le(data, offset)?;
1323 offset += 4;
1324
1325 let total_amount = read_u64_le(data, offset)?;
1326 offset += 8;
1327
1328 let increased_amount = read_u64_le(data, offset)?;
1329 offset += 8;
1330
1331 let transfer_fee = read_u64_le(data, offset)?;
1332
1333 Some(DexEvent::RaydiumClmmIncreaseLimitOrder(RaydiumClmmIncreaseLimitOrderEvent {
1334 metadata,
1335 pool_id,
1336 limit_order,
1337 zero_for_one,
1338 tick_index,
1339 total_amount,
1340 increased_amount,
1341 transfer_fee,
1342 }))
1343}
1344
1345#[inline(always)]
1347pub fn parse_decrease_limit_order_from_data(
1348 data: &[u8],
1349 metadata: EventMetadata,
1350) -> Option<DexEvent> {
1351 let mut offset = 0;
1352
1353 let pool_id = read_pubkey(data, offset)?;
1354 offset += 32;
1355
1356 let limit_order = read_pubkey(data, offset)?;
1357 offset += 32;
1358
1359 let zero_for_one = read_bool(data, offset)?;
1360 offset += 1;
1361
1362 let tick_index = read_i32_le(data, offset)?;
1363 offset += 4;
1364
1365 let total_amount = read_u64_le(data, offset)?;
1366 offset += 8;
1367
1368 let filled_amount = read_u64_le(data, offset)?;
1369 offset += 8;
1370
1371 let settled_output_amount = read_u64_le(data, offset)?;
1372 offset += 8;
1373
1374 let decreased_amount = read_u64_le(data, offset)?;
1375
1376 Some(DexEvent::RaydiumClmmDecreaseLimitOrder(RaydiumClmmDecreaseLimitOrderEvent {
1377 metadata,
1378 pool_id,
1379 limit_order,
1380 zero_for_one,
1381 tick_index,
1382 total_amount,
1383 filled_amount,
1384 settled_output_amount,
1385 decreased_amount,
1386 }))
1387}
1388
1389#[inline(always)]
1391pub fn parse_settle_limit_order_from_data(
1392 data: &[u8],
1393 metadata: EventMetadata,
1394) -> Option<DexEvent> {
1395 let mut offset = 0;
1396
1397 let pool_id = read_pubkey(data, offset)?;
1398 offset += 32;
1399
1400 let limit_order = read_pubkey(data, offset)?;
1401 offset += 32;
1402
1403 let zero_for_one = read_bool(data, offset)?;
1404 offset += 1;
1405
1406 let tick_index = read_i32_le(data, offset)?;
1407 offset += 4;
1408
1409 let total_amount = read_u64_le(data, offset)?;
1410 offset += 8;
1411
1412 let filled_amount = read_u64_le(data, offset)?;
1413 offset += 8;
1414
1415 let settled_amount_out = read_u64_le(data, offset)?;
1416
1417 Some(DexEvent::RaydiumClmmSettleLimitOrder(RaydiumClmmSettleLimitOrderEvent {
1418 metadata,
1419 pool_id,
1420 limit_order,
1421 zero_for_one,
1422 tick_index,
1423 total_amount,
1424 filled_amount,
1425 settled_amount_out,
1426 }))
1427}
1428
1429#[inline(always)]
1431pub fn parse_update_reward_infos_from_data(
1432 data: &[u8],
1433 metadata: EventMetadata,
1434) -> Option<DexEvent> {
1435 let mut offset = 0;
1436 let mut reward_growth_global_x64 = [0u128; 3];
1437 for reward_growth in &mut reward_growth_global_x64 {
1438 *reward_growth = read_u128_le(data, offset)?;
1439 offset += 16;
1440 }
1441
1442 Some(DexEvent::RaydiumClmmUpdateRewardInfos(RaydiumClmmUpdateRewardInfosEvent {
1443 metadata,
1444 reward_growth_global_x64,
1445 }))
1446}
1447
1448#[inline(always)]
1450pub fn parse_create_pool_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
1451 let mut offset = 0;
1452
1453 let token_0_mint = read_pubkey(data, offset)?;
1454 offset += 32;
1455
1456 let token_1_mint = read_pubkey(data, offset)?;
1457 offset += 32;
1458
1459 let tick_spacing = read_u16_le(data, offset)?;
1460 offset += 2;
1461
1462 let pool = read_pubkey(data, offset)?;
1463 offset += 32;
1464
1465 let sqrt_price_x64 = read_u128_le(data, offset)?;
1466 offset += 16;
1467
1468 let tick = read_i32_le(data, offset)?;
1469 offset += 4;
1470
1471 let token_vault_0 = read_pubkey(data, offset)?;
1472 offset += 32;
1473
1474 let token_vault_1 = read_pubkey(data, offset)?;
1475
1476 Some(DexEvent::RaydiumClmmCreatePool(RaydiumClmmCreatePoolEvent {
1477 metadata,
1478 pool,
1479 token_0_mint,
1480 token_1_mint,
1481 tick_spacing,
1482 sqrt_price_x64,
1483 tick,
1484 token_vault_0,
1485 token_vault_1,
1486 fee_rate: 0,
1487 creator: Pubkey::default(),
1488 open_time: 0,
1489 }))
1490}
1491
1492#[inline(always)]
1494pub fn parse_collect_personal_fee_from_data(
1495 data: &[u8],
1496 metadata: EventMetadata,
1497) -> Option<DexEvent> {
1498 let mut offset = 0;
1499
1500 let position_nft_mint = read_pubkey(data, offset)?;
1501 offset += 32;
1502
1503 let recipient_token_account_0 = read_pubkey(data, offset)?;
1504 offset += 32;
1505
1506 let recipient_token_account_1 = read_pubkey(data, offset)?;
1507 offset += 32;
1508
1509 let amount_0 = read_u64_le(data, offset)?;
1510 offset += 8;
1511
1512 let amount_1 = read_u64_le(data, offset)?;
1513
1514 Some(DexEvent::RaydiumClmmCollectFee(RaydiumClmmCollectFeeEvent {
1515 metadata,
1516 pool_state: Pubkey::default(),
1517 position_nft_mint,
1518 recipient_token_account_0,
1519 recipient_token_account_1,
1520 amount_0,
1521 amount_1,
1522 }))
1523}
1524
1525#[inline(always)]
1527pub fn parse_collect_protocol_fee_from_data(
1528 data: &[u8],
1529 metadata: EventMetadata,
1530) -> Option<DexEvent> {
1531 let mut offset = 0;
1532
1533 let pool_state = read_pubkey(data, offset)?;
1534 offset += 32;
1535
1536 let recipient_token_account_0 = read_pubkey(data, offset)?;
1537 offset += 32;
1538
1539 let recipient_token_account_1 = read_pubkey(data, offset)?;
1540 offset += 32;
1541
1542 let amount_0 = read_u64_le(data, offset)?;
1543 offset += 8;
1544
1545 let amount_1 = read_u64_le(data, offset)?;
1546
1547 Some(DexEvent::RaydiumClmmCollectFee(RaydiumClmmCollectFeeEvent {
1548 metadata,
1549 pool_state,
1550 position_nft_mint: Pubkey::default(),
1551 recipient_token_account_0,
1552 recipient_token_account_1,
1553 amount_0,
1554 amount_1,
1555 }))
1556}
1557
1558#[inline(always)]
1560pub fn parse_collect_fee_from_data(data: &[u8], metadata: EventMetadata) -> Option<DexEvent> {
1561 parse_collect_personal_fee_from_data(data, metadata)
1562}
1563
1564#[cfg(test)]
1565mod tests {
1566 use super::*;
1567 use base64::{engine::general_purpose, Engine as _};
1568
1569 fn metadata() -> EventMetadata {
1570 EventMetadata {
1571 signature: Signature::default(),
1572 slot: 1,
1573 tx_index: 0,
1574 block_time_us: 0,
1575 grpc_recv_us: 0,
1576 recent_blockhash: None,
1577 }
1578 }
1579
1580 fn pk(seed: u8) -> Pubkey {
1581 Pubkey::new_from_array([seed; 32])
1582 }
1583
1584 fn push_pk(out: &mut Vec<u8>, key: Pubkey) {
1585 out.extend_from_slice(key.as_ref());
1586 }
1587
1588 fn program_data_log(raw: &[u8]) -> String {
1589 format!("Program data: {}", general_purpose::STANDARD.encode(raw))
1590 }
1591
1592 #[test]
1593 fn official_swap_event_discriminator_and_body_parse() {
1594 let pool = pk(1);
1595 let sender = pk(2);
1596 let token_account_0 = pk(3);
1597 let token_account_1 = pk(4);
1598 let mut raw = Vec::new();
1599 raw.extend_from_slice(&discriminators::SWAP);
1600 push_pk(&mut raw, pool);
1601 push_pk(&mut raw, sender);
1602 push_pk(&mut raw, token_account_0);
1603 push_pk(&mut raw, token_account_1);
1604 raw.extend_from_slice(&10u64.to_le_bytes());
1605 raw.extend_from_slice(&1u64.to_le_bytes());
1606 raw.extend_from_slice(&20u64.to_le_bytes());
1607 raw.extend_from_slice(&2u64.to_le_bytes());
1608 raw.push(1);
1609 raw.extend_from_slice(&123u128.to_le_bytes());
1610 raw.extend_from_slice(&456u128.to_le_bytes());
1611 raw.extend_from_slice(&(-77i32).to_le_bytes());
1612
1613 let event = parse_log(&program_data_log(&raw), Signature::default(), 1, 0, None, 0)
1614 .expect("swap event");
1615
1616 let DexEvent::RaydiumClmmSwap(swap) = event else {
1617 panic!("expected swap");
1618 };
1619 assert_eq!(swap.pool_state, pool);
1620 assert_eq!(swap.sender, sender);
1621 assert_eq!(swap.token_account_0, token_account_0);
1622 assert_eq!(swap.token_account_1, token_account_1);
1623 assert_eq!(swap.amount_0, 10);
1624 assert_eq!(swap.transfer_fee_0, 1);
1625 assert_eq!(swap.amount_1, 20);
1626 assert_eq!(swap.transfer_fee_1, 2);
1627 assert!(swap.zero_for_one);
1628 assert_eq!(swap.sqrt_price_x64, 123);
1629 assert_eq!(swap.liquidity, 456);
1630 assert_eq!(swap.tick, -77);
1631 }
1632
1633 #[test]
1634 fn instruction_swap_discriminator_is_not_treated_as_log_event() {
1635 let mut raw = Vec::new();
1636 raw.extend_from_slice(&[248, 198, 158, 145, 225, 117, 135, 200]);
1637 raw.resize(8 + 32 + 32 + 32 + 32 + 8 + 8 + 8 + 8 + 1 + 16 + 16 + 4, 0);
1638
1639 assert!(parse_log(&program_data_log(&raw), Signature::default(), 1, 0, None, 0).is_none());
1640 }
1641
1642 #[test]
1643 fn official_liquidity_and_create_events_parse() {
1644 let mut inc = Vec::new();
1645 push_pk(&mut inc, pk(5));
1646 inc.extend_from_slice(&100u128.to_le_bytes());
1647 inc.extend_from_slice(&11u64.to_le_bytes());
1648 inc.extend_from_slice(&22u64.to_le_bytes());
1649 inc.extend_from_slice(&3u64.to_le_bytes());
1650 inc.extend_from_slice(&4u64.to_le_bytes());
1651
1652 let DexEvent::RaydiumClmmIncreaseLiquidity(inc_event) =
1653 parse_increase_liquidity_from_data(&inc, metadata()).expect("increase")
1654 else {
1655 panic!("expected increase");
1656 };
1657 assert_eq!(inc_event.position_nft_mint, pk(5));
1658 assert_eq!(inc_event.liquidity, 100);
1659 assert_eq!(inc_event.amount_0, 11);
1660 assert_eq!(inc_event.amount_1, 22);
1661 assert_eq!(inc_event.amount_0_transfer_fee, 3);
1662 assert_eq!(inc_event.amount_1_transfer_fee, 4);
1663
1664 let mut dec = Vec::new();
1665 push_pk(&mut dec, pk(6));
1666 dec.extend_from_slice(&200u128.to_le_bytes());
1667 dec.extend_from_slice(&31u64.to_le_bytes());
1668 dec.extend_from_slice(&32u64.to_le_bytes());
1669 dec.extend_from_slice(&5u64.to_le_bytes());
1670 dec.extend_from_slice(&6u64.to_le_bytes());
1671 dec.extend_from_slice(
1672 &[7u64.to_le_bytes(), 8u64.to_le_bytes(), 9u64.to_le_bytes()].concat(),
1673 );
1674 dec.extend_from_slice(&10u64.to_le_bytes());
1675 dec.extend_from_slice(&11u64.to_le_bytes());
1676
1677 let DexEvent::RaydiumClmmDecreaseLiquidity(dec_event) =
1678 parse_decrease_liquidity_from_data(&dec, metadata()).expect("decrease")
1679 else {
1680 panic!("expected decrease");
1681 };
1682 assert_eq!(dec_event.position_nft_mint, pk(6));
1683 assert_eq!(dec_event.liquidity, 200);
1684 assert_eq!(dec_event.decrease_amount_0, 31);
1685 assert_eq!(dec_event.decrease_amount_1, 32);
1686 assert_eq!(dec_event.fee_amount_0, 5);
1687 assert_eq!(dec_event.fee_amount_1, 6);
1688 assert_eq!(dec_event.reward_amounts, [7, 8, 9]);
1689 assert_eq!(dec_event.transfer_fee_0, 10);
1690 assert_eq!(dec_event.transfer_fee_1, 11);
1691
1692 let mut create = Vec::new();
1693 push_pk(&mut create, pk(7));
1694 push_pk(&mut create, pk(8));
1695 create.extend_from_slice(&64u16.to_le_bytes());
1696 push_pk(&mut create, pk(9));
1697 create.extend_from_slice(&333u128.to_le_bytes());
1698 create.extend_from_slice(&(-12i32).to_le_bytes());
1699 push_pk(&mut create, pk(10));
1700 push_pk(&mut create, pk(11));
1701
1702 let DexEvent::RaydiumClmmCreatePool(create_event) =
1703 parse_create_pool_from_data(&create, metadata()).expect("create")
1704 else {
1705 panic!("expected create");
1706 };
1707 assert_eq!(create_event.token_0_mint, pk(7));
1708 assert_eq!(create_event.token_1_mint, pk(8));
1709 assert_eq!(create_event.tick_spacing, 64);
1710 assert_eq!(create_event.pool, pk(9));
1711 assert_eq!(create_event.sqrt_price_x64, 333);
1712 assert_eq!(create_event.tick, -12);
1713 assert_eq!(create_event.token_vault_0, pk(10));
1714 assert_eq!(create_event.token_vault_1, pk(11));
1715 }
1716
1717 #[test]
1718 fn official_collect_and_liquidity_change_events_parse() {
1719 let mut personal = Vec::new();
1720 push_pk(&mut personal, pk(12));
1721 push_pk(&mut personal, pk(13));
1722 push_pk(&mut personal, pk(14));
1723 personal.extend_from_slice(&70u64.to_le_bytes());
1724 personal.extend_from_slice(&80u64.to_le_bytes());
1725
1726 let DexEvent::RaydiumClmmCollectFee(personal_event) =
1727 parse_collect_personal_fee_from_data(&personal, metadata()).expect("personal")
1728 else {
1729 panic!("expected personal collect");
1730 };
1731 assert_eq!(personal_event.position_nft_mint, pk(12));
1732 assert_eq!(personal_event.recipient_token_account_0, pk(13));
1733 assert_eq!(personal_event.recipient_token_account_1, pk(14));
1734
1735 let mut protocol = Vec::new();
1736 push_pk(&mut protocol, pk(15));
1737 push_pk(&mut protocol, pk(16));
1738 push_pk(&mut protocol, pk(17));
1739 protocol.extend_from_slice(&90u64.to_le_bytes());
1740 protocol.extend_from_slice(&100u64.to_le_bytes());
1741
1742 let DexEvent::RaydiumClmmCollectFee(protocol_event) =
1743 parse_collect_protocol_fee_from_data(&protocol, metadata()).expect("protocol")
1744 else {
1745 panic!("expected protocol collect");
1746 };
1747 assert_eq!(protocol_event.pool_state, pk(15));
1748 assert_eq!(protocol_event.recipient_token_account_0, pk(16));
1749 assert_eq!(protocol_event.recipient_token_account_1, pk(17));
1750
1751 let mut change = Vec::new();
1752 push_pk(&mut change, pk(18));
1753 change.extend_from_slice(&1i32.to_le_bytes());
1754 change.extend_from_slice(&(-10i32).to_le_bytes());
1755 change.extend_from_slice(&10i32.to_le_bytes());
1756 change.extend_from_slice(&1234u128.to_le_bytes());
1757 change.extend_from_slice(&5678u128.to_le_bytes());
1758
1759 let DexEvent::RaydiumClmmLiquidityChange(change_event) =
1760 parse_liquidity_change_from_data(&change, metadata()).expect("liquidity change")
1761 else {
1762 panic!("expected liquidity change");
1763 };
1764 assert_eq!(change_event.pool_state, pk(18));
1765 assert_eq!(change_event.tick, 1);
1766 assert_eq!(change_event.tick_lower, -10);
1767 assert_eq!(change_event.tick_upper, 10);
1768 assert_eq!(change_event.liquidity_before, 1234);
1769 assert_eq!(change_event.liquidity_after, 5678);
1770 }
1771
1772 #[test]
1773 fn official_dynamic_fee_and_limit_order_events_parse() {
1774 let mut config = Vec::new();
1775 config.extend_from_slice(&3u16.to_le_bytes());
1776 push_pk(&mut config, pk(21));
1777 config.extend_from_slice(&100u32.to_le_bytes());
1778 config.extend_from_slice(&200u32.to_le_bytes());
1779 config.extend_from_slice(&64u16.to_le_bytes());
1780 config.extend_from_slice(&300u32.to_le_bytes());
1781 push_pk(&mut config, pk(22));
1782
1783 let DexEvent::RaydiumClmmConfigChange(config_event) =
1784 parse_config_change_from_data(&config, metadata()).expect("config")
1785 else {
1786 panic!("expected config change");
1787 };
1788 assert_eq!(config_event.index, 3);
1789 assert_eq!(config_event.owner, pk(21));
1790 assert_eq!(config_event.fund_owner, pk(22));
1791
1792 let mut personal_position = Vec::new();
1793 push_pk(&mut personal_position, pk(23));
1794 push_pk(&mut personal_position, pk(24));
1795 push_pk(&mut personal_position, pk(25));
1796 personal_position.extend_from_slice(&(-4i32).to_le_bytes());
1797 personal_position.extend_from_slice(&8i32.to_le_bytes());
1798 personal_position.extend_from_slice(&900u128.to_le_bytes());
1799 personal_position.extend_from_slice(&31u64.to_le_bytes());
1800 personal_position.extend_from_slice(&32u64.to_le_bytes());
1801 personal_position.extend_from_slice(&1u64.to_le_bytes());
1802 personal_position.extend_from_slice(&2u64.to_le_bytes());
1803
1804 let DexEvent::RaydiumClmmCreatePersonalPosition(position_event) =
1805 parse_create_personal_position_from_data(&personal_position, metadata())
1806 .expect("personal position")
1807 else {
1808 panic!("expected personal position");
1809 };
1810 assert_eq!(position_event.pool_state, pk(23));
1811 assert_eq!(position_event.minter, pk(24));
1812 assert_eq!(position_event.nft_owner, pk(25));
1813 assert_eq!(position_event.liquidity, 900);
1814
1815 let mut open_order = Vec::new();
1816 push_pk(&mut open_order, pk(26));
1817 push_pk(&mut open_order, pk(27));
1818 open_order.push(1);
1819 open_order.extend_from_slice(&(-40i32).to_le_bytes());
1820 open_order.extend_from_slice(&1_000u64.to_le_bytes());
1821 open_order.extend_from_slice(&5u64.to_le_bytes());
1822
1823 let DexEvent::RaydiumClmmOpenLimitOrder(open_event) =
1824 parse_open_limit_order_from_data(&open_order, metadata()).expect("open order")
1825 else {
1826 panic!("expected open limit order");
1827 };
1828 assert_eq!(open_event.pool_id, pk(26));
1829 assert_eq!(open_event.limit_order, pk(27));
1830 assert!(open_event.zero_for_one);
1831 assert_eq!(open_event.tick_index, -40);
1832 assert_eq!(open_event.total_amount, 1_000);
1833 assert_eq!(open_event.transfer_fee, 5);
1834
1835 let mut settle_order = Vec::new();
1836 push_pk(&mut settle_order, pk(28));
1837 push_pk(&mut settle_order, pk(29));
1838 settle_order.push(0);
1839 settle_order.extend_from_slice(&41i32.to_le_bytes());
1840 settle_order.extend_from_slice(&2_000u64.to_le_bytes());
1841 settle_order.extend_from_slice(&1_500u64.to_le_bytes());
1842 settle_order.extend_from_slice(&3_000u64.to_le_bytes());
1843
1844 let DexEvent::RaydiumClmmSettleLimitOrder(settle_event) =
1845 parse_settle_limit_order_from_data(&settle_order, metadata()).expect("settle order")
1846 else {
1847 panic!("expected settle limit order");
1848 };
1849 assert_eq!(settle_event.pool_id, pk(28));
1850 assert!(!settle_event.zero_for_one);
1851 assert_eq!(settle_event.settled_amount_out, 3_000);
1852
1853 let mut reward = Vec::new();
1854 reward.extend_from_slice(&10u128.to_le_bytes());
1855 reward.extend_from_slice(&20u128.to_le_bytes());
1856 reward.extend_from_slice(&30u128.to_le_bytes());
1857
1858 let DexEvent::RaydiumClmmUpdateRewardInfos(reward_event) =
1859 parse_update_reward_infos_from_data(&reward, metadata()).expect("reward")
1860 else {
1861 panic!("expected reward infos");
1862 };
1863 assert_eq!(reward_event.reward_growth_global_x64, [10, 20, 30]);
1864 }
1865}