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)]
240#[non_exhaustive]
241pub enum EventType {
242 BlockMeta,
244
245 BonkTrade,
247 BonkPoolCreate,
248 BonkMigrateAmm,
249
250 PumpFunTrade, PumpFunBuy, PumpFunSell, PumpFunBuyExactSolIn, PumpFunCreate,
256 PumpFunCreateV2, PumpFunComplete,
258 PumpFunMigrate,
259 PumpFeesCreateFeeSharingConfig,
261 PumpFeesInitializeFeeConfig,
262 PumpFeesResetFeeSharingConfig,
263 PumpFeesRevokeFeeSharingAuthority,
264 PumpFeesTransferFeeSharingAuthority,
265 PumpFeesUpdateAdmin,
266 PumpFeesUpdateFeeConfig,
267 PumpFeesUpdateFeeShares,
268 PumpFeesUpsertFeeTiers,
269 PumpFunMigrateBondingCurveCreator,
271
272 PumpSwapTrade,
274 PumpSwapBuy,
275 PumpSwapSell,
276 PumpSwapCreatePool,
277 PumpSwapLiquidityAdded,
278 PumpSwapLiquidityRemoved,
279 RaydiumCpmmSwap,
284 RaydiumCpmmDeposit,
285 RaydiumCpmmWithdraw,
286 RaydiumCpmmInitialize,
287
288 RaydiumClmmSwap,
290 RaydiumClmmCreatePool,
291 RaydiumClmmOpenPosition,
292 RaydiumClmmClosePosition,
293 RaydiumClmmIncreaseLiquidity,
294 RaydiumClmmDecreaseLiquidity,
295 RaydiumClmmLiquidityChange,
296 RaydiumClmmConfigChange,
297 RaydiumClmmCreatePersonalPosition,
298 RaydiumClmmLiquidityCalculate,
299 RaydiumClmmOpenLimitOrder,
300 RaydiumClmmIncreaseLimitOrder,
301 RaydiumClmmDecreaseLimitOrder,
302 RaydiumClmmSettleLimitOrder,
303 RaydiumClmmUpdateRewardInfos,
304 RaydiumClmmOpenPositionWithTokenExtNft,
305 RaydiumClmmCollectFee,
306
307 RaydiumAmmV4Swap,
309 RaydiumAmmV4Deposit,
310 RaydiumAmmV4Withdraw,
311 RaydiumAmmV4Initialize2,
312 RaydiumAmmV4WithdrawPnl,
313
314 OrcaWhirlpoolSwap,
316 OrcaWhirlpoolLiquidityIncreased,
317 OrcaWhirlpoolLiquidityDecreased,
318 OrcaWhirlpoolPoolInitialized,
319
320 MeteoraPoolsSwap,
322 MeteoraPoolsAddLiquidity,
323 MeteoraPoolsRemoveLiquidity,
324 MeteoraPoolsBootstrapLiquidity,
325 MeteoraPoolsPoolCreated,
326 MeteoraPoolsSetPoolFees,
327
328 MeteoraDammV2Swap,
330 MeteoraDammV2AddLiquidity,
331 MeteoraDammV2RemoveLiquidity,
332 MeteoraDammV2CreatePosition,
334 MeteoraDammV2ClosePosition,
335 MeteoraDlmmSwap,
342 MeteoraDlmmAddLiquidity,
343 MeteoraDlmmRemoveLiquidity,
344 MeteoraDlmmInitializePool,
345 MeteoraDlmmInitializeBinArray,
346 MeteoraDlmmCreatePosition,
347 MeteoraDlmmClosePosition,
348 MeteoraDlmmClaimFee,
349
350 TokenAccount,
352 NonceAccount,
353 AccountPumpFunGlobal,
354 AccountPumpFunBondingCurve,
355 AccountPumpFunFeeConfig,
356 AccountPumpFunSharingConfig,
357 AccountPumpFunGlobalVolumeAccumulator,
358 AccountPumpFunUserVolumeAccumulator,
359
360 AccountPumpSwapGlobalConfig,
361 AccountPumpSwapPool,
362 AccountRaydiumClmmAmmConfig,
363 AccountRaydiumClmmPoolState,
364 AccountRaydiumClmmTickArrayState,
365}
366
367#[derive(Debug, Clone)]
368pub struct EventTypeFilter {
369 pub include_only: Option<Vec<EventType>>,
370 pub exclude_types: Option<Vec<EventType>>,
371}
372
373impl EventTypeFilter {
374 pub fn include_only(types: Vec<EventType>) -> Self {
375 Self { include_only: Some(types), exclude_types: None }
376 }
377
378 pub fn exclude_types(types: Vec<EventType>) -> Self {
379 Self { include_only: None, exclude_types: Some(types) }
380 }
381
382 #[inline]
383 fn includes_group<F>(&self, mut is_group: F) -> bool
384 where
385 F: FnMut(&EventType) -> bool,
386 {
387 if let Some(ref include_only) = self.include_only {
388 return include_only.iter().any(&mut is_group);
389 }
390 true
394 }
395
396 pub fn should_include(&self, event_type: EventType) -> bool {
397 if let Some(ref include_only) = self.include_only {
398 if include_only.contains(&event_type) {
400 return true;
401 }
402 if event_type == EventType::PumpFunTrade {
406 return include_only.iter().any(|t| {
407 matches!(
408 t,
409 EventType::PumpFunBuy
410 | EventType::PumpFunSell
411 | EventType::PumpFunBuyExactSolIn
412 )
413 });
414 }
415 if matches!(
416 event_type,
417 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
418 ) {
419 return include_only.contains(&EventType::PumpFunTrade);
420 }
421 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell) {
422 return include_only.contains(&EventType::PumpSwapTrade);
423 }
424 return false;
425 }
426
427 if let Some(ref exclude_types) = self.exclude_types {
428 if exclude_types.contains(&event_type) {
429 return false;
430 }
431 if matches!(
432 event_type,
433 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
434 ) && exclude_types.contains(&EventType::PumpFunTrade)
435 {
436 return false;
437 }
438 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell)
439 && exclude_types.contains(&EventType::PumpSwapTrade)
440 {
441 return false;
442 }
443 return true;
444 }
445
446 true
447 }
448
449 pub fn should_include_dex_event(&self, event: &crate::core::events::DexEvent) -> bool {
450 let Some(event_type) = event_type_from_dex_event(event) else { return true };
451 self.should_include(event_type)
452 }
453
454 #[inline]
455 pub fn includes_pumpfun(&self) -> bool {
456 self.includes_group(|t| {
457 matches!(
458 t,
459 EventType::PumpFunTrade
460 | EventType::PumpFunBuy
461 | EventType::PumpFunSell
462 | EventType::PumpFunBuyExactSolIn
463 | EventType::PumpFunCreate
464 | EventType::PumpFunCreateV2
465 | EventType::PumpFunComplete
466 | EventType::PumpFunMigrate
467 | EventType::PumpFunMigrateBondingCurveCreator
468 | EventType::AccountPumpFunGlobal
469 | EventType::AccountPumpFunBondingCurve
470 | EventType::AccountPumpFunFeeConfig
471 | EventType::AccountPumpFunSharingConfig
472 | EventType::AccountPumpFunGlobalVolumeAccumulator
473 | EventType::AccountPumpFunUserVolumeAccumulator
474 )
475 })
476 }
477
478 #[inline]
479 pub fn includes_meteora_damm_v2(&self) -> bool {
480 self.includes_group(|t| {
481 matches!(
482 t,
483 EventType::MeteoraDammV2Swap
484 | EventType::MeteoraDammV2AddLiquidity
485 | EventType::MeteoraDammV2CreatePosition
486 | EventType::MeteoraDammV2ClosePosition
487 | EventType::MeteoraDammV2RemoveLiquidity
488 )
489 })
490 }
491
492 #[inline]
493 pub fn includes_pump_fees(&self) -> bool {
494 self.includes_group(|t| {
495 matches!(
496 t,
497 EventType::PumpFeesCreateFeeSharingConfig
498 | EventType::PumpFeesInitializeFeeConfig
499 | EventType::PumpFeesResetFeeSharingConfig
500 | EventType::PumpFeesRevokeFeeSharingAuthority
501 | EventType::PumpFeesTransferFeeSharingAuthority
502 | EventType::PumpFeesUpdateAdmin
503 | EventType::PumpFeesUpdateFeeConfig
504 | EventType::PumpFeesUpdateFeeShares
505 | EventType::PumpFeesUpsertFeeTiers
506 )
507 })
508 }
509
510 #[inline]
512 pub fn includes_pumpswap(&self) -> bool {
513 self.includes_group(|t| {
514 matches!(
515 t,
516 EventType::PumpSwapTrade
517 | EventType::PumpSwapBuy
518 | EventType::PumpSwapSell
519 | EventType::PumpSwapCreatePool
520 | EventType::PumpSwapLiquidityAdded
521 | EventType::PumpSwapLiquidityRemoved
522 )
523 })
524 }
525
526 #[inline]
528 pub fn includes_raydium_launchpad(&self) -> bool {
529 self.includes_group(|t| {
530 matches!(
531 t,
532 EventType::BonkTrade | EventType::BonkPoolCreate | EventType::BonkMigrateAmm
533 )
534 })
535 }
536
537 #[inline]
538 pub fn includes_raydium_cpmm(&self) -> bool {
539 self.includes_group(|t| {
540 matches!(
541 t,
542 EventType::RaydiumCpmmSwap
543 | EventType::RaydiumCpmmDeposit
544 | EventType::RaydiumCpmmWithdraw
545 | EventType::RaydiumCpmmInitialize
546 )
547 })
548 }
549
550 #[inline]
551 pub fn includes_raydium_clmm(&self) -> bool {
552 self.includes_group(|t| {
553 matches!(
554 t,
555 EventType::RaydiumClmmSwap
556 | EventType::RaydiumClmmCreatePool
557 | EventType::RaydiumClmmOpenPosition
558 | EventType::RaydiumClmmClosePosition
559 | EventType::RaydiumClmmIncreaseLiquidity
560 | EventType::RaydiumClmmDecreaseLiquidity
561 | EventType::RaydiumClmmLiquidityChange
562 | EventType::RaydiumClmmConfigChange
563 | EventType::RaydiumClmmCreatePersonalPosition
564 | EventType::RaydiumClmmLiquidityCalculate
565 | EventType::RaydiumClmmOpenLimitOrder
566 | EventType::RaydiumClmmIncreaseLimitOrder
567 | EventType::RaydiumClmmDecreaseLimitOrder
568 | EventType::RaydiumClmmSettleLimitOrder
569 | EventType::RaydiumClmmUpdateRewardInfos
570 | EventType::RaydiumClmmOpenPositionWithTokenExtNft
571 | EventType::RaydiumClmmCollectFee
572 | EventType::AccountRaydiumClmmAmmConfig
573 | EventType::AccountRaydiumClmmPoolState
574 | EventType::AccountRaydiumClmmTickArrayState
575 )
576 })
577 }
578
579 #[inline]
580 pub fn includes_raydium_amm_v4(&self) -> bool {
581 self.includes_group(|t| {
582 matches!(
583 t,
584 EventType::RaydiumAmmV4Swap
585 | EventType::RaydiumAmmV4Deposit
586 | EventType::RaydiumAmmV4Withdraw
587 | EventType::RaydiumAmmV4Initialize2
588 | EventType::RaydiumAmmV4WithdrawPnl
589 )
590 })
591 }
592
593 #[inline]
594 pub fn includes_orca_whirlpool(&self) -> bool {
595 self.includes_group(|t| {
596 matches!(
597 t,
598 EventType::OrcaWhirlpoolSwap
599 | EventType::OrcaWhirlpoolLiquidityIncreased
600 | EventType::OrcaWhirlpoolLiquidityDecreased
601 | EventType::OrcaWhirlpoolPoolInitialized
602 )
603 })
604 }
605
606 #[inline]
607 pub fn includes_meteora_pools(&self) -> bool {
608 self.includes_group(|t| {
609 matches!(
610 t,
611 EventType::MeteoraPoolsSwap
612 | EventType::MeteoraPoolsAddLiquidity
613 | EventType::MeteoraPoolsRemoveLiquidity
614 | EventType::MeteoraPoolsBootstrapLiquidity
615 | EventType::MeteoraPoolsPoolCreated
616 | EventType::MeteoraPoolsSetPoolFees
617 )
618 })
619 }
620
621 #[inline]
622 pub fn includes_meteora_dlmm(&self) -> bool {
623 self.includes_group(|t| {
624 matches!(
625 t,
626 EventType::MeteoraDlmmSwap
627 | EventType::MeteoraDlmmAddLiquidity
628 | EventType::MeteoraDlmmRemoveLiquidity
629 | EventType::MeteoraDlmmInitializePool
630 | EventType::MeteoraDlmmInitializeBinArray
631 | EventType::MeteoraDlmmCreatePosition
632 | EventType::MeteoraDlmmClosePosition
633 | EventType::MeteoraDlmmClaimFee
634 )
635 })
636 }
637}
638
639#[inline]
640pub fn event_type_from_dex_event(event: &crate::core::events::DexEvent) -> Option<EventType> {
641 use crate::core::events::DexEvent;
642 match event {
643 DexEvent::PumpFunCreate(_) => Some(EventType::PumpFunCreate),
644 DexEvent::PumpFunCreateV2(_) => Some(EventType::PumpFunCreateV2),
645 DexEvent::PumpFunTrade(_) => Some(EventType::PumpFunTrade),
646 DexEvent::PumpFunBuy(_) => Some(EventType::PumpFunBuy),
647 DexEvent::PumpFunSell(_) => Some(EventType::PumpFunSell),
648 DexEvent::PumpFunBuyExactSolIn(_) => Some(EventType::PumpFunBuyExactSolIn),
649 DexEvent::PumpFunMigrate(_) => Some(EventType::PumpFunMigrate),
650 DexEvent::PumpFeesCreateFeeSharingConfig(_) => {
651 Some(EventType::PumpFeesCreateFeeSharingConfig)
652 }
653 DexEvent::PumpFeesInitializeFeeConfig(_) => Some(EventType::PumpFeesInitializeFeeConfig),
654 DexEvent::PumpFeesResetFeeSharingConfig(_) => {
655 Some(EventType::PumpFeesResetFeeSharingConfig)
656 }
657 DexEvent::PumpFeesRevokeFeeSharingAuthority(_) => {
658 Some(EventType::PumpFeesRevokeFeeSharingAuthority)
659 }
660 DexEvent::PumpFeesTransferFeeSharingAuthority(_) => {
661 Some(EventType::PumpFeesTransferFeeSharingAuthority)
662 }
663 DexEvent::PumpFeesUpdateAdmin(_) => Some(EventType::PumpFeesUpdateAdmin),
664 DexEvent::PumpFeesUpdateFeeConfig(_) => Some(EventType::PumpFeesUpdateFeeConfig),
665 DexEvent::PumpFeesUpdateFeeShares(_) => Some(EventType::PumpFeesUpdateFeeShares),
666 DexEvent::PumpFeesUpsertFeeTiers(_) => Some(EventType::PumpFeesUpsertFeeTiers),
667 DexEvent::PumpFunMigrateBondingCurveCreator(_) => {
668 Some(EventType::PumpFunMigrateBondingCurveCreator)
669 }
670 DexEvent::PumpFunGlobalAccount(_) => Some(EventType::AccountPumpFunGlobal),
671 DexEvent::PumpFunBondingCurveAccount(_) => Some(EventType::AccountPumpFunBondingCurve),
672 DexEvent::PumpFunFeeConfigAccount(_) => Some(EventType::AccountPumpFunFeeConfig),
673 DexEvent::PumpFunSharingConfigAccount(_) => Some(EventType::AccountPumpFunSharingConfig),
674 DexEvent::PumpFunGlobalVolumeAccumulatorAccount(_) => {
675 Some(EventType::AccountPumpFunGlobalVolumeAccumulator)
676 }
677 DexEvent::PumpFunUserVolumeAccumulatorAccount(_) => {
678 Some(EventType::AccountPumpFunUserVolumeAccumulator)
679 }
680 DexEvent::PumpSwapTrade(_) => Some(EventType::PumpSwapTrade),
681 DexEvent::PumpSwapBuy(_) => Some(EventType::PumpSwapBuy),
682 DexEvent::PumpSwapSell(_) => Some(EventType::PumpSwapSell),
683 DexEvent::PumpSwapCreatePool(_) => Some(EventType::PumpSwapCreatePool),
684 DexEvent::PumpSwapLiquidityAdded(_) => Some(EventType::PumpSwapLiquidityAdded),
685 DexEvent::PumpSwapLiquidityRemoved(_) => Some(EventType::PumpSwapLiquidityRemoved),
686 DexEvent::MeteoraDammV2Swap(_) => Some(EventType::MeteoraDammV2Swap),
687 DexEvent::MeteoraDammV2CreatePosition(_) => Some(EventType::MeteoraDammV2CreatePosition),
688 DexEvent::MeteoraDammV2ClosePosition(_) => Some(EventType::MeteoraDammV2ClosePosition),
689 DexEvent::MeteoraDammV2AddLiquidity(_) => Some(EventType::MeteoraDammV2AddLiquidity),
690 DexEvent::MeteoraDammV2RemoveLiquidity(_) => Some(EventType::MeteoraDammV2RemoveLiquidity),
691 DexEvent::BonkTrade(_) => Some(EventType::BonkTrade),
692 DexEvent::BonkPoolCreate(_) => Some(EventType::BonkPoolCreate),
693 DexEvent::BonkMigrateAmm(_) => Some(EventType::BonkMigrateAmm),
694 DexEvent::RaydiumClmmSwap(_) => Some(EventType::RaydiumClmmSwap),
695 DexEvent::RaydiumClmmCreatePool(_) => Some(EventType::RaydiumClmmCreatePool),
696 DexEvent::RaydiumClmmOpenPosition(_) => Some(EventType::RaydiumClmmOpenPosition),
697 DexEvent::RaydiumClmmOpenPositionWithTokenExtNft(_) => {
698 Some(EventType::RaydiumClmmOpenPositionWithTokenExtNft)
699 }
700 DexEvent::RaydiumClmmClosePosition(_) => Some(EventType::RaydiumClmmClosePosition),
701 DexEvent::RaydiumClmmIncreaseLiquidity(_) => Some(EventType::RaydiumClmmIncreaseLiquidity),
702 DexEvent::RaydiumClmmDecreaseLiquidity(_) => Some(EventType::RaydiumClmmDecreaseLiquidity),
703 DexEvent::RaydiumClmmLiquidityChange(_) => Some(EventType::RaydiumClmmLiquidityChange),
704 DexEvent::RaydiumClmmConfigChange(_) => Some(EventType::RaydiumClmmConfigChange),
705 DexEvent::RaydiumClmmCreatePersonalPosition(_) => {
706 Some(EventType::RaydiumClmmCreatePersonalPosition)
707 }
708 DexEvent::RaydiumClmmLiquidityCalculate(_) => {
709 Some(EventType::RaydiumClmmLiquidityCalculate)
710 }
711 DexEvent::RaydiumClmmOpenLimitOrder(_) => Some(EventType::RaydiumClmmOpenLimitOrder),
712 DexEvent::RaydiumClmmIncreaseLimitOrder(_) => {
713 Some(EventType::RaydiumClmmIncreaseLimitOrder)
714 }
715 DexEvent::RaydiumClmmDecreaseLimitOrder(_) => {
716 Some(EventType::RaydiumClmmDecreaseLimitOrder)
717 }
718 DexEvent::RaydiumClmmSettleLimitOrder(_) => Some(EventType::RaydiumClmmSettleLimitOrder),
719 DexEvent::RaydiumClmmUpdateRewardInfos(_) => Some(EventType::RaydiumClmmUpdateRewardInfos),
720 DexEvent::RaydiumClmmCollectFee(_) => Some(EventType::RaydiumClmmCollectFee),
721 DexEvent::RaydiumClmmAmmConfigAccount(_) => Some(EventType::AccountRaydiumClmmAmmConfig),
722 DexEvent::RaydiumClmmPoolStateAccount(_) => Some(EventType::AccountRaydiumClmmPoolState),
723 DexEvent::RaydiumClmmTickArrayStateAccount(_) => {
724 Some(EventType::AccountRaydiumClmmTickArrayState)
725 }
726 DexEvent::RaydiumCpmmSwap(_) => Some(EventType::RaydiumCpmmSwap),
727 DexEvent::RaydiumCpmmDeposit(_) => Some(EventType::RaydiumCpmmDeposit),
728 DexEvent::RaydiumCpmmWithdraw(_) => Some(EventType::RaydiumCpmmWithdraw),
729 DexEvent::RaydiumCpmmInitialize(_) => Some(EventType::RaydiumCpmmInitialize),
730 DexEvent::RaydiumAmmV4Swap(_) => Some(EventType::RaydiumAmmV4Swap),
731 DexEvent::RaydiumAmmV4Deposit(_) => Some(EventType::RaydiumAmmV4Deposit),
732 DexEvent::RaydiumAmmV4Initialize2(_) => Some(EventType::RaydiumAmmV4Initialize2),
733 DexEvent::RaydiumAmmV4Withdraw(_) => Some(EventType::RaydiumAmmV4Withdraw),
734 DexEvent::RaydiumAmmV4WithdrawPnl(_) => Some(EventType::RaydiumAmmV4WithdrawPnl),
735 DexEvent::OrcaWhirlpoolSwap(_) => Some(EventType::OrcaWhirlpoolSwap),
736 DexEvent::OrcaWhirlpoolLiquidityIncreased(_) => {
737 Some(EventType::OrcaWhirlpoolLiquidityIncreased)
738 }
739 DexEvent::OrcaWhirlpoolLiquidityDecreased(_) => {
740 Some(EventType::OrcaWhirlpoolLiquidityDecreased)
741 }
742 DexEvent::OrcaWhirlpoolPoolInitialized(_) => Some(EventType::OrcaWhirlpoolPoolInitialized),
743 DexEvent::MeteoraPoolsSwap(_) => Some(EventType::MeteoraPoolsSwap),
744 DexEvent::MeteoraPoolsAddLiquidity(_) => Some(EventType::MeteoraPoolsAddLiquidity),
745 DexEvent::MeteoraPoolsRemoveLiquidity(_) => Some(EventType::MeteoraPoolsRemoveLiquidity),
746 DexEvent::MeteoraPoolsBootstrapLiquidity(_) => {
747 Some(EventType::MeteoraPoolsBootstrapLiquidity)
748 }
749 DexEvent::MeteoraPoolsPoolCreated(_) => Some(EventType::MeteoraPoolsPoolCreated),
750 DexEvent::MeteoraPoolsSetPoolFees(_) => Some(EventType::MeteoraPoolsSetPoolFees),
751 DexEvent::MeteoraDlmmSwap(_) => Some(EventType::MeteoraDlmmSwap),
752 DexEvent::MeteoraDlmmAddLiquidity(_) => Some(EventType::MeteoraDlmmAddLiquidity),
753 DexEvent::MeteoraDlmmRemoveLiquidity(_) => Some(EventType::MeteoraDlmmRemoveLiquidity),
754 DexEvent::MeteoraDlmmInitializePool(_) => Some(EventType::MeteoraDlmmInitializePool),
755 DexEvent::MeteoraDlmmInitializeBinArray(_) => {
756 Some(EventType::MeteoraDlmmInitializeBinArray)
757 }
758 DexEvent::MeteoraDlmmCreatePosition(_) => Some(EventType::MeteoraDlmmCreatePosition),
759 DexEvent::MeteoraDlmmClosePosition(_) => Some(EventType::MeteoraDlmmClosePosition),
760 DexEvent::MeteoraDlmmClaimFee(_) => Some(EventType::MeteoraDlmmClaimFee),
761 DexEvent::TokenAccount(_) => Some(EventType::TokenAccount),
762 DexEvent::NonceAccount(_) => Some(EventType::NonceAccount),
763 DexEvent::PumpSwapGlobalConfigAccount(_) => Some(EventType::AccountPumpSwapGlobalConfig),
764 DexEvent::PumpSwapPoolAccount(_) => Some(EventType::AccountPumpSwapPool),
765 DexEvent::BlockMeta(_) => Some(EventType::BlockMeta),
766 DexEvent::TokenInfo(_) | DexEvent::Error(_) => None,
767 }
768}
769
770#[cfg(test)]
771mod event_type_filter_tests {
772 use super::*;
773
774 #[test]
775 fn generic_trade_filters_cover_specific_trade_variants() {
776 let pump = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
777 assert!(pump.should_include(EventType::PumpFunTrade));
778 assert!(pump.should_include(EventType::PumpFunBuy));
779 assert!(pump.should_include(EventType::PumpFunSell));
780 assert!(pump.should_include(EventType::PumpFunBuyExactSolIn));
781
782 let pump_specific = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
783 assert!(pump_specific.should_include(EventType::PumpFunTrade));
784
785 let pumpswap = EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]);
786 assert!(pumpswap.should_include(EventType::PumpSwapBuy));
787 assert!(pumpswap.should_include(EventType::PumpSwapSell));
788
789 let exclude_pumpswap = EventTypeFilter::exclude_types(vec![EventType::PumpSwapTrade]);
790 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapBuy));
791 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapSell));
792 }
793
794 #[test]
795 fn all_protocol_groups_are_filterable() {
796 assert!(EventTypeFilter::include_only(vec![EventType::PumpFunTrade]).includes_pumpfun());
797 assert!(EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]).includes_pumpswap());
798 assert!(EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateFeeShares])
799 .includes_pump_fees());
800 assert!(
801 EventTypeFilter::include_only(vec![EventType::BonkTrade]).includes_raydium_launchpad()
802 );
803 assert!(
804 EventTypeFilter::include_only(vec![EventType::RaydiumCpmmSwap]).includes_raydium_cpmm()
805 );
806 assert!(
807 EventTypeFilter::include_only(vec![EventType::RaydiumClmmSwap]).includes_raydium_clmm()
808 );
809 assert!(EventTypeFilter::include_only(vec![EventType::RaydiumAmmV4Swap])
810 .includes_raydium_amm_v4());
811 assert!(EventTypeFilter::include_only(vec![EventType::OrcaWhirlpoolSwap])
812 .includes_orca_whirlpool());
813 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraPoolsSwap])
814 .includes_meteora_pools());
815 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2Swap])
816 .includes_meteora_damm_v2());
817 assert!(
818 EventTypeFilter::include_only(vec![EventType::MeteoraDlmmSwap]).includes_meteora_dlmm()
819 );
820 }
821
822 #[test]
823 fn exclude_filters_do_not_skip_whole_protocol_groups() {
824 let raydium = EventTypeFilter::exclude_types(vec![EventType::RaydiumCpmmSwap]);
825 assert!(raydium.includes_raydium_cpmm());
826 assert!(!raydium.should_include(EventType::RaydiumCpmmSwap));
827 assert!(raydium.should_include(EventType::RaydiumCpmmDeposit));
828
829 let pump = EventTypeFilter::exclude_types(vec![EventType::PumpFunBuy]);
830 assert!(pump.includes_pumpfun());
831 assert!(!pump.should_include(EventType::PumpFunBuy));
832 assert!(pump.should_include(EventType::PumpFunSell));
833 }
834}
835
836#[derive(Debug, Clone)]
837pub struct SlotFilter {
838 pub min_slot: Option<u64>,
839 pub max_slot: Option<u64>,
840}
841
842impl SlotFilter {
843 pub fn new() -> Self {
844 Self { min_slot: None, max_slot: None }
845 }
846
847 pub fn min_slot(mut self, slot: u64) -> Self {
848 self.min_slot = Some(slot);
849 self
850 }
851
852 pub fn max_slot(mut self, slot: u64) -> Self {
853 self.max_slot = Some(slot);
854 self
855 }
856}
857
858impl Default for SlotFilter {
859 fn default() -> Self {
860 Self::new()
861 }
862}