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