1use serde::{Deserialize, Serialize};
2use yellowstone_grpc_proto::geyser::{
3 subscribe_request_filter_accounts_filter::Filter as AccountsFilterOneof,
4 subscribe_request_filter_accounts_filter_memcmp::Data as MemcmpDataOneof,
5 SubscribeRequestFilterAccountsFilter, SubscribeRequestFilterAccountsFilterMemcmp,
6};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
10pub enum OrderMode {
11 #[default]
13 Unordered,
14 Ordered,
18 StreamingOrdered,
22 MicroBatch,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct ClientConfig {
30 pub enable_metrics: bool,
32 pub connection_timeout_ms: u64,
34 pub request_timeout_ms: u64,
36 pub enable_tls: bool,
38 pub max_retries: u32,
39 pub retry_delay_ms: u64,
40 pub max_concurrent_streams: u32,
41 pub keep_alive_interval_ms: u64,
42 pub keep_alive_timeout_ms: u64,
43 pub buffer_size: usize,
44 pub order_mode: OrderMode,
46 pub order_timeout_ms: u64,
49 pub micro_batch_us: u64,
52}
53
54impl Default for ClientConfig {
55 fn default() -> Self {
56 Self {
57 enable_metrics: false,
58 connection_timeout_ms: 8000,
59 request_timeout_ms: 15000,
60 enable_tls: true,
61 max_retries: 3,
62 retry_delay_ms: 1000,
63 max_concurrent_streams: 100,
64 keep_alive_interval_ms: 30000,
65 keep_alive_timeout_ms: 5000,
66 buffer_size: 100_000,
67 order_mode: OrderMode::Unordered,
68 order_timeout_ms: 100,
69 micro_batch_us: 100, }
71 }
72}
73
74impl ClientConfig {
75 pub fn low_latency() -> Self {
76 Self {
77 enable_metrics: false,
78 connection_timeout_ms: 5000,
79 request_timeout_ms: 10000,
80 enable_tls: true,
81 max_retries: 1,
82 retry_delay_ms: 100,
83 max_concurrent_streams: 200,
84 keep_alive_interval_ms: 10000,
85 keep_alive_timeout_ms: 2000,
86 buffer_size: 100_000,
87 order_mode: OrderMode::Unordered,
88 order_timeout_ms: 50,
89 micro_batch_us: 50, }
91 }
92
93 pub fn high_throughput() -> Self {
94 Self {
95 enable_metrics: true,
96 connection_timeout_ms: 10000,
97 request_timeout_ms: 30000,
98 enable_tls: true,
99 max_retries: 5,
100 retry_delay_ms: 2000,
101 max_concurrent_streams: 500,
102 keep_alive_interval_ms: 60000,
103 keep_alive_timeout_ms: 10000,
104 buffer_size: 200_000,
105 order_mode: OrderMode::Unordered,
106 order_timeout_ms: 200,
107 micro_batch_us: 200, }
109 }
110}
111
112#[derive(Debug, Clone)]
113pub struct TransactionFilter {
114 pub account_include: Vec<String>,
115 pub account_exclude: Vec<String>,
116 pub account_required: Vec<String>,
117}
118
119impl TransactionFilter {
120 pub fn new() -> Self {
121 Self {
122 account_include: Vec::new(),
123 account_exclude: Vec::new(),
124 account_required: Vec::new(),
125 }
126 }
127
128 pub fn include_account(mut self, account: impl Into<String>) -> Self {
129 self.account_include.push(account.into());
130 self
131 }
132
133 pub fn exclude_account(mut self, account: impl Into<String>) -> Self {
134 self.account_exclude.push(account.into());
135 self
136 }
137
138 pub fn require_account(mut self, account: impl Into<String>) -> Self {
139 self.account_required.push(account.into());
140 self
141 }
142
143 pub fn from_program_ids(program_ids: Vec<String>) -> Self {
145 Self {
146 account_include: program_ids,
147 account_exclude: Vec::new(),
148 account_required: Vec::new(),
149 }
150 }
151}
152
153impl Default for TransactionFilter {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159#[derive(Debug, Clone)]
160pub struct AccountFilter {
161 pub account: Vec<String>,
162 pub owner: Vec<String>,
163 pub filters: Vec<SubscribeRequestFilterAccountsFilter>,
164}
165
166impl AccountFilter {
167 pub fn new() -> Self {
168 Self { account: Vec::new(), owner: Vec::new(), filters: Vec::new() }
169 }
170
171 pub fn add_account(mut self, account: impl Into<String>) -> Self {
172 self.account.push(account.into());
173 self
174 }
175
176 pub fn add_owner(mut self, owner: impl Into<String>) -> Self {
177 self.owner.push(owner.into());
178 self
179 }
180
181 pub fn add_filter(mut self, filter: SubscribeRequestFilterAccountsFilter) -> Self {
182 self.filters.push(filter);
183 self
184 }
185
186 pub fn from_program_owners(program_ids: Vec<String>) -> Self {
188 Self { account: Vec::new(), owner: program_ids, filters: Vec::new() }
189 }
190}
191
192impl Default for AccountFilter {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198#[inline]
201pub fn account_filter_memcmp(offset: u64, bytes: Vec<u8>) -> SubscribeRequestFilterAccountsFilter {
202 SubscribeRequestFilterAccountsFilter {
203 filter: Some(AccountsFilterOneof::Memcmp(SubscribeRequestFilterAccountsFilterMemcmp {
204 offset,
205 data: Some(MemcmpDataOneof::Bytes(bytes)),
206 })),
207 }
208}
209
210#[derive(Debug, Clone)]
211pub struct AccountFilterData {
212 pub memcmp: Option<AccountFilterMemcmp>,
213 pub datasize: Option<u64>,
214}
215
216#[derive(Debug, Clone)]
217pub struct AccountFilterMemcmp {
218 pub offset: u64,
219 pub bytes: Vec<u8>,
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
223pub enum Protocol {
224 PumpFun,
225 PumpSwap,
226 PumpFees,
227 Bonk,
229 RaydiumLaunchpad,
230 RaydiumCpmm,
231 RaydiumClmm,
232 RaydiumAmmV4,
233 OrcaWhirlpool,
234 MeteoraPools,
235 MeteoraDammV2,
236 MeteoraDlmm,
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq)]
240pub enum EventType {
241 BlockMeta,
243
244 BonkTrade,
246 BonkPoolCreate,
247 BonkMigrateAmm,
248
249 PumpFunTrade, PumpFunBuy, PumpFunSell, PumpFunBuyExactSolIn, PumpFunCreate,
255 PumpFunCreateV2, PumpFunComplete,
257 PumpFunMigrate,
258 PumpFeesCreateFeeSharingConfig,
260 PumpFeesInitializeFeeConfig,
261 PumpFeesResetFeeSharingConfig,
262 PumpFeesRevokeFeeSharingAuthority,
263 PumpFeesTransferFeeSharingAuthority,
264 PumpFeesUpdateAdmin,
265 PumpFeesUpdateFeeConfig,
266 PumpFeesUpdateFeeShares,
267 PumpFeesUpsertFeeTiers,
268 PumpFunMigrateBondingCurveCreator,
270
271 PumpSwapTrade,
273 PumpSwapBuy,
274 PumpSwapSell,
275 PumpSwapCreatePool,
276 PumpSwapLiquidityAdded,
277 PumpSwapLiquidityRemoved,
278 RaydiumCpmmSwap,
283 RaydiumCpmmDeposit,
284 RaydiumCpmmWithdraw,
285 RaydiumCpmmInitialize,
286
287 RaydiumClmmSwap,
289 RaydiumClmmCreatePool,
290 RaydiumClmmOpenPosition,
291 RaydiumClmmClosePosition,
292 RaydiumClmmIncreaseLiquidity,
293 RaydiumClmmDecreaseLiquidity,
294 RaydiumClmmOpenPositionWithTokenExtNft,
295 RaydiumClmmCollectFee,
296
297 RaydiumAmmV4Swap,
299 RaydiumAmmV4Deposit,
300 RaydiumAmmV4Withdraw,
301 RaydiumAmmV4Initialize2,
302 RaydiumAmmV4WithdrawPnl,
303
304 OrcaWhirlpoolSwap,
306 OrcaWhirlpoolLiquidityIncreased,
307 OrcaWhirlpoolLiquidityDecreased,
308 OrcaWhirlpoolPoolInitialized,
309
310 MeteoraPoolsSwap,
312 MeteoraPoolsAddLiquidity,
313 MeteoraPoolsRemoveLiquidity,
314 MeteoraPoolsBootstrapLiquidity,
315 MeteoraPoolsPoolCreated,
316 MeteoraPoolsSetPoolFees,
317
318 MeteoraDammV2Swap,
320 MeteoraDammV2AddLiquidity,
321 MeteoraDammV2RemoveLiquidity,
322 MeteoraDammV2CreatePosition,
324 MeteoraDammV2ClosePosition,
325 MeteoraDlmmSwap,
332 MeteoraDlmmAddLiquidity,
333 MeteoraDlmmRemoveLiquidity,
334 MeteoraDlmmInitializePool,
335 MeteoraDlmmInitializeBinArray,
336 MeteoraDlmmCreatePosition,
337 MeteoraDlmmClosePosition,
338 MeteoraDlmmClaimFee,
339
340 TokenAccount,
342 NonceAccount,
343 AccountPumpFunGlobal,
344 AccountPumpFunBondingCurve,
345 AccountPumpFunFeeConfig,
346 AccountPumpFunSharingConfig,
347 AccountPumpFunGlobalVolumeAccumulator,
348 AccountPumpFunUserVolumeAccumulator,
349
350 AccountPumpSwapGlobalConfig,
351 AccountPumpSwapPool,
352}
353
354#[derive(Debug, Clone)]
355pub struct EventTypeFilter {
356 pub include_only: Option<Vec<EventType>>,
357 pub exclude_types: Option<Vec<EventType>>,
358}
359
360impl EventTypeFilter {
361 pub fn include_only(types: Vec<EventType>) -> Self {
362 Self { include_only: Some(types), exclude_types: None }
363 }
364
365 pub fn exclude_types(types: Vec<EventType>) -> Self {
366 Self { include_only: None, exclude_types: Some(types) }
367 }
368
369 #[inline]
370 fn includes_group<F>(&self, mut is_group: F) -> bool
371 where
372 F: FnMut(&EventType) -> bool,
373 {
374 if let Some(ref include_only) = self.include_only {
375 return include_only.iter().any(&mut is_group);
376 }
377 true
381 }
382
383 pub fn should_include(&self, event_type: EventType) -> bool {
384 if let Some(ref include_only) = self.include_only {
385 if include_only.contains(&event_type) {
387 return true;
388 }
389 if event_type == EventType::PumpFunTrade {
393 return include_only.iter().any(|t| {
394 matches!(
395 t,
396 EventType::PumpFunBuy
397 | EventType::PumpFunSell
398 | EventType::PumpFunBuyExactSolIn
399 )
400 });
401 }
402 if matches!(
403 event_type,
404 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
405 ) {
406 return include_only.contains(&EventType::PumpFunTrade);
407 }
408 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell) {
409 return include_only.contains(&EventType::PumpSwapTrade);
410 }
411 return false;
412 }
413
414 if let Some(ref exclude_types) = self.exclude_types {
415 if exclude_types.contains(&event_type) {
416 return false;
417 }
418 if matches!(
419 event_type,
420 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
421 ) && exclude_types.contains(&EventType::PumpFunTrade)
422 {
423 return false;
424 }
425 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell)
426 && exclude_types.contains(&EventType::PumpSwapTrade)
427 {
428 return false;
429 }
430 return true;
431 }
432
433 true
434 }
435
436 pub fn should_include_dex_event(&self, event: &crate::core::events::DexEvent) -> bool {
437 let Some(event_type) = event_type_from_dex_event(event) else { return true };
438 self.should_include(event_type)
439 }
440
441 #[inline]
442 pub fn includes_pumpfun(&self) -> bool {
443 self.includes_group(|t| {
444 matches!(
445 t,
446 EventType::PumpFunTrade
447 | EventType::PumpFunBuy
448 | EventType::PumpFunSell
449 | EventType::PumpFunBuyExactSolIn
450 | EventType::PumpFunCreate
451 | EventType::PumpFunCreateV2
452 | EventType::PumpFunComplete
453 | EventType::PumpFunMigrate
454 | EventType::PumpFunMigrateBondingCurveCreator
455 | EventType::AccountPumpFunGlobal
456 | EventType::AccountPumpFunBondingCurve
457 | EventType::AccountPumpFunFeeConfig
458 | EventType::AccountPumpFunSharingConfig
459 | EventType::AccountPumpFunGlobalVolumeAccumulator
460 | EventType::AccountPumpFunUserVolumeAccumulator
461 )
462 })
463 }
464
465 #[inline]
466 pub fn includes_meteora_damm_v2(&self) -> bool {
467 self.includes_group(|t| {
468 matches!(
469 t,
470 EventType::MeteoraDammV2Swap
471 | EventType::MeteoraDammV2AddLiquidity
472 | EventType::MeteoraDammV2CreatePosition
473 | EventType::MeteoraDammV2ClosePosition
474 | EventType::MeteoraDammV2RemoveLiquidity
475 )
476 })
477 }
478
479 #[inline]
480 pub fn includes_pump_fees(&self) -> bool {
481 self.includes_group(|t| {
482 matches!(
483 t,
484 EventType::PumpFeesCreateFeeSharingConfig
485 | EventType::PumpFeesInitializeFeeConfig
486 | EventType::PumpFeesResetFeeSharingConfig
487 | EventType::PumpFeesRevokeFeeSharingAuthority
488 | EventType::PumpFeesTransferFeeSharingAuthority
489 | EventType::PumpFeesUpdateAdmin
490 | EventType::PumpFeesUpdateFeeConfig
491 | EventType::PumpFeesUpdateFeeShares
492 | EventType::PumpFeesUpsertFeeTiers
493 )
494 })
495 }
496
497 #[inline]
499 pub fn includes_pumpswap(&self) -> bool {
500 self.includes_group(|t| {
501 matches!(
502 t,
503 EventType::PumpSwapTrade
504 | EventType::PumpSwapBuy
505 | EventType::PumpSwapSell
506 | EventType::PumpSwapCreatePool
507 | EventType::PumpSwapLiquidityAdded
508 | EventType::PumpSwapLiquidityRemoved
509 )
510 })
511 }
512
513 #[inline]
515 pub fn includes_raydium_launchpad(&self) -> bool {
516 self.includes_group(|t| {
517 matches!(
518 t,
519 EventType::BonkTrade | EventType::BonkPoolCreate | EventType::BonkMigrateAmm
520 )
521 })
522 }
523
524 #[inline]
525 pub fn includes_raydium_cpmm(&self) -> bool {
526 self.includes_group(|t| {
527 matches!(
528 t,
529 EventType::RaydiumCpmmSwap
530 | EventType::RaydiumCpmmDeposit
531 | EventType::RaydiumCpmmWithdraw
532 | EventType::RaydiumCpmmInitialize
533 )
534 })
535 }
536
537 #[inline]
538 pub fn includes_raydium_clmm(&self) -> bool {
539 self.includes_group(|t| {
540 matches!(
541 t,
542 EventType::RaydiumClmmSwap
543 | EventType::RaydiumClmmCreatePool
544 | EventType::RaydiumClmmOpenPosition
545 | EventType::RaydiumClmmClosePosition
546 | EventType::RaydiumClmmIncreaseLiquidity
547 | EventType::RaydiumClmmDecreaseLiquidity
548 | EventType::RaydiumClmmOpenPositionWithTokenExtNft
549 | EventType::RaydiumClmmCollectFee
550 )
551 })
552 }
553
554 #[inline]
555 pub fn includes_raydium_amm_v4(&self) -> bool {
556 self.includes_group(|t| {
557 matches!(
558 t,
559 EventType::RaydiumAmmV4Swap
560 | EventType::RaydiumAmmV4Deposit
561 | EventType::RaydiumAmmV4Withdraw
562 | EventType::RaydiumAmmV4Initialize2
563 | EventType::RaydiumAmmV4WithdrawPnl
564 )
565 })
566 }
567
568 #[inline]
569 pub fn includes_orca_whirlpool(&self) -> bool {
570 self.includes_group(|t| {
571 matches!(
572 t,
573 EventType::OrcaWhirlpoolSwap
574 | EventType::OrcaWhirlpoolLiquidityIncreased
575 | EventType::OrcaWhirlpoolLiquidityDecreased
576 | EventType::OrcaWhirlpoolPoolInitialized
577 )
578 })
579 }
580
581 #[inline]
582 pub fn includes_meteora_pools(&self) -> bool {
583 self.includes_group(|t| {
584 matches!(
585 t,
586 EventType::MeteoraPoolsSwap
587 | EventType::MeteoraPoolsAddLiquidity
588 | EventType::MeteoraPoolsRemoveLiquidity
589 | EventType::MeteoraPoolsBootstrapLiquidity
590 | EventType::MeteoraPoolsPoolCreated
591 | EventType::MeteoraPoolsSetPoolFees
592 )
593 })
594 }
595
596 #[inline]
597 pub fn includes_meteora_dlmm(&self) -> bool {
598 self.includes_group(|t| {
599 matches!(
600 t,
601 EventType::MeteoraDlmmSwap
602 | EventType::MeteoraDlmmAddLiquidity
603 | EventType::MeteoraDlmmRemoveLiquidity
604 | EventType::MeteoraDlmmInitializePool
605 | EventType::MeteoraDlmmInitializeBinArray
606 | EventType::MeteoraDlmmCreatePosition
607 | EventType::MeteoraDlmmClosePosition
608 | EventType::MeteoraDlmmClaimFee
609 )
610 })
611 }
612}
613
614#[inline]
615pub fn event_type_from_dex_event(event: &crate::core::events::DexEvent) -> Option<EventType> {
616 use crate::core::events::DexEvent;
617 match event {
618 DexEvent::PumpFunCreate(_) => Some(EventType::PumpFunCreate),
619 DexEvent::PumpFunCreateV2(_) => Some(EventType::PumpFunCreateV2),
620 DexEvent::PumpFunTrade(_) => Some(EventType::PumpFunTrade),
621 DexEvent::PumpFunBuy(_) => Some(EventType::PumpFunBuy),
622 DexEvent::PumpFunSell(_) => Some(EventType::PumpFunSell),
623 DexEvent::PumpFunBuyExactSolIn(_) => Some(EventType::PumpFunBuyExactSolIn),
624 DexEvent::PumpFunMigrate(_) => Some(EventType::PumpFunMigrate),
625 DexEvent::PumpFeesCreateFeeSharingConfig(_) => {
626 Some(EventType::PumpFeesCreateFeeSharingConfig)
627 }
628 DexEvent::PumpFeesInitializeFeeConfig(_) => Some(EventType::PumpFeesInitializeFeeConfig),
629 DexEvent::PumpFeesResetFeeSharingConfig(_) => {
630 Some(EventType::PumpFeesResetFeeSharingConfig)
631 }
632 DexEvent::PumpFeesRevokeFeeSharingAuthority(_) => {
633 Some(EventType::PumpFeesRevokeFeeSharingAuthority)
634 }
635 DexEvent::PumpFeesTransferFeeSharingAuthority(_) => {
636 Some(EventType::PumpFeesTransferFeeSharingAuthority)
637 }
638 DexEvent::PumpFeesUpdateAdmin(_) => Some(EventType::PumpFeesUpdateAdmin),
639 DexEvent::PumpFeesUpdateFeeConfig(_) => Some(EventType::PumpFeesUpdateFeeConfig),
640 DexEvent::PumpFeesUpdateFeeShares(_) => Some(EventType::PumpFeesUpdateFeeShares),
641 DexEvent::PumpFeesUpsertFeeTiers(_) => Some(EventType::PumpFeesUpsertFeeTiers),
642 DexEvent::PumpFunMigrateBondingCurveCreator(_) => {
643 Some(EventType::PumpFunMigrateBondingCurveCreator)
644 }
645 DexEvent::PumpFunGlobalAccount(_) => Some(EventType::AccountPumpFunGlobal),
646 DexEvent::PumpFunBondingCurveAccount(_) => Some(EventType::AccountPumpFunBondingCurve),
647 DexEvent::PumpFunFeeConfigAccount(_) => Some(EventType::AccountPumpFunFeeConfig),
648 DexEvent::PumpFunSharingConfigAccount(_) => Some(EventType::AccountPumpFunSharingConfig),
649 DexEvent::PumpFunGlobalVolumeAccumulatorAccount(_) => {
650 Some(EventType::AccountPumpFunGlobalVolumeAccumulator)
651 }
652 DexEvent::PumpFunUserVolumeAccumulatorAccount(_) => {
653 Some(EventType::AccountPumpFunUserVolumeAccumulator)
654 }
655 DexEvent::PumpSwapTrade(_) => Some(EventType::PumpSwapTrade),
656 DexEvent::PumpSwapBuy(_) => Some(EventType::PumpSwapBuy),
657 DexEvent::PumpSwapSell(_) => Some(EventType::PumpSwapSell),
658 DexEvent::PumpSwapCreatePool(_) => Some(EventType::PumpSwapCreatePool),
659 DexEvent::PumpSwapLiquidityAdded(_) => Some(EventType::PumpSwapLiquidityAdded),
660 DexEvent::PumpSwapLiquidityRemoved(_) => Some(EventType::PumpSwapLiquidityRemoved),
661 DexEvent::MeteoraDammV2Swap(_) => Some(EventType::MeteoraDammV2Swap),
662 DexEvent::MeteoraDammV2CreatePosition(_) => Some(EventType::MeteoraDammV2CreatePosition),
663 DexEvent::MeteoraDammV2ClosePosition(_) => Some(EventType::MeteoraDammV2ClosePosition),
664 DexEvent::MeteoraDammV2AddLiquidity(_) => Some(EventType::MeteoraDammV2AddLiquidity),
665 DexEvent::MeteoraDammV2RemoveLiquidity(_) => Some(EventType::MeteoraDammV2RemoveLiquidity),
666 DexEvent::BonkTrade(_) => Some(EventType::BonkTrade),
667 DexEvent::BonkPoolCreate(_) => Some(EventType::BonkPoolCreate),
668 DexEvent::BonkMigrateAmm(_) => Some(EventType::BonkMigrateAmm),
669 DexEvent::RaydiumClmmSwap(_) => Some(EventType::RaydiumClmmSwap),
670 DexEvent::RaydiumClmmCreatePool(_) => Some(EventType::RaydiumClmmCreatePool),
671 DexEvent::RaydiumClmmOpenPosition(_) => Some(EventType::RaydiumClmmOpenPosition),
672 DexEvent::RaydiumClmmOpenPositionWithTokenExtNft(_) => {
673 Some(EventType::RaydiumClmmOpenPositionWithTokenExtNft)
674 }
675 DexEvent::RaydiumClmmClosePosition(_) => Some(EventType::RaydiumClmmClosePosition),
676 DexEvent::RaydiumClmmIncreaseLiquidity(_) => Some(EventType::RaydiumClmmIncreaseLiquidity),
677 DexEvent::RaydiumClmmDecreaseLiquidity(_) => Some(EventType::RaydiumClmmDecreaseLiquidity),
678 DexEvent::RaydiumClmmCollectFee(_) => Some(EventType::RaydiumClmmCollectFee),
679 DexEvent::RaydiumCpmmSwap(_) => Some(EventType::RaydiumCpmmSwap),
680 DexEvent::RaydiumCpmmDeposit(_) => Some(EventType::RaydiumCpmmDeposit),
681 DexEvent::RaydiumCpmmWithdraw(_) => Some(EventType::RaydiumCpmmWithdraw),
682 DexEvent::RaydiumCpmmInitialize(_) => Some(EventType::RaydiumCpmmInitialize),
683 DexEvent::RaydiumAmmV4Swap(_) => Some(EventType::RaydiumAmmV4Swap),
684 DexEvent::RaydiumAmmV4Deposit(_) => Some(EventType::RaydiumAmmV4Deposit),
685 DexEvent::RaydiumAmmV4Initialize2(_) => Some(EventType::RaydiumAmmV4Initialize2),
686 DexEvent::RaydiumAmmV4Withdraw(_) => Some(EventType::RaydiumAmmV4Withdraw),
687 DexEvent::RaydiumAmmV4WithdrawPnl(_) => Some(EventType::RaydiumAmmV4WithdrawPnl),
688 DexEvent::OrcaWhirlpoolSwap(_) => Some(EventType::OrcaWhirlpoolSwap),
689 DexEvent::OrcaWhirlpoolLiquidityIncreased(_) => {
690 Some(EventType::OrcaWhirlpoolLiquidityIncreased)
691 }
692 DexEvent::OrcaWhirlpoolLiquidityDecreased(_) => {
693 Some(EventType::OrcaWhirlpoolLiquidityDecreased)
694 }
695 DexEvent::OrcaWhirlpoolPoolInitialized(_) => Some(EventType::OrcaWhirlpoolPoolInitialized),
696 DexEvent::MeteoraPoolsSwap(_) => Some(EventType::MeteoraPoolsSwap),
697 DexEvent::MeteoraPoolsAddLiquidity(_) => Some(EventType::MeteoraPoolsAddLiquidity),
698 DexEvent::MeteoraPoolsRemoveLiquidity(_) => Some(EventType::MeteoraPoolsRemoveLiquidity),
699 DexEvent::MeteoraPoolsBootstrapLiquidity(_) => {
700 Some(EventType::MeteoraPoolsBootstrapLiquidity)
701 }
702 DexEvent::MeteoraPoolsPoolCreated(_) => Some(EventType::MeteoraPoolsPoolCreated),
703 DexEvent::MeteoraPoolsSetPoolFees(_) => Some(EventType::MeteoraPoolsSetPoolFees),
704 DexEvent::MeteoraDlmmSwap(_) => Some(EventType::MeteoraDlmmSwap),
705 DexEvent::MeteoraDlmmAddLiquidity(_) => Some(EventType::MeteoraDlmmAddLiquidity),
706 DexEvent::MeteoraDlmmRemoveLiquidity(_) => Some(EventType::MeteoraDlmmRemoveLiquidity),
707 DexEvent::MeteoraDlmmInitializePool(_) => Some(EventType::MeteoraDlmmInitializePool),
708 DexEvent::MeteoraDlmmInitializeBinArray(_) => {
709 Some(EventType::MeteoraDlmmInitializeBinArray)
710 }
711 DexEvent::MeteoraDlmmCreatePosition(_) => Some(EventType::MeteoraDlmmCreatePosition),
712 DexEvent::MeteoraDlmmClosePosition(_) => Some(EventType::MeteoraDlmmClosePosition),
713 DexEvent::MeteoraDlmmClaimFee(_) => Some(EventType::MeteoraDlmmClaimFee),
714 DexEvent::TokenAccount(_) => Some(EventType::TokenAccount),
715 DexEvent::NonceAccount(_) => Some(EventType::NonceAccount),
716 DexEvent::PumpSwapGlobalConfigAccount(_) => Some(EventType::AccountPumpSwapGlobalConfig),
717 DexEvent::PumpSwapPoolAccount(_) => Some(EventType::AccountPumpSwapPool),
718 DexEvent::BlockMeta(_) => Some(EventType::BlockMeta),
719 DexEvent::TokenInfo(_) | DexEvent::Error(_) => None,
720 }
721}
722
723#[cfg(test)]
724mod event_type_filter_tests {
725 use super::*;
726
727 #[test]
728 fn generic_trade_filters_cover_specific_trade_variants() {
729 let pump = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
730 assert!(pump.should_include(EventType::PumpFunTrade));
731 assert!(pump.should_include(EventType::PumpFunBuy));
732 assert!(pump.should_include(EventType::PumpFunSell));
733 assert!(pump.should_include(EventType::PumpFunBuyExactSolIn));
734
735 let pump_specific = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
736 assert!(pump_specific.should_include(EventType::PumpFunTrade));
737
738 let pumpswap = EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]);
739 assert!(pumpswap.should_include(EventType::PumpSwapBuy));
740 assert!(pumpswap.should_include(EventType::PumpSwapSell));
741
742 let exclude_pumpswap = EventTypeFilter::exclude_types(vec![EventType::PumpSwapTrade]);
743 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapBuy));
744 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapSell));
745 }
746
747 #[test]
748 fn all_protocol_groups_are_filterable() {
749 assert!(EventTypeFilter::include_only(vec![EventType::PumpFunTrade]).includes_pumpfun());
750 assert!(EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]).includes_pumpswap());
751 assert!(EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateFeeShares])
752 .includes_pump_fees());
753 assert!(
754 EventTypeFilter::include_only(vec![EventType::BonkTrade]).includes_raydium_launchpad()
755 );
756 assert!(
757 EventTypeFilter::include_only(vec![EventType::RaydiumCpmmSwap]).includes_raydium_cpmm()
758 );
759 assert!(
760 EventTypeFilter::include_only(vec![EventType::RaydiumClmmSwap]).includes_raydium_clmm()
761 );
762 assert!(EventTypeFilter::include_only(vec![EventType::RaydiumAmmV4Swap])
763 .includes_raydium_amm_v4());
764 assert!(EventTypeFilter::include_only(vec![EventType::OrcaWhirlpoolSwap])
765 .includes_orca_whirlpool());
766 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraPoolsSwap])
767 .includes_meteora_pools());
768 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2Swap])
769 .includes_meteora_damm_v2());
770 assert!(
771 EventTypeFilter::include_only(vec![EventType::MeteoraDlmmSwap]).includes_meteora_dlmm()
772 );
773 }
774
775 #[test]
776 fn exclude_filters_do_not_skip_whole_protocol_groups() {
777 let raydium = EventTypeFilter::exclude_types(vec![EventType::RaydiumCpmmSwap]);
778 assert!(raydium.includes_raydium_cpmm());
779 assert!(!raydium.should_include(EventType::RaydiumCpmmSwap));
780 assert!(raydium.should_include(EventType::RaydiumCpmmDeposit));
781
782 let pump = EventTypeFilter::exclude_types(vec![EventType::PumpFunBuy]);
783 assert!(pump.includes_pumpfun());
784 assert!(!pump.should_include(EventType::PumpFunBuy));
785 assert!(pump.should_include(EventType::PumpFunSell));
786 }
787}
788
789#[derive(Debug, Clone)]
790pub struct SlotFilter {
791 pub min_slot: Option<u64>,
792 pub max_slot: Option<u64>,
793}
794
795impl SlotFilter {
796 pub fn new() -> Self {
797 Self { min_slot: None, max_slot: None }
798 }
799
800 pub fn min_slot(mut self, slot: u64) -> Self {
801 self.min_slot = Some(slot);
802 self
803 }
804
805 pub fn max_slot(mut self, slot: u64) -> Self {
806 self.max_slot = Some(slot);
807 self
808 }
809}
810
811impl Default for SlotFilter {
812 fn default() -> Self {
813 Self::new()
814 }
815}