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,
19 StreamingOrdered,
23 MicroBatch,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ClientConfig {
31 pub enable_metrics: bool,
33 pub connection_timeout_ms: u64,
35 pub request_timeout_ms: u64,
37 pub enable_tls: bool,
39 pub max_retries: u32,
40 pub retry_delay_ms: u64,
43 pub max_concurrent_streams: u32,
44 pub keep_alive_interval_ms: u64,
45 pub keep_alive_timeout_ms: u64,
46 pub buffer_size: usize,
47 pub order_mode: OrderMode,
49 pub order_timeout_ms: u64,
52 pub micro_batch_us: u64,
55}
56
57impl Default for ClientConfig {
58 fn default() -> Self {
59 Self {
60 enable_metrics: false,
61 connection_timeout_ms: 8000,
62 request_timeout_ms: 15000,
63 enable_tls: true,
64 max_retries: 3,
65 retry_delay_ms: 1000,
66 max_concurrent_streams: 100,
67 keep_alive_interval_ms: 30000,
68 keep_alive_timeout_ms: 5000,
69 buffer_size: 100_000,
70 order_mode: OrderMode::Unordered,
71 order_timeout_ms: 100,
72 micro_batch_us: 100, }
74 }
75}
76
77impl ClientConfig {
78 pub fn low_latency() -> Self {
79 Self {
80 enable_metrics: false,
81 connection_timeout_ms: 5000,
82 request_timeout_ms: 10000,
83 enable_tls: true,
84 max_retries: 1,
85 retry_delay_ms: 100,
86 max_concurrent_streams: 200,
87 keep_alive_interval_ms: 10000,
88 keep_alive_timeout_ms: 2000,
89 buffer_size: 100_000,
90 order_mode: OrderMode::Unordered,
91 order_timeout_ms: 50,
92 micro_batch_us: 50, }
94 }
95
96 pub fn high_throughput() -> Self {
97 Self {
98 enable_metrics: true,
99 connection_timeout_ms: 10000,
100 request_timeout_ms: 30000,
101 enable_tls: true,
102 max_retries: 5,
103 retry_delay_ms: 2000,
104 max_concurrent_streams: 500,
105 keep_alive_interval_ms: 60000,
106 keep_alive_timeout_ms: 10000,
107 buffer_size: 200_000,
108 order_mode: OrderMode::Unordered,
109 order_timeout_ms: 200,
110 micro_batch_us: 200, }
112 }
113}
114
115#[derive(Debug, Clone)]
116pub struct TransactionFilter {
117 pub account_include: Vec<String>,
118 pub account_exclude: Vec<String>,
119 pub account_required: Vec<String>,
120}
121
122impl TransactionFilter {
123 pub fn new() -> Self {
124 Self {
125 account_include: Vec::new(),
126 account_exclude: Vec::new(),
127 account_required: Vec::new(),
128 }
129 }
130
131 pub fn include_account(mut self, account: impl Into<String>) -> Self {
132 self.account_include.push(account.into());
133 self
134 }
135
136 pub fn exclude_account(mut self, account: impl Into<String>) -> Self {
137 self.account_exclude.push(account.into());
138 self
139 }
140
141 pub fn require_account(mut self, account: impl Into<String>) -> Self {
142 self.account_required.push(account.into());
143 self
144 }
145
146 pub fn from_program_ids(program_ids: Vec<String>) -> Self {
148 Self {
149 account_include: program_ids,
150 account_exclude: Vec::new(),
151 account_required: Vec::new(),
152 }
153 }
154}
155
156impl Default for TransactionFilter {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162#[derive(Debug, Clone)]
163pub struct AccountFilter {
164 pub account: Vec<String>,
165 pub owner: Vec<String>,
166 pub filters: Vec<SubscribeRequestFilterAccountsFilter>,
167}
168
169impl AccountFilter {
170 pub fn new() -> Self {
171 Self { account: Vec::new(), owner: Vec::new(), filters: Vec::new() }
172 }
173
174 pub fn add_account(mut self, account: impl Into<String>) -> Self {
175 self.account.push(account.into());
176 self
177 }
178
179 pub fn add_owner(mut self, owner: impl Into<String>) -> Self {
180 self.owner.push(owner.into());
181 self
182 }
183
184 pub fn add_filter(mut self, filter: SubscribeRequestFilterAccountsFilter) -> Self {
185 self.filters.push(filter);
186 self
187 }
188
189 pub fn from_program_owners(program_ids: Vec<String>) -> Self {
191 Self { account: Vec::new(), owner: program_ids, filters: Vec::new() }
192 }
193}
194
195impl Default for AccountFilter {
196 fn default() -> Self {
197 Self::new()
198 }
199}
200
201#[inline]
204pub fn account_filter_memcmp(offset: u64, bytes: Vec<u8>) -> SubscribeRequestFilterAccountsFilter {
205 SubscribeRequestFilterAccountsFilter {
206 filter: Some(AccountsFilterOneof::Memcmp(SubscribeRequestFilterAccountsFilterMemcmp {
207 offset,
208 data: Some(MemcmpDataOneof::Bytes(bytes)),
209 })),
210 }
211}
212
213#[derive(Debug, Clone)]
214pub struct AccountFilterData {
215 pub memcmp: Option<AccountFilterMemcmp>,
216 pub datasize: Option<u64>,
217}
218
219#[derive(Debug, Clone)]
220pub struct AccountFilterMemcmp {
221 pub offset: u64,
222 pub bytes: Vec<u8>,
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
226pub enum Protocol {
227 PumpFun,
228 PumpSwap,
229 PumpFees,
230 LaunchLab,
232 StonkFun,
234 RaydiumLaunchlab,
236 RaydiumCpmm,
237 RaydiumClmm,
238 RaydiumAmmV4,
239 OrcaWhirlpool,
240 MeteoraPools,
241 MeteoraDammV2,
242 MeteoraDlmm,
243 MeteoraDbc,
244}
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247#[non_exhaustive]
248pub enum EventType {
249 BlockMeta,
251
252 RaydiumLaunchlabTrade,
254 RaydiumLaunchlabPoolCreate,
255 RaydiumLaunchlabMigrateAmm,
256
257 PumpFunTrade, PumpFunBuy, PumpFunSell, PumpFunBuyExactSolIn, PumpFunCreate,
263 PumpFunCreateV2, PumpFunComplete,
265 PumpFunMigrate,
266 PumpFeesCreateFeeSharingConfig,
268 PumpFeesInitializeFeeConfig,
269 PumpFeesResetFeeSharingConfig,
270 PumpFeesRevokeFeeSharingAuthority,
271 PumpFeesTransferFeeSharingAuthority,
272 PumpFeesUpdateAdmin,
273 PumpFeesUpdateFeeConfig,
274 PumpFeesUpdateFeeShares,
275 PumpFeesUpsertFeeTiers,
276 PumpFunMigrateBondingCurveCreator,
278
279 PumpSwapTrade,
281 PumpSwapBuy,
282 PumpSwapSell,
283 PumpSwapCreatePool,
284 PumpSwapLiquidityAdded,
285 PumpSwapLiquidityRemoved,
286 RaydiumCpmmSwap,
291 RaydiumCpmmDeposit,
292 RaydiumCpmmWithdraw,
293 RaydiumCpmmInitialize,
294
295 RaydiumClmmSwap,
297 RaydiumClmmCreatePool,
298 RaydiumClmmOpenPosition,
299 RaydiumClmmClosePosition,
300 RaydiumClmmIncreaseLiquidity,
301 RaydiumClmmDecreaseLiquidity,
302 RaydiumClmmLiquidityChange,
303 RaydiumClmmConfigChange,
304 RaydiumClmmCreatePersonalPosition,
305 RaydiumClmmLiquidityCalculate,
306 RaydiumClmmOpenLimitOrder,
307 RaydiumClmmIncreaseLimitOrder,
308 RaydiumClmmDecreaseLimitOrder,
309 RaydiumClmmSettleLimitOrder,
310 RaydiumClmmUpdateRewardInfos,
311 RaydiumClmmOpenPositionWithTokenExtNft,
312 RaydiumClmmCollectFee,
313
314 RaydiumAmmV4Swap,
316 RaydiumAmmV4Deposit,
317 RaydiumAmmV4Withdraw,
318 RaydiumAmmV4Initialize2,
319 RaydiumAmmV4WithdrawPnl,
320
321 OrcaWhirlpoolSwap,
323 OrcaWhirlpoolLiquidityIncreased,
324 OrcaWhirlpoolLiquidityDecreased,
325 OrcaWhirlpoolPoolInitialized,
326
327 MeteoraPoolsSwap,
329 MeteoraPoolsAddLiquidity,
330 MeteoraPoolsRemoveLiquidity,
331 MeteoraPoolsBootstrapLiquidity,
332 MeteoraPoolsPoolCreated,
333 MeteoraPoolsSetPoolFees,
334
335 MeteoraDammV2Swap,
337 MeteoraDammV2AddLiquidity,
338 MeteoraDammV2RemoveLiquidity,
339 MeteoraDammV2InitializePool,
340 MeteoraDammV2CreatePosition,
341 MeteoraDammV2ClaimPositionFee,
342 MeteoraDammV2ClaimReward,
343 MeteoraDlmmClaimReward,
344 MeteoraDammV2ClosePosition,
345 MeteoraDammV2UpdateDelegatePermission,
346 MeteoraDammV2WithdrawDeadLiquidityReward,
347 MeteoraDammV2WithdrawIneligibleReward,
348 MeteoraDammV2UpdateRewardFunder,
349 MeteoraDammV2UpdateRewardDuration,
350 MeteoraDammV2InitializeReward,
351 MeteoraDammV2FundReward,
352 MeteoraDammV2CreateConfig,
353 MeteoraDammV2CreateDynamicConfig,
354 MeteoraDbcSwap,
361 MeteoraDbcInitializePool,
362 MeteoraDbcCurveComplete,
363
364 MeteoraDlmmSwap,
366 MeteoraDlmmAddLiquidity,
367 MeteoraDlmmRemoveLiquidity,
368 MeteoraDlmmInitializePool,
369 MeteoraDlmmInitializeBinArray,
370 MeteoraDlmmCreatePosition,
371 MeteoraDlmmClosePosition,
372 MeteoraDlmmClaimFee,
373
374 TokenAccount,
376 TokenInfo,
377 NonceAccount,
378 AccountPumpFunGlobal,
379 AccountPumpFunBondingCurve,
380 AccountPumpFunFeeConfig,
381 AccountPumpFunSharingConfig,
382 AccountPumpFunGlobalVolumeAccumulator,
383 AccountPumpFunUserVolumeAccumulator,
384
385 AccountPumpSwapGlobalConfig,
386 AccountPumpSwapPool,
387 AccountRaydiumClmmAmmConfig,
388 AccountRaydiumClmmPoolState,
389 AccountRaydiumClmmTickArrayState,
390 AccountRaydiumCpmmAmmConfig,
391 AccountRaydiumCpmmPoolState,
392 RaydiumCpmmCollectCreatorFee,
393 AccountRaydiumCpmmCreatorFeeShare,
394 AccountOrcaWhirlpool,
395 AccountOrcaPosition,
396 AccountOrcaTickArray,
397 AccountLiquiditySnapshot,
398 AccountRawSnapshot,
400 AccountOrcaFeeTier,
401 AccountOrcaWhirlpoolsConfig,
402 PumpFunPostCompleteBuy,
403 PumpFunSweepBondingCurveFee,
404 PumpSwapSweepPoolFee,
405 PumpRouteIntent,
407 RawInstruction,
408}
409
410#[derive(Debug, Clone)]
411pub struct EventTypeFilter {
412 pub include_only: Option<Vec<EventType>>,
413 pub exclude_types: Option<Vec<EventType>>,
414}
415
416impl EventTypeFilter {
417 pub fn include_only(types: Vec<EventType>) -> Self {
418 Self { include_only: Some(types), exclude_types: None }
419 }
420
421 pub fn exclude_types(types: Vec<EventType>) -> Self {
422 Self { include_only: None, exclude_types: Some(types) }
423 }
424
425 #[inline]
426 fn includes_any(&self, event_types: &[EventType]) -> bool {
427 event_types.iter().any(|event_type| self.should_include(*event_type))
428 }
429
430 pub fn should_include(&self, event_type: EventType) -> bool {
431 if event_type == EventType::RawInstruction
432 && self.exclude_types.as_ref().is_some_and(|types| types.contains(&event_type))
433 {
434 return false;
435 }
436 if let Some(ref include_only) = self.include_only {
437 if include_only.contains(&event_type) {
439 return true;
440 }
441 if matches!(
442 event_type,
443 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
444 ) {
445 if pumpfun_trade_filter_is_generic(include_only) {
446 return true;
447 }
448 if event_type == EventType::PumpFunBuyExactSolIn
449 && pumpfun_buy_filter_is_generic(include_only)
450 {
451 return true;
452 }
453 return false;
454 }
455 if is_pumpfun_create_family(event_type) {
456 return include_only.iter().any(|t| is_pumpfun_create_family(*t));
457 }
458 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell) {
459 return include_only.contains(&EventType::PumpSwapTrade);
460 }
461 return false;
462 }
463
464 if let Some(ref exclude_types) = self.exclude_types {
465 if exclude_types.contains(&event_type) {
466 return false;
467 }
468 if matches!(
469 event_type,
470 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
471 ) && exclude_types.contains(&EventType::PumpFunTrade)
472 {
473 return false;
474 }
475 if event_type == EventType::PumpFunBuyExactSolIn
476 && exclude_types.contains(&EventType::PumpFunBuy)
477 {
478 return false;
479 }
480 if is_pumpfun_create_family(event_type)
481 && exclude_types.iter().any(|t| is_pumpfun_create_family(*t))
482 {
483 return false;
484 }
485 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell)
486 && exclude_types.contains(&EventType::PumpSwapTrade)
487 {
488 return false;
489 }
490 return true;
491 }
492
493 true
494 }
495
496 pub(crate) fn includes_pump_route(&self, kind: crate::core::events::PumpRouteKind) -> bool {
500 if self
501 .exclude_types
502 .as_ref()
503 .is_some_and(|types| types.contains(&EventType::PumpRouteIntent))
504 {
505 return false;
506 }
507 self.include_only.as_ref().is_some_and(|types| types.contains(&EventType::PumpRouteIntent))
508 || self.should_include(EventType::PumpFunTrade)
509 || (kind == crate::core::events::PumpRouteKind::MultiHopSwap
510 && self.should_include(EventType::PumpSwapTrade))
511 }
512
513 pub(crate) fn includes_unresolved_pumpfun(&self) -> bool {
514 !self.exclude_types.as_ref().is_some_and(|types| types.contains(&EventType::PumpFunTrade))
515 && self.should_include(EventType::PumpFunTrade)
516 }
517
518 pub fn should_include_dex_event(&self, event: &crate::core::events::DexEvent) -> bool {
519 if let crate::core::events::DexEvent::PumpFunTrade(t) = event {
520 if t.parse_status == crate::core::events::PumpFunParseStatus::Unresolved {
521 return self.includes_unresolved_pumpfun();
524 }
525 }
526 if let crate::core::events::DexEvent::RawInstruction(raw) = event {
527 return crate::core::events::raw_instruction_matches_filter(&raw.dexes, self);
528 }
529 if let crate::core::events::DexEvent::PumpRouteIntent(intent) = event {
530 return self.includes_pump_route(intent.kind);
531 }
532 let Some(event_type) = event_type_from_dex_event(event) else { return true };
533 self.should_include(event_type)
534 }
535
536 #[inline]
537 pub fn includes_block_meta(&self) -> bool {
538 if let Some(ref include_only) = self.include_only {
539 return include_only.contains(&EventType::BlockMeta);
540 }
541 false
542 }
543
544 #[inline]
545 pub fn normalize_dex_event(
546 &self,
547 event: crate::core::events::DexEvent,
548 ) -> crate::core::events::DexEvent {
549 use crate::core::events::DexEvent;
550
551 let Some(ref include_only) = self.include_only else { return event };
552 if pumpfun_trade_filter_is_generic(include_only) {
553 return match event {
554 DexEvent::PumpFunBuy(t)
555 | DexEvent::PumpFunSell(t)
556 | DexEvent::PumpFunBuyExactSolIn(t) => DexEvent::PumpFunTrade(t),
557 other => other,
558 };
559 }
560 if pumpfun_buy_filter_is_generic(include_only) {
561 return match event {
562 DexEvent::PumpFunBuyExactSolIn(t) => DexEvent::PumpFunBuy(t),
563 other => other,
564 };
565 }
566
567 event
568 }
569
570 #[inline]
571 pub fn includes_pumpfun(&self) -> bool {
572 self.includes_any(&[
573 EventType::PumpFunTrade,
574 EventType::PumpFunBuy,
575 EventType::PumpFunSell,
576 EventType::PumpFunBuyExactSolIn,
577 EventType::PumpFunCreate,
578 EventType::PumpFunCreateV2,
579 EventType::PumpFunComplete,
580 EventType::PumpFunMigrate,
581 EventType::PumpFunMigrateBondingCurveCreator,
582 EventType::PumpFunPostCompleteBuy,
583 EventType::PumpFunSweepBondingCurveFee,
584 ])
585 }
586
587 #[inline]
588 pub fn includes_meteora_damm_v2(&self) -> bool {
589 self.includes_any(&[
590 EventType::MeteoraDammV2Swap,
591 EventType::MeteoraDammV2AddLiquidity,
592 EventType::MeteoraDammV2CreatePosition,
593 EventType::MeteoraDammV2ClaimPositionFee,
594 EventType::MeteoraDammV2ClaimReward,
595 EventType::MeteoraDammV2ClosePosition,
596 EventType::MeteoraDammV2InitializePool,
597 EventType::MeteoraDammV2RemoveLiquidity,
598 EventType::MeteoraDammV2UpdateDelegatePermission,
599 EventType::MeteoraDammV2WithdrawDeadLiquidityReward,
600 EventType::MeteoraDammV2WithdrawIneligibleReward,
601 EventType::MeteoraDammV2UpdateRewardFunder,
602 EventType::MeteoraDammV2UpdateRewardDuration,
603 EventType::MeteoraDammV2InitializeReward,
604 EventType::MeteoraDammV2FundReward,
605 EventType::MeteoraDammV2CreateConfig,
606 EventType::MeteoraDammV2CreateDynamicConfig,
607 ])
608 }
609
610 #[inline]
611 pub fn includes_pump_fees(&self) -> bool {
612 self.includes_any(&[
613 EventType::PumpFeesCreateFeeSharingConfig,
614 EventType::PumpFeesInitializeFeeConfig,
615 EventType::PumpFeesResetFeeSharingConfig,
616 EventType::PumpFeesRevokeFeeSharingAuthority,
617 EventType::PumpFeesTransferFeeSharingAuthority,
618 EventType::PumpFeesUpdateAdmin,
619 EventType::PumpFeesUpdateFeeConfig,
620 EventType::PumpFeesUpdateFeeShares,
621 EventType::PumpFeesUpsertFeeTiers,
622 ])
623 }
624
625 #[inline]
627 pub fn includes_pumpswap(&self) -> bool {
628 self.includes_any(&[
629 EventType::PumpSwapTrade,
630 EventType::PumpSwapBuy,
631 EventType::PumpSwapSell,
632 EventType::PumpSwapCreatePool,
633 EventType::PumpSwapSweepPoolFee,
634 EventType::PumpSwapLiquidityAdded,
635 EventType::PumpSwapLiquidityRemoved,
636 ])
637 }
638
639 #[inline]
641 pub fn includes_raydium_launchlab(&self) -> bool {
642 self.includes_any(&[
643 EventType::RaydiumLaunchlabTrade,
644 EventType::RaydiumLaunchlabPoolCreate,
645 EventType::RaydiumLaunchlabMigrateAmm,
646 ])
647 }
648
649 #[inline]
650 pub fn includes_raydium_cpmm(&self) -> bool {
651 self.includes_any(&[
652 EventType::RaydiumCpmmSwap,
653 EventType::RaydiumCpmmDeposit,
654 EventType::RaydiumCpmmWithdraw,
655 EventType::RaydiumCpmmInitialize,
656 EventType::RaydiumCpmmCollectCreatorFee,
657 ])
658 }
659
660 #[inline]
661 pub fn includes_raydium_clmm(&self) -> bool {
662 self.includes_any(&[
663 EventType::RaydiumClmmSwap,
664 EventType::RaydiumClmmCreatePool,
665 EventType::RaydiumClmmOpenPosition,
666 EventType::RaydiumClmmClosePosition,
667 EventType::RaydiumClmmIncreaseLiquidity,
668 EventType::RaydiumClmmDecreaseLiquidity,
669 EventType::RaydiumClmmLiquidityChange,
670 EventType::RaydiumClmmConfigChange,
671 EventType::RaydiumClmmCreatePersonalPosition,
672 EventType::RaydiumClmmLiquidityCalculate,
673 EventType::RaydiumClmmOpenLimitOrder,
674 EventType::RaydiumClmmIncreaseLimitOrder,
675 EventType::RaydiumClmmDecreaseLimitOrder,
676 EventType::RaydiumClmmSettleLimitOrder,
677 EventType::RaydiumClmmUpdateRewardInfos,
678 EventType::RaydiumClmmOpenPositionWithTokenExtNft,
679 EventType::RaydiumClmmCollectFee,
680 ])
681 }
682
683 #[inline]
684 pub fn includes_raydium_amm_v4(&self) -> bool {
685 self.includes_any(&[
686 EventType::RaydiumAmmV4Swap,
687 EventType::RaydiumAmmV4Deposit,
688 EventType::RaydiumAmmV4Withdraw,
689 EventType::RaydiumAmmV4Initialize2,
690 EventType::RaydiumAmmV4WithdrawPnl,
691 ])
692 }
693
694 #[inline]
695 pub fn includes_orca_whirlpool(&self) -> bool {
696 self.includes_any(&[
697 EventType::OrcaWhirlpoolSwap,
698 EventType::OrcaWhirlpoolLiquidityIncreased,
699 EventType::OrcaWhirlpoolLiquidityDecreased,
700 EventType::OrcaWhirlpoolPoolInitialized,
701 ])
702 }
703
704 #[inline]
705 pub fn includes_meteora_pools(&self) -> bool {
706 self.includes_any(&[
707 EventType::MeteoraPoolsSwap,
708 EventType::MeteoraPoolsAddLiquidity,
709 EventType::MeteoraPoolsRemoveLiquidity,
710 EventType::MeteoraPoolsBootstrapLiquidity,
711 EventType::MeteoraPoolsPoolCreated,
712 EventType::MeteoraPoolsSetPoolFees,
713 ])
714 }
715
716 #[inline]
717 pub fn includes_meteora_dlmm(&self) -> bool {
718 self.includes_any(&[
719 EventType::MeteoraDlmmSwap,
720 EventType::MeteoraDlmmAddLiquidity,
721 EventType::MeteoraDlmmRemoveLiquidity,
722 EventType::MeteoraDlmmInitializePool,
723 EventType::MeteoraDlmmInitializeBinArray,
724 EventType::MeteoraDlmmCreatePosition,
725 EventType::MeteoraDlmmClosePosition,
726 EventType::MeteoraDlmmClaimFee,
727 EventType::MeteoraDlmmClaimReward,
728 ])
729 }
730
731 #[inline]
732 pub fn includes_meteora_dbc(&self) -> bool {
733 self.includes_any(&[
734 EventType::MeteoraDbcSwap,
735 EventType::MeteoraDbcInitializePool,
736 EventType::MeteoraDbcCurveComplete,
737 ])
738 }
739}
740
741#[inline]
742fn pumpfun_trade_filter_is_generic(include_only: &[EventType]) -> bool {
743 include_only.contains(&EventType::PumpFunTrade)
744 && !include_only.iter().any(|t| {
745 matches!(
746 t,
747 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
748 )
749 })
750}
751
752#[inline]
753fn pumpfun_buy_filter_is_generic(include_only: &[EventType]) -> bool {
754 include_only.contains(&EventType::PumpFunBuy)
755 && !include_only.contains(&EventType::PumpFunBuyExactSolIn)
756}
757
758#[inline]
759fn is_pumpfun_create_family(event_type: EventType) -> bool {
760 matches!(event_type, EventType::PumpFunCreate | EventType::PumpFunCreateV2)
761}
762
763#[inline]
764pub fn event_type_from_dex_event(event: &crate::core::events::DexEvent) -> Option<EventType> {
765 use crate::core::events::DexEvent;
766 match event {
767 DexEvent::PumpRouteIntent(_) => Some(EventType::PumpRouteIntent),
768 DexEvent::RawInstruction(_) => Some(EventType::RawInstruction),
769 DexEvent::PumpFunCreate(_) => Some(EventType::PumpFunCreate),
770 DexEvent::PumpFunCreateV2(_) => Some(EventType::PumpFunCreateV2),
771 DexEvent::PumpFunTrade(_) => Some(EventType::PumpFunTrade),
772 DexEvent::PumpFunBuy(_) => Some(EventType::PumpFunBuy),
773 DexEvent::PumpFunSell(_) => Some(EventType::PumpFunSell),
774 DexEvent::PumpFunBuyExactSolIn(_) => Some(EventType::PumpFunBuyExactSolIn),
775 DexEvent::PumpFunMigrate(_) => Some(EventType::PumpFunMigrate),
776 DexEvent::PumpFeesCreateFeeSharingConfig(_) => {
777 Some(EventType::PumpFeesCreateFeeSharingConfig)
778 }
779 DexEvent::PumpFeesInitializeFeeConfig(_) => Some(EventType::PumpFeesInitializeFeeConfig),
780 DexEvent::PumpFeesResetFeeSharingConfig(_) => {
781 Some(EventType::PumpFeesResetFeeSharingConfig)
782 }
783 DexEvent::PumpFeesRevokeFeeSharingAuthority(_) => {
784 Some(EventType::PumpFeesRevokeFeeSharingAuthority)
785 }
786 DexEvent::PumpFeesTransferFeeSharingAuthority(_) => {
787 Some(EventType::PumpFeesTransferFeeSharingAuthority)
788 }
789 DexEvent::PumpFeesUpdateAdmin(_) => Some(EventType::PumpFeesUpdateAdmin),
790 DexEvent::PumpFeesUpdateFeeConfig(_) => Some(EventType::PumpFeesUpdateFeeConfig),
791 DexEvent::PumpFeesUpdateFeeShares(_) => Some(EventType::PumpFeesUpdateFeeShares),
792 DexEvent::PumpFeesUpsertFeeTiers(_) => Some(EventType::PumpFeesUpsertFeeTiers),
793 DexEvent::PumpFunPostCompleteBuy(_) => Some(EventType::PumpFunPostCompleteBuy),
794 DexEvent::PumpFunSweepBondingCurveFee(_) => Some(EventType::PumpFunSweepBondingCurveFee),
795 DexEvent::PumpFunComplete(_) => Some(EventType::PumpFunComplete),
796 DexEvent::PumpSwapSweepPoolFee(_) => Some(EventType::PumpSwapSweepPoolFee),
797 DexEvent::PumpFunMigrateBondingCurveCreator(_) => {
798 Some(EventType::PumpFunMigrateBondingCurveCreator)
799 }
800 DexEvent::PumpFunGlobalAccount(_) => Some(EventType::AccountPumpFunGlobal),
801 DexEvent::PumpFunBondingCurveAccount(_) => Some(EventType::AccountPumpFunBondingCurve),
802 DexEvent::PumpFunFeeConfigAccount(_) => Some(EventType::AccountPumpFunFeeConfig),
803 DexEvent::PumpFunSharingConfigAccount(_) => Some(EventType::AccountPumpFunSharingConfig),
804 DexEvent::PumpFunGlobalVolumeAccumulatorAccount(_) => {
805 Some(EventType::AccountPumpFunGlobalVolumeAccumulator)
806 }
807 DexEvent::PumpFunUserVolumeAccumulatorAccount(_) => {
808 Some(EventType::AccountPumpFunUserVolumeAccumulator)
809 }
810 DexEvent::PumpSwapTrade(_) => Some(EventType::PumpSwapTrade),
811 DexEvent::PumpSwapBuy(_) => Some(EventType::PumpSwapBuy),
812 DexEvent::PumpSwapSell(_) => Some(EventType::PumpSwapSell),
813 DexEvent::PumpSwapCreatePool(_) => Some(EventType::PumpSwapCreatePool),
814 DexEvent::PumpSwapLiquidityAdded(_) => Some(EventType::PumpSwapLiquidityAdded),
815 DexEvent::PumpSwapLiquidityRemoved(_) => Some(EventType::PumpSwapLiquidityRemoved),
816 DexEvent::MeteoraDammV2Swap(_) => Some(EventType::MeteoraDammV2Swap),
817 DexEvent::MeteoraDammV2ClaimPositionFee(_) => {
818 Some(EventType::MeteoraDammV2ClaimPositionFee)
819 }
820 DexEvent::MeteoraDammV2ClaimReward(_) => Some(EventType::MeteoraDammV2ClaimReward),
821 DexEvent::MeteoraDlmmClaimReward(_) => Some(EventType::MeteoraDlmmClaimReward),
822 DexEvent::MeteoraDammV2CreatePosition(_) => Some(EventType::MeteoraDammV2CreatePosition),
823 DexEvent::MeteoraDammV2ClosePosition(_) => Some(EventType::MeteoraDammV2ClosePosition),
824 DexEvent::MeteoraDammV2AddLiquidity(_) => Some(EventType::MeteoraDammV2AddLiquidity),
825 DexEvent::MeteoraDammV2RemoveLiquidity(_) => Some(EventType::MeteoraDammV2RemoveLiquidity),
826 DexEvent::MeteoraDammV2InitializePool(_) => Some(EventType::MeteoraDammV2InitializePool),
827 DexEvent::MeteoraDammV2UpdateDelegatePermission(_) => {
828 Some(EventType::MeteoraDammV2UpdateDelegatePermission)
829 }
830 DexEvent::MeteoraDammV2WithdrawDeadLiquidityReward(_) => {
831 Some(EventType::MeteoraDammV2WithdrawDeadLiquidityReward)
832 }
833 DexEvent::MeteoraDammV2WithdrawIneligibleReward(_) => {
834 Some(EventType::MeteoraDammV2WithdrawIneligibleReward)
835 }
836 DexEvent::MeteoraDammV2UpdateRewardFunder(_) => {
837 Some(EventType::MeteoraDammV2UpdateRewardFunder)
838 }
839 DexEvent::MeteoraDammV2UpdateRewardDuration(_) => {
840 Some(EventType::MeteoraDammV2UpdateRewardDuration)
841 }
842 DexEvent::MeteoraDammV2InitializeReward(_) => {
843 Some(EventType::MeteoraDammV2InitializeReward)
844 }
845 DexEvent::MeteoraDammV2FundReward(_) => Some(EventType::MeteoraDammV2FundReward),
846 DexEvent::MeteoraDammV2CreateConfig(_) => Some(EventType::MeteoraDammV2CreateConfig),
847 DexEvent::MeteoraDammV2CreateDynamicConfig(_) => {
848 Some(EventType::MeteoraDammV2CreateDynamicConfig)
849 }
850 DexEvent::MeteoraDbcSwap(_) => Some(EventType::MeteoraDbcSwap),
851 DexEvent::MeteoraDbcInitializePool(_) => Some(EventType::MeteoraDbcInitializePool),
852 DexEvent::MeteoraDbcCurveComplete(_) => Some(EventType::MeteoraDbcCurveComplete),
853 DexEvent::RaydiumLaunchlabTrade(_) => Some(EventType::RaydiumLaunchlabTrade),
854 DexEvent::RaydiumLaunchlabPoolCreate(_) => Some(EventType::RaydiumLaunchlabPoolCreate),
855 DexEvent::RaydiumLaunchlabMigrateAmm(_) => Some(EventType::RaydiumLaunchlabMigrateAmm),
856 DexEvent::RaydiumClmmSwap(_) => Some(EventType::RaydiumClmmSwap),
857 DexEvent::RaydiumClmmCreatePool(_) => Some(EventType::RaydiumClmmCreatePool),
858 DexEvent::RaydiumClmmOpenPosition(_) => Some(EventType::RaydiumClmmOpenPosition),
859 DexEvent::RaydiumClmmOpenPositionWithTokenExtNft(_) => {
860 Some(EventType::RaydiumClmmOpenPositionWithTokenExtNft)
861 }
862 DexEvent::RaydiumClmmClosePosition(_) => Some(EventType::RaydiumClmmClosePosition),
863 DexEvent::RaydiumClmmIncreaseLiquidity(_) => Some(EventType::RaydiumClmmIncreaseLiquidity),
864 DexEvent::RaydiumClmmDecreaseLiquidity(_) => Some(EventType::RaydiumClmmDecreaseLiquidity),
865 DexEvent::RaydiumClmmLiquidityChange(_) => Some(EventType::RaydiumClmmLiquidityChange),
866 DexEvent::RaydiumClmmConfigChange(_) => Some(EventType::RaydiumClmmConfigChange),
867 DexEvent::RaydiumClmmCreatePersonalPosition(_) => {
868 Some(EventType::RaydiumClmmCreatePersonalPosition)
869 }
870 DexEvent::RaydiumClmmLiquidityCalculate(_) => {
871 Some(EventType::RaydiumClmmLiquidityCalculate)
872 }
873 DexEvent::RaydiumClmmOpenLimitOrder(_) => Some(EventType::RaydiumClmmOpenLimitOrder),
874 DexEvent::RaydiumClmmIncreaseLimitOrder(_) => {
875 Some(EventType::RaydiumClmmIncreaseLimitOrder)
876 }
877 DexEvent::RaydiumClmmDecreaseLimitOrder(_) => {
878 Some(EventType::RaydiumClmmDecreaseLimitOrder)
879 }
880 DexEvent::RaydiumClmmSettleLimitOrder(_) => Some(EventType::RaydiumClmmSettleLimitOrder),
881 DexEvent::RaydiumClmmUpdateRewardInfos(_) => Some(EventType::RaydiumClmmUpdateRewardInfos),
882 DexEvent::RaydiumClmmCollectFee(_) => Some(EventType::RaydiumClmmCollectFee),
883 DexEvent::RaydiumClmmAmmConfigAccount(_) => Some(EventType::AccountRaydiumClmmAmmConfig),
884 DexEvent::RaydiumClmmPoolStateAccount(_) => Some(EventType::AccountRaydiumClmmPoolState),
885 DexEvent::RaydiumClmmTickArrayStateAccount(_) => {
886 Some(EventType::AccountRaydiumClmmTickArrayState)
887 }
888 DexEvent::RaydiumCpmmSwap(_) => Some(EventType::RaydiumCpmmSwap),
889 DexEvent::RaydiumCpmmDeposit(_) => Some(EventType::RaydiumCpmmDeposit),
890 DexEvent::RaydiumCpmmWithdraw(_) => Some(EventType::RaydiumCpmmWithdraw),
891 DexEvent::RaydiumCpmmInitialize(_) => Some(EventType::RaydiumCpmmInitialize),
892 DexEvent::RaydiumCpmmAmmConfigAccount(_) => Some(EventType::AccountRaydiumCpmmAmmConfig),
893 DexEvent::RaydiumCpmmPoolStateAccount(_) => Some(EventType::AccountRaydiumCpmmPoolState),
894 DexEvent::RaydiumCpmmCollectCreatorFee(_) => Some(EventType::RaydiumCpmmCollectCreatorFee),
895 DexEvent::RaydiumCpmmCreatorFeeShareAccount(_) => {
896 Some(EventType::AccountRaydiumCpmmCreatorFeeShare)
897 }
898 DexEvent::RaydiumAmmV4Swap(_) => Some(EventType::RaydiumAmmV4Swap),
899 DexEvent::RaydiumAmmV4Deposit(_) => Some(EventType::RaydiumAmmV4Deposit),
900 DexEvent::RaydiumAmmV4Initialize2(_) => Some(EventType::RaydiumAmmV4Initialize2),
901 DexEvent::RaydiumAmmV4Withdraw(_) => Some(EventType::RaydiumAmmV4Withdraw),
902 DexEvent::RaydiumAmmV4WithdrawPnl(_) => Some(EventType::RaydiumAmmV4WithdrawPnl),
903 DexEvent::OrcaWhirlpoolSwap(_) => Some(EventType::OrcaWhirlpoolSwap),
904 DexEvent::OrcaWhirlpoolLiquidityIncreased(_) => {
905 Some(EventType::OrcaWhirlpoolLiquidityIncreased)
906 }
907 DexEvent::OrcaWhirlpoolLiquidityDecreased(_) => {
908 Some(EventType::OrcaWhirlpoolLiquidityDecreased)
909 }
910 DexEvent::OrcaWhirlpoolPoolInitialized(_) => Some(EventType::OrcaWhirlpoolPoolInitialized),
911 DexEvent::OrcaWhirlpoolAccount(_) => Some(EventType::AccountOrcaWhirlpool),
912 DexEvent::OrcaPositionAccount(_) => Some(EventType::AccountOrcaPosition),
913 DexEvent::OrcaTickArrayAccount(_) => Some(EventType::AccountOrcaTickArray),
914 DexEvent::LiquidityAccountSnapshot(_) => Some(EventType::AccountLiquiditySnapshot),
915 DexEvent::RawAccountSnapshot(_) => Some(EventType::AccountRawSnapshot),
916 DexEvent::OrcaFeeTierAccount(_) => Some(EventType::AccountOrcaFeeTier),
917 DexEvent::OrcaWhirlpoolsConfigAccount(_) => Some(EventType::AccountOrcaWhirlpoolsConfig),
918 DexEvent::MeteoraPoolsSwap(_) => Some(EventType::MeteoraPoolsSwap),
919 DexEvent::MeteoraPoolsAddLiquidity(_) => Some(EventType::MeteoraPoolsAddLiquidity),
920 DexEvent::MeteoraPoolsRemoveLiquidity(_) => Some(EventType::MeteoraPoolsRemoveLiquidity),
921 DexEvent::MeteoraPoolsBootstrapLiquidity(_) => {
922 Some(EventType::MeteoraPoolsBootstrapLiquidity)
923 }
924 DexEvent::MeteoraPoolsPoolCreated(_) => Some(EventType::MeteoraPoolsPoolCreated),
925 DexEvent::MeteoraPoolsSetPoolFees(_) => Some(EventType::MeteoraPoolsSetPoolFees),
926 DexEvent::MeteoraDlmmSwap(_) => Some(EventType::MeteoraDlmmSwap),
927 DexEvent::MeteoraDlmmAddLiquidity(_) => Some(EventType::MeteoraDlmmAddLiquidity),
928 DexEvent::MeteoraDlmmRemoveLiquidity(_) => Some(EventType::MeteoraDlmmRemoveLiquidity),
929 DexEvent::MeteoraDlmmInitializePool(_) => Some(EventType::MeteoraDlmmInitializePool),
930 DexEvent::MeteoraDlmmInitializeBinArray(_) => {
931 Some(EventType::MeteoraDlmmInitializeBinArray)
932 }
933 DexEvent::MeteoraDlmmCreatePosition(_) => Some(EventType::MeteoraDlmmCreatePosition),
934 DexEvent::MeteoraDlmmClosePosition(_) => Some(EventType::MeteoraDlmmClosePosition),
935 DexEvent::MeteoraDlmmClaimFee(_) => Some(EventType::MeteoraDlmmClaimFee),
936 DexEvent::TokenAccount(_) => Some(EventType::TokenAccount),
937 DexEvent::TokenInfo(_) => Some(EventType::TokenInfo),
938 DexEvent::NonceAccount(_) => Some(EventType::NonceAccount),
939 DexEvent::PumpSwapGlobalConfigAccount(_) => Some(EventType::AccountPumpSwapGlobalConfig),
940 DexEvent::PumpSwapPoolAccount(_) => Some(EventType::AccountPumpSwapPool),
941 DexEvent::BlockMeta(_) => Some(EventType::BlockMeta),
942 DexEvent::Error(_) => None,
943 }
944}
945
946#[cfg(test)]
947mod event_type_filter_tests {
948 use super::*;
949
950 #[test]
951 fn generic_trade_filters_cover_specific_trade_variants() {
952 let pump = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
953 assert!(pump.should_include(EventType::PumpFunTrade));
954 assert!(pump.should_include(EventType::PumpFunBuy));
955 assert!(pump.should_include(EventType::PumpFunSell));
956 assert!(pump.should_include(EventType::PumpFunBuyExactSolIn));
957
958 let pump_specific = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
959 assert!(!pump_specific.should_include(EventType::PumpFunTrade));
960 assert!(pump_specific.should_include(EventType::PumpFunBuy));
961 assert!(!pump_specific.should_include(EventType::PumpFunSell));
962 assert!(pump_specific.should_include(EventType::PumpFunBuyExactSolIn));
963
964 let pump_exact_buy = EventTypeFilter::include_only(vec![EventType::PumpFunBuyExactSolIn]);
965 assert!(!pump_exact_buy.should_include(EventType::PumpFunTrade));
966 assert!(!pump_exact_buy.should_include(EventType::PumpFunBuy));
967 assert!(!pump_exact_buy.should_include(EventType::PumpFunSell));
968 assert!(pump_exact_buy.should_include(EventType::PumpFunBuyExactSolIn));
969
970 let pumpswap = EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]);
971 assert!(pumpswap.should_include(EventType::PumpSwapBuy));
972 assert!(pumpswap.should_include(EventType::PumpSwapSell));
973
974 let exclude_pumpswap = EventTypeFilter::exclude_types(vec![EventType::PumpSwapTrade]);
975 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapBuy));
976 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapSell));
977 }
978
979 #[test]
980 fn generic_pumpfun_trade_filter_normalizes_specific_variants() {
981 use crate::core::events::{DexEvent, PumpFunTradeEvent};
982
983 let filter = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
984 let event = DexEvent::PumpFunBuy(PumpFunTradeEvent { is_buy: true, ..Default::default() });
985 assert!(matches!(filter.normalize_dex_event(event), DexEvent::PumpFunTrade(_)));
986
987 let specific_filter =
988 EventTypeFilter::include_only(vec![EventType::PumpFunTrade, EventType::PumpFunBuy]);
989 let event = DexEvent::PumpFunBuy(PumpFunTradeEvent { is_buy: true, ..Default::default() });
990 assert!(matches!(specific_filter.normalize_dex_event(event), DexEvent::PumpFunBuy(_)));
991
992 let buy_filter = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
993 let event = DexEvent::PumpFunBuyExactSolIn(PumpFunTradeEvent {
994 is_buy: true,
995 ..Default::default()
996 });
997 assert!(matches!(buy_filter.normalize_dex_event(event), DexEvent::PumpFunBuy(_)));
998
999 let exact_filter = EventTypeFilter::include_only(vec![EventType::PumpFunBuyExactSolIn]);
1000 let event = DexEvent::PumpFunBuyExactSolIn(PumpFunTradeEvent {
1001 is_buy: true,
1002 ..Default::default()
1003 });
1004 assert!(matches!(
1005 exact_filter.normalize_dex_event(event),
1006 DexEvent::PumpFunBuyExactSolIn(_)
1007 ));
1008
1009 let create_and_trade_filter =
1010 EventTypeFilter::include_only(vec![EventType::PumpFunCreate, EventType::PumpFunTrade]);
1011 let event =
1012 DexEvent::PumpFunSell(PumpFunTradeEvent { is_buy: false, ..Default::default() });
1013 assert!(matches!(
1014 create_and_trade_filter.normalize_dex_event(event),
1015 DexEvent::PumpFunTrade(_)
1016 ));
1017 }
1018
1019 #[test]
1020 fn all_protocol_groups_are_filterable() {
1021 assert!(EventTypeFilter::include_only(vec![EventType::PumpFunTrade]).includes_pumpfun());
1022 assert!(!EventTypeFilter::include_only(vec![EventType::AccountPumpFunGlobal])
1023 .includes_pumpfun());
1024 assert!(
1025 !EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateAdmin]).includes_pumpfun()
1026 );
1027 assert!(EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]).includes_pumpswap());
1028 assert!(EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateFeeShares])
1029 .includes_pump_fees());
1030 assert!(EventTypeFilter::include_only(vec![EventType::RaydiumLaunchlabTrade])
1031 .includes_raydium_launchlab());
1032 assert!(
1033 EventTypeFilter::include_only(vec![EventType::RaydiumCpmmSwap]).includes_raydium_cpmm()
1034 );
1035 assert!(
1036 EventTypeFilter::include_only(vec![EventType::RaydiumClmmSwap]).includes_raydium_clmm()
1037 );
1038 assert!(!EventTypeFilter::include_only(vec![EventType::AccountRaydiumClmmPoolState])
1039 .includes_raydium_clmm());
1040 assert!(EventTypeFilter::include_only(vec![EventType::RaydiumAmmV4Swap])
1041 .includes_raydium_amm_v4());
1042 assert!(EventTypeFilter::include_only(vec![EventType::OrcaWhirlpoolSwap])
1043 .includes_orca_whirlpool());
1044 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraPoolsSwap])
1045 .includes_meteora_pools());
1046 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2Swap])
1047 .includes_meteora_damm_v2());
1048 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2InitializePool])
1049 .includes_meteora_damm_v2());
1050 assert!(
1051 EventTypeFilter::include_only(vec![EventType::MeteoraDlmmSwap]).includes_meteora_dlmm()
1052 );
1053 assert!(
1054 EventTypeFilter::include_only(vec![EventType::MeteoraDbcSwap]).includes_meteora_dbc()
1055 );
1056 }
1057
1058 #[test]
1059 fn exclude_filters_do_not_skip_whole_protocol_groups() {
1060 let raydium = EventTypeFilter::exclude_types(vec![EventType::RaydiumCpmmSwap]);
1061 assert!(raydium.includes_raydium_cpmm());
1062 assert!(!raydium.should_include(EventType::RaydiumCpmmSwap));
1063 assert!(raydium.should_include(EventType::RaydiumCpmmDeposit));
1064
1065 let all_cpmm = EventTypeFilter::exclude_types(vec![
1066 EventType::RaydiumCpmmSwap,
1067 EventType::RaydiumCpmmDeposit,
1068 EventType::RaydiumCpmmWithdraw,
1069 EventType::RaydiumCpmmInitialize,
1070 EventType::RaydiumCpmmCollectCreatorFee,
1071 ]);
1072 assert!(!all_cpmm.includes_raydium_cpmm());
1073
1074 let all_launchlab = EventTypeFilter::exclude_types(vec![
1075 EventType::RaydiumLaunchlabTrade,
1076 EventType::RaydiumLaunchlabPoolCreate,
1077 EventType::RaydiumLaunchlabMigrateAmm,
1078 ]);
1079 assert!(!all_launchlab.includes_raydium_launchlab());
1080
1081 let pump = EventTypeFilter::exclude_types(vec![EventType::PumpFunBuy]);
1082 assert!(pump.includes_pumpfun());
1083 assert!(!pump.should_include(EventType::PumpFunBuy));
1084 assert!(!pump.should_include(EventType::PumpFunBuyExactSolIn));
1085 assert!(pump.should_include(EventType::PumpFunSell));
1086 }
1087}
1088
1089#[derive(Debug, Clone)]
1090pub struct SlotFilter {
1091 pub min_slot: Option<u64>,
1092 pub max_slot: Option<u64>,
1093}
1094
1095impl SlotFilter {
1096 pub fn new() -> Self {
1097 Self { min_slot: None, max_slot: None }
1098 }
1099
1100 pub fn min_slot(mut self, slot: u64) -> Self {
1101 self.min_slot = Some(slot);
1102 self
1103 }
1104
1105 pub fn max_slot(mut self, slot: u64) -> Self {
1106 self.max_slot = Some(slot);
1107 self
1108 }
1109}
1110
1111impl Default for SlotFilter {
1112 fn default() -> Self {
1113 Self::new()
1114 }
1115}