Skip to main content

sol_parser_sdk/grpc/
types.rs

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/// 事件输出顺序模式
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
10pub enum OrderMode {
11    /// 无序模式:收到即输出,超低延迟 (10-20μs)
12    #[default]
13    Unordered,
14    /// 有序模式:按 slot + tx_index 排序后输出
15    /// 新 slot 或超时触发排序输出;不保证已收齐全部交易。
16    /// 已关闭 slot 或输出水位之前的迟到事件会丢弃并记录 continuity break 警告。
17    /// 延迟增加约 1-50ms(取决于 slot 内交易数量)
18    Ordered,
19    /// 流式有序模式:连续序列立即释放,低延迟 + 顺序保证
20    /// 只要收到从 0 开始的连续 tx_index 序列,立即释放
21    /// 延迟约 0.1-5ms,比 Ordered 低 5-50 倍
22    StreamingOrdered,
23    /// 微批次模式:极短时间窗口内收集事件,窗口结束后排序释放
24    /// 窗口大小由 micro_batch_us 配置(默认 100μs)
25    /// 延迟约 50-200μs,接近 Unordered 但保证顺序
26    MicroBatch,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ClientConfig {
31    /// 是否启用性能监控
32    pub enable_metrics: bool,
33    /// 连接超时时间(毫秒)
34    pub connection_timeout_ms: u64,
35    /// 请求超时时间(毫秒)
36    pub request_timeout_ms: u64,
37    /// 是否启用TLS
38    pub enable_tls: bool,
39    pub max_retries: u32,
40    /// Automatic reconnect base delay; exponential backoff caps at 60s and resets
41    /// after an established stream. Zero is clamped to 1ms to avoid a busy loop.
42    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    /// 事件输出顺序模式
48    pub order_mode: OrderMode,
49    /// 有序模式下,slot 超时时间(毫秒)
50    /// 超过此时间未收到新 slot 信号,强制输出当前缓冲的事件
51    pub order_timeout_ms: u64,
52    /// MicroBatch 模式下的时间窗口大小(微秒)
53    /// 默认 100μs,可根据网络状况调整
54    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, // 100μs 默认窗口
73        }
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, // 50μs 更激进的窗口
93        }
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, // 200μs 高吞吐模式
111        }
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    /// 从程序ID列表创建过滤器
147    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    /// 从程序ID列表创建所有者过滤器
190    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/// Build a memcmp account filter for use in `AccountFilter::filters`.
202/// ATA accounts have mint at offset 0; PumpSwap pool accounts often use offset 32 for mint/pubkey.
203#[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    /// All traffic from the shared LaunchLab program.
231    LaunchLab,
232    /// LaunchLab traffic attributed to StonkFun after parsing `platform_config`.
233    StonkFun,
234    /// Backward-compatible alias for [`Protocol::LaunchLab`].
235    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    // Block events
250    BlockMeta,
251
252    // RaydiumLaunchlab events
253    RaydiumLaunchlabTrade,
254    RaydiumLaunchlabPoolCreate,
255    RaydiumLaunchlabMigrateAmm,
256
257    // PumpFun events
258    PumpFunTrade,         // All trade events (backward compatible)
259    PumpFunBuy,           // Buy events only (filter by ix_name)
260    PumpFunSell,          // Sell events only (filter by ix_name)
261    PumpFunBuyExactSolIn, // BuyExactSolIn events only (filter by ix_name)
262    PumpFunCreate,
263    PumpFunCreateV2, // SPL-22 / Mayhem create
264    PumpFunComplete,
265    PumpFunMigrate,
266    /// Pump fees(`pfeeUx...`,`idl/pump_fees.json` Program data events)
267    PumpFeesCreateFeeSharingConfig,
268    PumpFeesInitializeFeeConfig,
269    PumpFeesResetFeeSharingConfig,
270    PumpFeesRevokeFeeSharingAuthority,
271    PumpFeesTransferFeeSharingAuthority,
272    PumpFeesUpdateAdmin,
273    PumpFeesUpdateFeeConfig,
274    PumpFeesUpdateFeeShares,
275    PumpFeesUpsertFeeTiers,
276    /// Pump.fun:`migrateBondingCurveCreatorEvent`
277    PumpFunMigrateBondingCurveCreator,
278
279    // PumpSwap events
280    PumpSwapTrade,
281    PumpSwapBuy,
282    PumpSwapSell,
283    PumpSwapCreatePool,
284    PumpSwapLiquidityAdded,
285    PumpSwapLiquidityRemoved,
286    // PumpSwapPoolUpdated,
287    // PumpSwapFeesClaimed,
288
289    // Raydium CPMM events
290    RaydiumCpmmSwap,
291    RaydiumCpmmDeposit,
292    RaydiumCpmmWithdraw,
293    RaydiumCpmmInitialize,
294
295    // Raydium CLMM events
296    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    // Raydium AMM V4 events
315    RaydiumAmmV4Swap,
316    RaydiumAmmV4Deposit,
317    RaydiumAmmV4Withdraw,
318    RaydiumAmmV4Initialize2,
319    RaydiumAmmV4WithdrawPnl,
320
321    // Orca Whirlpool events
322    OrcaWhirlpoolSwap,
323    OrcaWhirlpoolLiquidityIncreased,
324    OrcaWhirlpoolLiquidityDecreased,
325    OrcaWhirlpoolPoolInitialized,
326
327    // Meteora events
328    MeteoraPoolsSwap,
329    MeteoraPoolsAddLiquidity,
330    MeteoraPoolsRemoveLiquidity,
331    MeteoraPoolsBootstrapLiquidity,
332    MeteoraPoolsPoolCreated,
333    MeteoraPoolsSetPoolFees,
334
335    // Meteora DAMM V2 events
336    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    // MeteoraDammV2InitializeReward,
355    // MeteoraDammV2FundReward,
356    // MeteoraDammV2ClaimReward,
357    // MeteoraDlmmClaimReward,
358
359    // Meteora DBC events
360    MeteoraDbcSwap,
361    MeteoraDbcInitializePool,
362    MeteoraDbcCurveComplete,
363
364    // Meteora DLMM events
365    MeteoraDlmmSwap,
366    MeteoraDlmmAddLiquidity,
367    MeteoraDlmmRemoveLiquidity,
368    MeteoraDlmmInitializePool,
369    MeteoraDlmmInitializeBinArray,
370    MeteoraDlmmCreatePosition,
371    MeteoraDlmmClosePosition,
372    MeteoraDlmmClaimFee,
373
374    // Account events
375    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    /// Raw subscription bytes with slot/write_version; explicitly opt in via include_only.
399    AccountRawSnapshot,
400    AccountOrcaFeeTier,
401    AccountOrcaWhirlpoolsConfig,
402    PumpFunPostCompleteBuy,
403    PumpFunSweepBondingCurveFee,
404    PumpSwapSweepPoolFee,
405}
406
407#[derive(Debug, Clone)]
408pub struct EventTypeFilter {
409    pub include_only: Option<Vec<EventType>>,
410    pub exclude_types: Option<Vec<EventType>>,
411}
412
413impl EventTypeFilter {
414    pub fn include_only(types: Vec<EventType>) -> Self {
415        Self { include_only: Some(types), exclude_types: None }
416    }
417
418    pub fn exclude_types(types: Vec<EventType>) -> Self {
419        Self { include_only: None, exclude_types: Some(types) }
420    }
421
422    #[inline]
423    fn includes_any(&self, event_types: &[EventType]) -> bool {
424        event_types.iter().any(|event_type| self.should_include(*event_type))
425    }
426
427    pub fn should_include(&self, event_type: EventType) -> bool {
428        if let Some(ref include_only) = self.include_only {
429            // Direct match
430            if include_only.contains(&event_type) {
431                return true;
432            }
433            if matches!(
434                event_type,
435                EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
436            ) {
437                if pumpfun_trade_filter_is_generic(include_only) {
438                    return true;
439                }
440                if event_type == EventType::PumpFunBuyExactSolIn
441                    && pumpfun_buy_filter_is_generic(include_only)
442                {
443                    return true;
444                }
445                return false;
446            }
447            if is_pumpfun_create_family(event_type) {
448                return include_only.iter().any(|t| is_pumpfun_create_family(*t));
449            }
450            if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell) {
451                return include_only.contains(&EventType::PumpSwapTrade);
452            }
453            return false;
454        }
455
456        if let Some(ref exclude_types) = self.exclude_types {
457            if exclude_types.contains(&event_type) {
458                return false;
459            }
460            if matches!(
461                event_type,
462                EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
463            ) && exclude_types.contains(&EventType::PumpFunTrade)
464            {
465                return false;
466            }
467            if event_type == EventType::PumpFunBuyExactSolIn
468                && exclude_types.contains(&EventType::PumpFunBuy)
469            {
470                return false;
471            }
472            if is_pumpfun_create_family(event_type)
473                && exclude_types.iter().any(|t| is_pumpfun_create_family(*t))
474            {
475                return false;
476            }
477            if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell)
478                && exclude_types.contains(&EventType::PumpSwapTrade)
479            {
480                return false;
481            }
482            return true;
483        }
484
485        true
486    }
487
488    pub fn should_include_dex_event(&self, event: &crate::core::events::DexEvent) -> bool {
489        let Some(event_type) = event_type_from_dex_event(event) else { return true };
490        self.should_include(event_type)
491    }
492
493    #[inline]
494    pub fn includes_block_meta(&self) -> bool {
495        if let Some(ref include_only) = self.include_only {
496            return include_only.contains(&EventType::BlockMeta);
497        }
498        false
499    }
500
501    #[inline]
502    pub fn normalize_dex_event(
503        &self,
504        event: crate::core::events::DexEvent,
505    ) -> crate::core::events::DexEvent {
506        use crate::core::events::DexEvent;
507
508        let Some(ref include_only) = self.include_only else { return event };
509        if pumpfun_trade_filter_is_generic(include_only) {
510            return match event {
511                DexEvent::PumpFunBuy(t)
512                | DexEvent::PumpFunSell(t)
513                | DexEvent::PumpFunBuyExactSolIn(t) => DexEvent::PumpFunTrade(t),
514                other => other,
515            };
516        }
517        if pumpfun_buy_filter_is_generic(include_only) {
518            return match event {
519                DexEvent::PumpFunBuyExactSolIn(t) => DexEvent::PumpFunBuy(t),
520                other => other,
521            };
522        }
523
524        event
525    }
526
527    #[inline]
528    pub fn includes_pumpfun(&self) -> bool {
529        self.includes_any(&[
530            EventType::PumpFunTrade,
531            EventType::PumpFunBuy,
532            EventType::PumpFunSell,
533            EventType::PumpFunBuyExactSolIn,
534            EventType::PumpFunCreate,
535            EventType::PumpFunCreateV2,
536            EventType::PumpFunComplete,
537            EventType::PumpFunMigrate,
538            EventType::PumpFunMigrateBondingCurveCreator,
539            EventType::PumpFunPostCompleteBuy,
540            EventType::PumpFunSweepBondingCurveFee,
541        ])
542    }
543
544    #[inline]
545    pub fn includes_meteora_damm_v2(&self) -> bool {
546        self.includes_any(&[
547            EventType::MeteoraDammV2Swap,
548            EventType::MeteoraDammV2AddLiquidity,
549            EventType::MeteoraDammV2CreatePosition,
550            EventType::MeteoraDammV2ClaimPositionFee,
551            EventType::MeteoraDammV2ClaimReward,
552            EventType::MeteoraDammV2ClosePosition,
553            EventType::MeteoraDammV2InitializePool,
554            EventType::MeteoraDammV2RemoveLiquidity,
555            EventType::MeteoraDammV2UpdateDelegatePermission,
556            EventType::MeteoraDammV2WithdrawDeadLiquidityReward,
557            EventType::MeteoraDammV2WithdrawIneligibleReward,
558            EventType::MeteoraDammV2UpdateRewardFunder,
559            EventType::MeteoraDammV2UpdateRewardDuration,
560            EventType::MeteoraDammV2InitializeReward,
561            EventType::MeteoraDammV2FundReward,
562            EventType::MeteoraDammV2CreateConfig,
563            EventType::MeteoraDammV2CreateDynamicConfig,
564        ])
565    }
566
567    #[inline]
568    pub fn includes_pump_fees(&self) -> bool {
569        self.includes_any(&[
570            EventType::PumpFeesCreateFeeSharingConfig,
571            EventType::PumpFeesInitializeFeeConfig,
572            EventType::PumpFeesResetFeeSharingConfig,
573            EventType::PumpFeesRevokeFeeSharingAuthority,
574            EventType::PumpFeesTransferFeeSharingAuthority,
575            EventType::PumpFeesUpdateAdmin,
576            EventType::PumpFeesUpdateFeeConfig,
577            EventType::PumpFeesUpdateFeeShares,
578            EventType::PumpFeesUpsertFeeTiers,
579        ])
580    }
581
582    /// Check if PumpSwap protocol events are included in the filter
583    #[inline]
584    pub fn includes_pumpswap(&self) -> bool {
585        self.includes_any(&[
586            EventType::PumpSwapTrade,
587            EventType::PumpSwapBuy,
588            EventType::PumpSwapSell,
589            EventType::PumpSwapCreatePool,
590            EventType::PumpSwapSweepPoolFee,
591            EventType::PumpSwapLiquidityAdded,
592            EventType::PumpSwapLiquidityRemoved,
593        ])
594    }
595
596    /// Check if LaunchLab events are included in the filter.
597    #[inline]
598    pub fn includes_raydium_launchlab(&self) -> bool {
599        self.includes_any(&[
600            EventType::RaydiumLaunchlabTrade,
601            EventType::RaydiumLaunchlabPoolCreate,
602            EventType::RaydiumLaunchlabMigrateAmm,
603        ])
604    }
605
606    #[inline]
607    pub fn includes_raydium_cpmm(&self) -> bool {
608        self.includes_any(&[
609            EventType::RaydiumCpmmSwap,
610            EventType::RaydiumCpmmDeposit,
611            EventType::RaydiumCpmmWithdraw,
612            EventType::RaydiumCpmmInitialize,
613            EventType::RaydiumCpmmCollectCreatorFee,
614        ])
615    }
616
617    #[inline]
618    pub fn includes_raydium_clmm(&self) -> bool {
619        self.includes_any(&[
620            EventType::RaydiumClmmSwap,
621            EventType::RaydiumClmmCreatePool,
622            EventType::RaydiumClmmOpenPosition,
623            EventType::RaydiumClmmClosePosition,
624            EventType::RaydiumClmmIncreaseLiquidity,
625            EventType::RaydiumClmmDecreaseLiquidity,
626            EventType::RaydiumClmmLiquidityChange,
627            EventType::RaydiumClmmConfigChange,
628            EventType::RaydiumClmmCreatePersonalPosition,
629            EventType::RaydiumClmmLiquidityCalculate,
630            EventType::RaydiumClmmOpenLimitOrder,
631            EventType::RaydiumClmmIncreaseLimitOrder,
632            EventType::RaydiumClmmDecreaseLimitOrder,
633            EventType::RaydiumClmmSettleLimitOrder,
634            EventType::RaydiumClmmUpdateRewardInfos,
635            EventType::RaydiumClmmOpenPositionWithTokenExtNft,
636            EventType::RaydiumClmmCollectFee,
637        ])
638    }
639
640    #[inline]
641    pub fn includes_raydium_amm_v4(&self) -> bool {
642        self.includes_any(&[
643            EventType::RaydiumAmmV4Swap,
644            EventType::RaydiumAmmV4Deposit,
645            EventType::RaydiumAmmV4Withdraw,
646            EventType::RaydiumAmmV4Initialize2,
647            EventType::RaydiumAmmV4WithdrawPnl,
648        ])
649    }
650
651    #[inline]
652    pub fn includes_orca_whirlpool(&self) -> bool {
653        self.includes_any(&[
654            EventType::OrcaWhirlpoolSwap,
655            EventType::OrcaWhirlpoolLiquidityIncreased,
656            EventType::OrcaWhirlpoolLiquidityDecreased,
657            EventType::OrcaWhirlpoolPoolInitialized,
658        ])
659    }
660
661    #[inline]
662    pub fn includes_meteora_pools(&self) -> bool {
663        self.includes_any(&[
664            EventType::MeteoraPoolsSwap,
665            EventType::MeteoraPoolsAddLiquidity,
666            EventType::MeteoraPoolsRemoveLiquidity,
667            EventType::MeteoraPoolsBootstrapLiquidity,
668            EventType::MeteoraPoolsPoolCreated,
669            EventType::MeteoraPoolsSetPoolFees,
670        ])
671    }
672
673    #[inline]
674    pub fn includes_meteora_dlmm(&self) -> bool {
675        self.includes_any(&[
676            EventType::MeteoraDlmmSwap,
677            EventType::MeteoraDlmmAddLiquidity,
678            EventType::MeteoraDlmmRemoveLiquidity,
679            EventType::MeteoraDlmmInitializePool,
680            EventType::MeteoraDlmmInitializeBinArray,
681            EventType::MeteoraDlmmCreatePosition,
682            EventType::MeteoraDlmmClosePosition,
683            EventType::MeteoraDlmmClaimFee,
684            EventType::MeteoraDlmmClaimReward,
685        ])
686    }
687
688    #[inline]
689    pub fn includes_meteora_dbc(&self) -> bool {
690        self.includes_any(&[
691            EventType::MeteoraDbcSwap,
692            EventType::MeteoraDbcInitializePool,
693            EventType::MeteoraDbcCurveComplete,
694        ])
695    }
696}
697
698#[inline]
699fn pumpfun_trade_filter_is_generic(include_only: &[EventType]) -> bool {
700    include_only.contains(&EventType::PumpFunTrade)
701        && !include_only.iter().any(|t| {
702            matches!(
703                t,
704                EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
705            )
706        })
707}
708
709#[inline]
710fn pumpfun_buy_filter_is_generic(include_only: &[EventType]) -> bool {
711    include_only.contains(&EventType::PumpFunBuy)
712        && !include_only.contains(&EventType::PumpFunBuyExactSolIn)
713}
714
715#[inline]
716fn is_pumpfun_create_family(event_type: EventType) -> bool {
717    matches!(event_type, EventType::PumpFunCreate | EventType::PumpFunCreateV2)
718}
719
720#[inline]
721pub fn event_type_from_dex_event(event: &crate::core::events::DexEvent) -> Option<EventType> {
722    use crate::core::events::DexEvent;
723    match event {
724        DexEvent::PumpFunCreate(_) => Some(EventType::PumpFunCreate),
725        DexEvent::PumpFunCreateV2(_) => Some(EventType::PumpFunCreateV2),
726        DexEvent::PumpFunTrade(_) => Some(EventType::PumpFunTrade),
727        DexEvent::PumpFunBuy(_) => Some(EventType::PumpFunBuy),
728        DexEvent::PumpFunSell(_) => Some(EventType::PumpFunSell),
729        DexEvent::PumpFunBuyExactSolIn(_) => Some(EventType::PumpFunBuyExactSolIn),
730        DexEvent::PumpFunMigrate(_) => Some(EventType::PumpFunMigrate),
731        DexEvent::PumpFeesCreateFeeSharingConfig(_) => {
732            Some(EventType::PumpFeesCreateFeeSharingConfig)
733        }
734        DexEvent::PumpFeesInitializeFeeConfig(_) => Some(EventType::PumpFeesInitializeFeeConfig),
735        DexEvent::PumpFeesResetFeeSharingConfig(_) => {
736            Some(EventType::PumpFeesResetFeeSharingConfig)
737        }
738        DexEvent::PumpFeesRevokeFeeSharingAuthority(_) => {
739            Some(EventType::PumpFeesRevokeFeeSharingAuthority)
740        }
741        DexEvent::PumpFeesTransferFeeSharingAuthority(_) => {
742            Some(EventType::PumpFeesTransferFeeSharingAuthority)
743        }
744        DexEvent::PumpFeesUpdateAdmin(_) => Some(EventType::PumpFeesUpdateAdmin),
745        DexEvent::PumpFeesUpdateFeeConfig(_) => Some(EventType::PumpFeesUpdateFeeConfig),
746        DexEvent::PumpFeesUpdateFeeShares(_) => Some(EventType::PumpFeesUpdateFeeShares),
747        DexEvent::PumpFeesUpsertFeeTiers(_) => Some(EventType::PumpFeesUpsertFeeTiers),
748        DexEvent::PumpFunPostCompleteBuy(_) => Some(EventType::PumpFunPostCompleteBuy),
749        DexEvent::PumpFunSweepBondingCurveFee(_) => Some(EventType::PumpFunSweepBondingCurveFee),
750        DexEvent::PumpFunComplete(_) => Some(EventType::PumpFunComplete),
751        DexEvent::PumpSwapSweepPoolFee(_) => Some(EventType::PumpSwapSweepPoolFee),
752        DexEvent::PumpFunMigrateBondingCurveCreator(_) => {
753            Some(EventType::PumpFunMigrateBondingCurveCreator)
754        }
755        DexEvent::PumpFunGlobalAccount(_) => Some(EventType::AccountPumpFunGlobal),
756        DexEvent::PumpFunBondingCurveAccount(_) => Some(EventType::AccountPumpFunBondingCurve),
757        DexEvent::PumpFunFeeConfigAccount(_) => Some(EventType::AccountPumpFunFeeConfig),
758        DexEvent::PumpFunSharingConfigAccount(_) => Some(EventType::AccountPumpFunSharingConfig),
759        DexEvent::PumpFunGlobalVolumeAccumulatorAccount(_) => {
760            Some(EventType::AccountPumpFunGlobalVolumeAccumulator)
761        }
762        DexEvent::PumpFunUserVolumeAccumulatorAccount(_) => {
763            Some(EventType::AccountPumpFunUserVolumeAccumulator)
764        }
765        DexEvent::PumpSwapTrade(_) => Some(EventType::PumpSwapTrade),
766        DexEvent::PumpSwapBuy(_) => Some(EventType::PumpSwapBuy),
767        DexEvent::PumpSwapSell(_) => Some(EventType::PumpSwapSell),
768        DexEvent::PumpSwapCreatePool(_) => Some(EventType::PumpSwapCreatePool),
769        DexEvent::PumpSwapLiquidityAdded(_) => Some(EventType::PumpSwapLiquidityAdded),
770        DexEvent::PumpSwapLiquidityRemoved(_) => Some(EventType::PumpSwapLiquidityRemoved),
771        DexEvent::MeteoraDammV2Swap(_) => Some(EventType::MeteoraDammV2Swap),
772        DexEvent::MeteoraDammV2ClaimPositionFee(_) => {
773            Some(EventType::MeteoraDammV2ClaimPositionFee)
774        }
775        DexEvent::MeteoraDammV2ClaimReward(_) => Some(EventType::MeteoraDammV2ClaimReward),
776        DexEvent::MeteoraDlmmClaimReward(_) => Some(EventType::MeteoraDlmmClaimReward),
777        DexEvent::MeteoraDammV2CreatePosition(_) => Some(EventType::MeteoraDammV2CreatePosition),
778        DexEvent::MeteoraDammV2ClosePosition(_) => Some(EventType::MeteoraDammV2ClosePosition),
779        DexEvent::MeteoraDammV2AddLiquidity(_) => Some(EventType::MeteoraDammV2AddLiquidity),
780        DexEvent::MeteoraDammV2RemoveLiquidity(_) => Some(EventType::MeteoraDammV2RemoveLiquidity),
781        DexEvent::MeteoraDammV2InitializePool(_) => Some(EventType::MeteoraDammV2InitializePool),
782        DexEvent::MeteoraDammV2UpdateDelegatePermission(_) => {
783            Some(EventType::MeteoraDammV2UpdateDelegatePermission)
784        }
785        DexEvent::MeteoraDammV2WithdrawDeadLiquidityReward(_) => {
786            Some(EventType::MeteoraDammV2WithdrawDeadLiquidityReward)
787        }
788        DexEvent::MeteoraDammV2WithdrawIneligibleReward(_) => {
789            Some(EventType::MeteoraDammV2WithdrawIneligibleReward)
790        }
791        DexEvent::MeteoraDammV2UpdateRewardFunder(_) => {
792            Some(EventType::MeteoraDammV2UpdateRewardFunder)
793        }
794        DexEvent::MeteoraDammV2UpdateRewardDuration(_) => {
795            Some(EventType::MeteoraDammV2UpdateRewardDuration)
796        }
797        DexEvent::MeteoraDammV2InitializeReward(_) => {
798            Some(EventType::MeteoraDammV2InitializeReward)
799        }
800        DexEvent::MeteoraDammV2FundReward(_) => Some(EventType::MeteoraDammV2FundReward),
801        DexEvent::MeteoraDammV2CreateConfig(_) => Some(EventType::MeteoraDammV2CreateConfig),
802        DexEvent::MeteoraDammV2CreateDynamicConfig(_) => {
803            Some(EventType::MeteoraDammV2CreateDynamicConfig)
804        }
805        DexEvent::MeteoraDbcSwap(_) => Some(EventType::MeteoraDbcSwap),
806        DexEvent::MeteoraDbcInitializePool(_) => Some(EventType::MeteoraDbcInitializePool),
807        DexEvent::MeteoraDbcCurveComplete(_) => Some(EventType::MeteoraDbcCurveComplete),
808        DexEvent::RaydiumLaunchlabTrade(_) => Some(EventType::RaydiumLaunchlabTrade),
809        DexEvent::RaydiumLaunchlabPoolCreate(_) => Some(EventType::RaydiumLaunchlabPoolCreate),
810        DexEvent::RaydiumLaunchlabMigrateAmm(_) => Some(EventType::RaydiumLaunchlabMigrateAmm),
811        DexEvent::RaydiumClmmSwap(_) => Some(EventType::RaydiumClmmSwap),
812        DexEvent::RaydiumClmmCreatePool(_) => Some(EventType::RaydiumClmmCreatePool),
813        DexEvent::RaydiumClmmOpenPosition(_) => Some(EventType::RaydiumClmmOpenPosition),
814        DexEvent::RaydiumClmmOpenPositionWithTokenExtNft(_) => {
815            Some(EventType::RaydiumClmmOpenPositionWithTokenExtNft)
816        }
817        DexEvent::RaydiumClmmClosePosition(_) => Some(EventType::RaydiumClmmClosePosition),
818        DexEvent::RaydiumClmmIncreaseLiquidity(_) => Some(EventType::RaydiumClmmIncreaseLiquidity),
819        DexEvent::RaydiumClmmDecreaseLiquidity(_) => Some(EventType::RaydiumClmmDecreaseLiquidity),
820        DexEvent::RaydiumClmmLiquidityChange(_) => Some(EventType::RaydiumClmmLiquidityChange),
821        DexEvent::RaydiumClmmConfigChange(_) => Some(EventType::RaydiumClmmConfigChange),
822        DexEvent::RaydiumClmmCreatePersonalPosition(_) => {
823            Some(EventType::RaydiumClmmCreatePersonalPosition)
824        }
825        DexEvent::RaydiumClmmLiquidityCalculate(_) => {
826            Some(EventType::RaydiumClmmLiquidityCalculate)
827        }
828        DexEvent::RaydiumClmmOpenLimitOrder(_) => Some(EventType::RaydiumClmmOpenLimitOrder),
829        DexEvent::RaydiumClmmIncreaseLimitOrder(_) => {
830            Some(EventType::RaydiumClmmIncreaseLimitOrder)
831        }
832        DexEvent::RaydiumClmmDecreaseLimitOrder(_) => {
833            Some(EventType::RaydiumClmmDecreaseLimitOrder)
834        }
835        DexEvent::RaydiumClmmSettleLimitOrder(_) => Some(EventType::RaydiumClmmSettleLimitOrder),
836        DexEvent::RaydiumClmmUpdateRewardInfos(_) => Some(EventType::RaydiumClmmUpdateRewardInfos),
837        DexEvent::RaydiumClmmCollectFee(_) => Some(EventType::RaydiumClmmCollectFee),
838        DexEvent::RaydiumClmmAmmConfigAccount(_) => Some(EventType::AccountRaydiumClmmAmmConfig),
839        DexEvent::RaydiumClmmPoolStateAccount(_) => Some(EventType::AccountRaydiumClmmPoolState),
840        DexEvent::RaydiumClmmTickArrayStateAccount(_) => {
841            Some(EventType::AccountRaydiumClmmTickArrayState)
842        }
843        DexEvent::RaydiumCpmmSwap(_) => Some(EventType::RaydiumCpmmSwap),
844        DexEvent::RaydiumCpmmDeposit(_) => Some(EventType::RaydiumCpmmDeposit),
845        DexEvent::RaydiumCpmmWithdraw(_) => Some(EventType::RaydiumCpmmWithdraw),
846        DexEvent::RaydiumCpmmInitialize(_) => Some(EventType::RaydiumCpmmInitialize),
847        DexEvent::RaydiumCpmmAmmConfigAccount(_) => Some(EventType::AccountRaydiumCpmmAmmConfig),
848        DexEvent::RaydiumCpmmPoolStateAccount(_) => Some(EventType::AccountRaydiumCpmmPoolState),
849        DexEvent::RaydiumCpmmCollectCreatorFee(_) => Some(EventType::RaydiumCpmmCollectCreatorFee),
850        DexEvent::RaydiumCpmmCreatorFeeShareAccount(_) => {
851            Some(EventType::AccountRaydiumCpmmCreatorFeeShare)
852        }
853        DexEvent::RaydiumAmmV4Swap(_) => Some(EventType::RaydiumAmmV4Swap),
854        DexEvent::RaydiumAmmV4Deposit(_) => Some(EventType::RaydiumAmmV4Deposit),
855        DexEvent::RaydiumAmmV4Initialize2(_) => Some(EventType::RaydiumAmmV4Initialize2),
856        DexEvent::RaydiumAmmV4Withdraw(_) => Some(EventType::RaydiumAmmV4Withdraw),
857        DexEvent::RaydiumAmmV4WithdrawPnl(_) => Some(EventType::RaydiumAmmV4WithdrawPnl),
858        DexEvent::OrcaWhirlpoolSwap(_) => Some(EventType::OrcaWhirlpoolSwap),
859        DexEvent::OrcaWhirlpoolLiquidityIncreased(_) => {
860            Some(EventType::OrcaWhirlpoolLiquidityIncreased)
861        }
862        DexEvent::OrcaWhirlpoolLiquidityDecreased(_) => {
863            Some(EventType::OrcaWhirlpoolLiquidityDecreased)
864        }
865        DexEvent::OrcaWhirlpoolPoolInitialized(_) => Some(EventType::OrcaWhirlpoolPoolInitialized),
866        DexEvent::OrcaWhirlpoolAccount(_) => Some(EventType::AccountOrcaWhirlpool),
867        DexEvent::OrcaPositionAccount(_) => Some(EventType::AccountOrcaPosition),
868        DexEvent::OrcaTickArrayAccount(_) => Some(EventType::AccountOrcaTickArray),
869        DexEvent::LiquidityAccountSnapshot(_) => Some(EventType::AccountLiquiditySnapshot),
870        DexEvent::RawAccountSnapshot(_) => Some(EventType::AccountRawSnapshot),
871        DexEvent::OrcaFeeTierAccount(_) => Some(EventType::AccountOrcaFeeTier),
872        DexEvent::OrcaWhirlpoolsConfigAccount(_) => Some(EventType::AccountOrcaWhirlpoolsConfig),
873        DexEvent::MeteoraPoolsSwap(_) => Some(EventType::MeteoraPoolsSwap),
874        DexEvent::MeteoraPoolsAddLiquidity(_) => Some(EventType::MeteoraPoolsAddLiquidity),
875        DexEvent::MeteoraPoolsRemoveLiquidity(_) => Some(EventType::MeteoraPoolsRemoveLiquidity),
876        DexEvent::MeteoraPoolsBootstrapLiquidity(_) => {
877            Some(EventType::MeteoraPoolsBootstrapLiquidity)
878        }
879        DexEvent::MeteoraPoolsPoolCreated(_) => Some(EventType::MeteoraPoolsPoolCreated),
880        DexEvent::MeteoraPoolsSetPoolFees(_) => Some(EventType::MeteoraPoolsSetPoolFees),
881        DexEvent::MeteoraDlmmSwap(_) => Some(EventType::MeteoraDlmmSwap),
882        DexEvent::MeteoraDlmmAddLiquidity(_) => Some(EventType::MeteoraDlmmAddLiquidity),
883        DexEvent::MeteoraDlmmRemoveLiquidity(_) => Some(EventType::MeteoraDlmmRemoveLiquidity),
884        DexEvent::MeteoraDlmmInitializePool(_) => Some(EventType::MeteoraDlmmInitializePool),
885        DexEvent::MeteoraDlmmInitializeBinArray(_) => {
886            Some(EventType::MeteoraDlmmInitializeBinArray)
887        }
888        DexEvent::MeteoraDlmmCreatePosition(_) => Some(EventType::MeteoraDlmmCreatePosition),
889        DexEvent::MeteoraDlmmClosePosition(_) => Some(EventType::MeteoraDlmmClosePosition),
890        DexEvent::MeteoraDlmmClaimFee(_) => Some(EventType::MeteoraDlmmClaimFee),
891        DexEvent::TokenAccount(_) => Some(EventType::TokenAccount),
892        DexEvent::TokenInfo(_) => Some(EventType::TokenInfo),
893        DexEvent::NonceAccount(_) => Some(EventType::NonceAccount),
894        DexEvent::PumpSwapGlobalConfigAccount(_) => Some(EventType::AccountPumpSwapGlobalConfig),
895        DexEvent::PumpSwapPoolAccount(_) => Some(EventType::AccountPumpSwapPool),
896        DexEvent::BlockMeta(_) => Some(EventType::BlockMeta),
897        DexEvent::Error(_) => None,
898    }
899}
900
901#[cfg(test)]
902mod event_type_filter_tests {
903    use super::*;
904
905    #[test]
906    fn generic_trade_filters_cover_specific_trade_variants() {
907        let pump = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
908        assert!(pump.should_include(EventType::PumpFunTrade));
909        assert!(pump.should_include(EventType::PumpFunBuy));
910        assert!(pump.should_include(EventType::PumpFunSell));
911        assert!(pump.should_include(EventType::PumpFunBuyExactSolIn));
912
913        let pump_specific = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
914        assert!(!pump_specific.should_include(EventType::PumpFunTrade));
915        assert!(pump_specific.should_include(EventType::PumpFunBuy));
916        assert!(!pump_specific.should_include(EventType::PumpFunSell));
917        assert!(pump_specific.should_include(EventType::PumpFunBuyExactSolIn));
918
919        let pump_exact_buy = EventTypeFilter::include_only(vec![EventType::PumpFunBuyExactSolIn]);
920        assert!(!pump_exact_buy.should_include(EventType::PumpFunTrade));
921        assert!(!pump_exact_buy.should_include(EventType::PumpFunBuy));
922        assert!(!pump_exact_buy.should_include(EventType::PumpFunSell));
923        assert!(pump_exact_buy.should_include(EventType::PumpFunBuyExactSolIn));
924
925        let pumpswap = EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]);
926        assert!(pumpswap.should_include(EventType::PumpSwapBuy));
927        assert!(pumpswap.should_include(EventType::PumpSwapSell));
928
929        let exclude_pumpswap = EventTypeFilter::exclude_types(vec![EventType::PumpSwapTrade]);
930        assert!(!exclude_pumpswap.should_include(EventType::PumpSwapBuy));
931        assert!(!exclude_pumpswap.should_include(EventType::PumpSwapSell));
932    }
933
934    #[test]
935    fn generic_pumpfun_trade_filter_normalizes_specific_variants() {
936        use crate::core::events::{DexEvent, PumpFunTradeEvent};
937
938        let filter = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
939        let event = DexEvent::PumpFunBuy(PumpFunTradeEvent { is_buy: true, ..Default::default() });
940        assert!(matches!(filter.normalize_dex_event(event), DexEvent::PumpFunTrade(_)));
941
942        let specific_filter =
943            EventTypeFilter::include_only(vec![EventType::PumpFunTrade, EventType::PumpFunBuy]);
944        let event = DexEvent::PumpFunBuy(PumpFunTradeEvent { is_buy: true, ..Default::default() });
945        assert!(matches!(specific_filter.normalize_dex_event(event), DexEvent::PumpFunBuy(_)));
946
947        let buy_filter = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
948        let event = DexEvent::PumpFunBuyExactSolIn(PumpFunTradeEvent {
949            is_buy: true,
950            ..Default::default()
951        });
952        assert!(matches!(buy_filter.normalize_dex_event(event), DexEvent::PumpFunBuy(_)));
953
954        let exact_filter = EventTypeFilter::include_only(vec![EventType::PumpFunBuyExactSolIn]);
955        let event = DexEvent::PumpFunBuyExactSolIn(PumpFunTradeEvent {
956            is_buy: true,
957            ..Default::default()
958        });
959        assert!(matches!(
960            exact_filter.normalize_dex_event(event),
961            DexEvent::PumpFunBuyExactSolIn(_)
962        ));
963
964        let create_and_trade_filter =
965            EventTypeFilter::include_only(vec![EventType::PumpFunCreate, EventType::PumpFunTrade]);
966        let event =
967            DexEvent::PumpFunSell(PumpFunTradeEvent { is_buy: false, ..Default::default() });
968        assert!(matches!(
969            create_and_trade_filter.normalize_dex_event(event),
970            DexEvent::PumpFunTrade(_)
971        ));
972    }
973
974    #[test]
975    fn all_protocol_groups_are_filterable() {
976        assert!(EventTypeFilter::include_only(vec![EventType::PumpFunTrade]).includes_pumpfun());
977        assert!(!EventTypeFilter::include_only(vec![EventType::AccountPumpFunGlobal])
978            .includes_pumpfun());
979        assert!(
980            !EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateAdmin]).includes_pumpfun()
981        );
982        assert!(EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]).includes_pumpswap());
983        assert!(EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateFeeShares])
984            .includes_pump_fees());
985        assert!(EventTypeFilter::include_only(vec![EventType::RaydiumLaunchlabTrade])
986            .includes_raydium_launchlab());
987        assert!(
988            EventTypeFilter::include_only(vec![EventType::RaydiumCpmmSwap]).includes_raydium_cpmm()
989        );
990        assert!(
991            EventTypeFilter::include_only(vec![EventType::RaydiumClmmSwap]).includes_raydium_clmm()
992        );
993        assert!(!EventTypeFilter::include_only(vec![EventType::AccountRaydiumClmmPoolState])
994            .includes_raydium_clmm());
995        assert!(EventTypeFilter::include_only(vec![EventType::RaydiumAmmV4Swap])
996            .includes_raydium_amm_v4());
997        assert!(EventTypeFilter::include_only(vec![EventType::OrcaWhirlpoolSwap])
998            .includes_orca_whirlpool());
999        assert!(EventTypeFilter::include_only(vec![EventType::MeteoraPoolsSwap])
1000            .includes_meteora_pools());
1001        assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2Swap])
1002            .includes_meteora_damm_v2());
1003        assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2InitializePool])
1004            .includes_meteora_damm_v2());
1005        assert!(
1006            EventTypeFilter::include_only(vec![EventType::MeteoraDlmmSwap]).includes_meteora_dlmm()
1007        );
1008        assert!(
1009            EventTypeFilter::include_only(vec![EventType::MeteoraDbcSwap]).includes_meteora_dbc()
1010        );
1011    }
1012
1013    #[test]
1014    fn exclude_filters_do_not_skip_whole_protocol_groups() {
1015        let raydium = EventTypeFilter::exclude_types(vec![EventType::RaydiumCpmmSwap]);
1016        assert!(raydium.includes_raydium_cpmm());
1017        assert!(!raydium.should_include(EventType::RaydiumCpmmSwap));
1018        assert!(raydium.should_include(EventType::RaydiumCpmmDeposit));
1019
1020        let all_cpmm = EventTypeFilter::exclude_types(vec![
1021            EventType::RaydiumCpmmSwap,
1022            EventType::RaydiumCpmmDeposit,
1023            EventType::RaydiumCpmmWithdraw,
1024            EventType::RaydiumCpmmInitialize,
1025            EventType::RaydiumCpmmCollectCreatorFee,
1026        ]);
1027        assert!(!all_cpmm.includes_raydium_cpmm());
1028
1029        let all_launchlab = EventTypeFilter::exclude_types(vec![
1030            EventType::RaydiumLaunchlabTrade,
1031            EventType::RaydiumLaunchlabPoolCreate,
1032            EventType::RaydiumLaunchlabMigrateAmm,
1033        ]);
1034        assert!(!all_launchlab.includes_raydium_launchlab());
1035
1036        let pump = EventTypeFilter::exclude_types(vec![EventType::PumpFunBuy]);
1037        assert!(pump.includes_pumpfun());
1038        assert!(!pump.should_include(EventType::PumpFunBuy));
1039        assert!(!pump.should_include(EventType::PumpFunBuyExactSolIn));
1040        assert!(pump.should_include(EventType::PumpFunSell));
1041    }
1042}
1043
1044#[derive(Debug, Clone)]
1045pub struct SlotFilter {
1046    pub min_slot: Option<u64>,
1047    pub max_slot: Option<u64>,
1048}
1049
1050impl SlotFilter {
1051    pub fn new() -> Self {
1052        Self { min_slot: None, max_slot: None }
1053    }
1054
1055    pub fn min_slot(mut self, slot: u64) -> Self {
1056        self.min_slot = Some(slot);
1057        self
1058    }
1059
1060    pub fn max_slot(mut self, slot: u64) -> Self {
1061        self.max_slot = Some(slot);
1062        self
1063    }
1064}
1065
1066impl Default for SlotFilter {
1067    fn default() -> Self {
1068        Self::new()
1069    }
1070}