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