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