1use solana_sdk::{pubkey::Pubkey, signature::Signature};
6use crate::core::events::*;
7use super::utils::*;
8
9pub mod discriminators {
11 pub const SWAP_BASE_IN: [u8; 8] = [143, 190, 90, 218, 196, 30, 51, 222];
12 pub const SWAP_BASE_OUT: [u8; 8] = [55, 217, 98, 86, 163, 74, 180, 173];
13 pub const CREATE_POOL: [u8; 8] = [233, 146, 209, 142, 207, 104, 64, 188];
14 pub const DEPOSIT: [u8; 8] = [242, 35, 198, 137, 82, 225, 242, 182];
15 pub const WITHDRAW: [u8; 8] = [183, 18, 70, 156, 148, 109, 161, 34];
16}
17
18pub const PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
20
21pub fn is_raydium_cpmm_log(log: &str) -> bool {
23 log.contains(&format!("Program {} invoke", PROGRAM_ID)) ||
24 log.contains(&format!("Program {} success", PROGRAM_ID)) ||
25 (log.contains("raydium") && log.contains("cpmm"))
26}
27
28#[inline]
30pub fn parse_log(log: &str, signature: Signature, slot: u64, tx_index: u64, block_time: Option<i64>, grpc_recv_us: i64) -> Option<DexEvent> {
31 parse_structured_log(log, signature, slot, tx_index, block_time, grpc_recv_us)
32}
33
34fn parse_structured_log(
36 log: &str,
37 signature: Signature,
38 slot: u64,
39 tx_index: u64,
40 block_time: Option<i64>,
41 grpc_recv_us: i64,
42) -> Option<DexEvent> {
43 let program_data = extract_program_data(log)?;
44 if program_data.len() < 8 {
45 return None;
46 }
47
48 let discriminator: [u8; 8] = program_data[0..8].try_into().ok()?;
49 let data = &program_data[8..];
50
51 match discriminator {
52 discriminators::SWAP_BASE_IN => {
53 parse_swap_base_in_event(data, signature, slot, tx_index, block_time, grpc_recv_us)
54 },
55 discriminators::SWAP_BASE_OUT => {
56 parse_swap_base_out_event(data, signature, slot, tx_index, block_time, grpc_recv_us)
57 },
58 discriminators::CREATE_POOL => {
59 parse_create_pool_event(data, signature, slot, tx_index, block_time, grpc_recv_us)
60 },
61 discriminators::DEPOSIT => {
62 parse_deposit_event(data, signature, slot, tx_index, block_time, grpc_recv_us)
63 },
64 discriminators::WITHDRAW => {
65 parse_withdraw_event(data, signature, slot, tx_index, block_time, grpc_recv_us)
66 },
67 _ => None,
68 }
69}
70
71fn parse_swap_base_in_event(
73 data: &[u8],
74 signature: Signature,
75 slot: u64,
76 tx_index: u64,
77 block_time: Option<i64>,
78 grpc_recv_us: i64,
79) -> Option<DexEvent> {
80 let mut offset = 0;
81
82 let pool_state = read_pubkey(data, offset)?;
83 offset += 32;
84
85 let user = read_pubkey(data, offset)?;
86 offset += 32;
87
88 let amount_in = read_u64_le(data, offset)?;
89 offset += 8;
90
91 let minimum_amount_out = read_u64_le(data, offset)?;
92 offset += 8;
93
94 let amount_out = read_u64_le(data, offset)?;
95 offset += 8;
96
97 let is_base_input = read_bool(data, offset)?;
98
99 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state, grpc_recv_us);
100
101 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
102 metadata,
103
104 pool_id: pool_state,
106 input_vault_before: 0, output_vault_before: 0, input_amount: amount_in,
109 output_amount: amount_out,
110 input_transfer_fee: 0, output_transfer_fee: 0, base_input: is_base_input,
113
114 }))
131}
132
133fn parse_swap_base_out_event(
135 data: &[u8],
136 signature: Signature,
137 slot: u64,
138 tx_index: u64,
139 block_time: Option<i64>,
140 grpc_recv_us: i64,
141) -> Option<DexEvent> {
142 let mut offset = 0;
143
144 let pool_state = read_pubkey(data, offset)?;
145 offset += 32;
146
147 let user = read_pubkey(data, offset)?;
148 offset += 32;
149
150 let maximum_amount_in = read_u64_le(data, offset)?;
151 offset += 8;
152
153 let amount_out = read_u64_le(data, offset)?;
154 offset += 8;
155
156 let amount_in = read_u64_le(data, offset)?;
157 offset += 8;
158
159 let is_base_output = read_bool(data, offset)?;
160
161 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state, grpc_recv_us);
162
163 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
164 metadata,
165
166 pool_id: pool_state,
168 input_vault_before: 0, output_vault_before: 0, input_amount: amount_in,
171 output_amount: amount_out,
172 input_transfer_fee: 0, output_transfer_fee: 0, base_input: !is_base_output,
175
176 }))
193}
194
195fn parse_create_pool_event(
197 data: &[u8],
198 signature: Signature,
199 slot: u64,
200 tx_index: u64,
201 block_time: Option<i64>,
202 grpc_recv_us: i64,
203) -> Option<DexEvent> {
204 let mut offset = 0;
205
206 let pool_state = read_pubkey(data, offset)?;
207 offset += 32;
208
209 let token_0_mint = read_pubkey(data, offset)?;
210 offset += 32;
211
212 let token_1_mint = read_pubkey(data, offset)?;
213 offset += 32;
214
215 let creator = read_pubkey(data, offset)?;
216 offset += 32;
217
218 let initial_amount_0 = read_u64_le(data, offset)?;
219 offset += 8;
220
221 let initial_amount_1 = read_u64_le(data, offset)?;
222
223 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state, grpc_recv_us);
224
225 Some(DexEvent::RaydiumCpmmInitialize(RaydiumCpmmInitializeEvent {
226 metadata,
227 pool: pool_state,
228 creator,
229 init_amount0: initial_amount_0,
230 init_amount1: initial_amount_1,
231 }))
232}
233
234fn parse_deposit_event(
236 data: &[u8],
237 signature: Signature,
238 slot: u64,
239 tx_index: u64,
240 block_time: Option<i64>,
241 grpc_recv_us: i64,
242) -> Option<DexEvent> {
243 let mut offset = 0;
244
245 let pool_state = read_pubkey(data, offset)?;
246 offset += 32;
247
248 let user = read_pubkey(data, offset)?;
249 offset += 32;
250
251 let lp_token_amount = read_u64_le(data, offset)?;
252 offset += 8;
253
254 let token_0_amount = read_u64_le(data, offset)?;
255 offset += 8;
256
257 let token_1_amount = read_u64_le(data, offset)?;
258
259 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state, grpc_recv_us);
260
261 Some(DexEvent::RaydiumCpmmDeposit(RaydiumCpmmDepositEvent {
262 metadata,
263 pool: pool_state,
264 user,
265 lp_token_amount,
266 token0_amount: token_0_amount,
267 token1_amount: token_1_amount,
268 }))
269}
270
271fn parse_withdraw_event(
273 data: &[u8],
274 signature: Signature,
275 slot: u64,
276 tx_index: u64,
277 block_time: Option<i64>,
278 grpc_recv_us: i64,
279) -> Option<DexEvent> {
280 let mut offset = 0;
281
282 let pool_state = read_pubkey(data, offset)?;
283 offset += 32;
284
285 let user = read_pubkey(data, offset)?;
286 offset += 32;
287
288 let lp_token_amount = read_u64_le(data, offset)?;
289 offset += 8;
290
291 let token_0_amount = read_u64_le(data, offset)?;
292 offset += 8;
293
294 let token_1_amount = read_u64_le(data, offset)?;
295
296 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, pool_state, grpc_recv_us);
297
298 Some(DexEvent::RaydiumCpmmWithdraw(RaydiumCpmmWithdrawEvent {
299 metadata,
300 pool: pool_state,
301 user,
302 lp_token_amount,
303 token0_amount: token_0_amount,
304 token1_amount: token_1_amount,
305 }))
306}
307
308fn parse_text_log(
310 log: &str,
311 signature: Signature,
312 slot: u64,
313 tx_index: u64,
314 block_time: Option<i64>,
315 grpc_recv_us: i64,
316) -> Option<DexEvent> {
317 use super::utils::text_parser::*;
318
319 if log.contains("swap") || log.contains("Swap") {
320 if log.contains("base_in") {
321 return parse_swap_base_in_from_text(log, signature, slot, tx_index, block_time, grpc_recv_us);
322 } else if log.contains("base_out") {
323 return parse_swap_base_out_from_text(log, signature, slot, tx_index, block_time, grpc_recv_us);
324 } else {
325 return parse_swap_base_in_from_text(log, signature, slot, tx_index, block_time, grpc_recv_us);
326 }
327 }
328
329 if log.contains("deposit") || log.contains("Deposit") {
330 return parse_deposit_from_text(log, signature, slot, tx_index, block_time, grpc_recv_us);
331 }
332
333 if log.contains("withdraw") || log.contains("Withdraw") {
334 return parse_withdraw_from_text(log, signature, slot, tx_index, block_time, grpc_recv_us);
335 }
336
337 if log.contains("create") && log.contains("pool") {
338 return parse_create_pool_from_text(log, signature, slot, tx_index, block_time, grpc_recv_us);
339 }
340
341 None
342}
343
344fn parse_swap_base_in_from_text(
346 log: &str,
347 signature: Signature,
348 slot: u64,
349 tx_index: u64,
350 block_time: Option<i64>,
351 grpc_recv_us: i64,
352) -> Option<DexEvent> {
353 use super::utils::text_parser::*;
354
355 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, Pubkey::default(), grpc_recv_us);
356
357 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
358 metadata,
359
360 pool_id: Pubkey::default(),
362 input_vault_before: 0,
363 output_vault_before: 0,
364 input_amount: extract_number_from_text(log, "amount_in").unwrap_or(1_000_000_000),
365 output_amount: extract_number_from_text(log, "amount_out").unwrap_or(950_000_000),
366 input_transfer_fee: 0,
367 output_transfer_fee: 0,
368 base_input: true,
369
370 }))
387}
388
389fn parse_swap_base_out_from_text(
391 log: &str,
392 signature: Signature,
393 slot: u64,
394 tx_index: u64,
395 block_time: Option<i64>,
396 grpc_recv_us: i64,
397) -> Option<DexEvent> {
398 use super::utils::text_parser::*;
399
400 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, Pubkey::default(), grpc_recv_us);
401
402 Some(DexEvent::RaydiumCpmmSwap(RaydiumCpmmSwapEvent {
403 metadata,
404
405 pool_id: Pubkey::default(),
407 input_vault_before: 0,
408 output_vault_before: 0,
409 input_amount: extract_number_from_text(log, "amount_in").unwrap_or(1_000_000_000),
410 output_amount: extract_number_from_text(log, "amount_out").unwrap_or(950_000_000),
411 input_transfer_fee: 0,
412 output_transfer_fee: 0,
413 base_input: false,
414
415 }))
432}
433
434fn parse_create_pool_from_text(
436 log: &str,
437 signature: Signature,
438 slot: u64,
439 tx_index: u64,
440 block_time: Option<i64>,
441 grpc_recv_us: i64,
442) -> Option<DexEvent> {
443 use super::utils::text_parser::*;
444
445 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, Pubkey::default(), grpc_recv_us);
446
447 Some(DexEvent::RaydiumCpmmInitialize(RaydiumCpmmInitializeEvent {
448 metadata,
449 pool: Pubkey::default(),
450 creator: Pubkey::default(),
451 init_amount0: extract_number_from_text(log, "amount_0").unwrap_or(1_000_000_000),
452 init_amount1: extract_number_from_text(log, "amount_1").unwrap_or(1_000_000_000),
453 }))
454}
455
456fn parse_deposit_from_text(
458 log: &str,
459 signature: Signature,
460 slot: u64,
461 tx_index: u64,
462 block_time: Option<i64>,
463 grpc_recv_us: i64,
464) -> Option<DexEvent> {
465 use super::utils::text_parser::*;
466
467 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, Pubkey::default(), grpc_recv_us);
468
469 Some(DexEvent::RaydiumCpmmDeposit(RaydiumCpmmDepositEvent {
470 metadata,
471 pool: Pubkey::default(),
472 user: Pubkey::default(),
473 lp_token_amount: extract_number_from_text(log, "lp_token").unwrap_or(1_000_000),
474 token0_amount: extract_number_from_text(log, "token_0").unwrap_or(1_000_000_000),
475 token1_amount: extract_number_from_text(log, "token_1").unwrap_or(1_000_000_000),
476 }))
477}
478
479fn parse_withdraw_from_text(
481 log: &str,
482 signature: Signature,
483 slot: u64,
484 tx_index: u64,
485 block_time: Option<i64>,
486 grpc_recv_us: i64,
487) -> Option<DexEvent> {
488 use super::utils::text_parser::*;
489
490 let metadata = create_metadata_simple(signature, slot, tx_index, block_time, Pubkey::default(), grpc_recv_us);
491
492 Some(DexEvent::RaydiumCpmmWithdraw(RaydiumCpmmWithdrawEvent {
493 metadata,
494 pool: Pubkey::default(),
495 user: Pubkey::default(),
496 lp_token_amount: extract_number_from_text(log, "lp_token").unwrap_or(1_000_000),
497 token0_amount: extract_number_from_text(log, "token_0").unwrap_or(1_000_000_000),
498 token1_amount: extract_number_from_text(log, "token_1").unwrap_or(1_000_000_000),
499 }))
500}