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 if include_only.contains(&EventType::PumpFunTrade) {
420 return true;
421 }
422 if is_pumpfun_buy_family(event_type) {
423 return include_only.iter().any(|t| is_pumpfun_buy_family(*t));
424 }
425 return false;
426 }
427 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell) {
428 return include_only.contains(&EventType::PumpSwapTrade);
429 }
430 return false;
431 }
432
433 if let Some(ref exclude_types) = self.exclude_types {
434 if exclude_types.contains(&event_type) {
435 return false;
436 }
437 if matches!(
438 event_type,
439 EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
440 ) && exclude_types.contains(&EventType::PumpFunTrade)
441 {
442 return false;
443 }
444 if is_pumpfun_buy_family(event_type)
445 && exclude_types.iter().any(|t| is_pumpfun_buy_family(*t))
446 {
447 return false;
448 }
449 if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell)
450 && exclude_types.contains(&EventType::PumpSwapTrade)
451 {
452 return false;
453 }
454 return true;
455 }
456
457 true
458 }
459
460 pub fn should_include_dex_event(&self, event: &crate::core::events::DexEvent) -> bool {
461 let Some(event_type) = event_type_from_dex_event(event) else { return true };
462 self.should_include(event_type)
463 }
464
465 #[inline]
466 pub fn includes_pumpfun(&self) -> bool {
467 self.includes_group(|t| {
468 matches!(
469 t,
470 EventType::PumpFunTrade
471 | EventType::PumpFunBuy
472 | EventType::PumpFunSell
473 | EventType::PumpFunBuyExactSolIn
474 | EventType::PumpFunCreate
475 | EventType::PumpFunCreateV2
476 | EventType::PumpFunComplete
477 | EventType::PumpFunMigrate
478 | EventType::PumpFunMigrateBondingCurveCreator
479 | EventType::AccountPumpFunGlobal
480 | EventType::AccountPumpFunBondingCurve
481 | EventType::AccountPumpFunFeeConfig
482 | EventType::AccountPumpFunSharingConfig
483 | EventType::AccountPumpFunGlobalVolumeAccumulator
484 | EventType::AccountPumpFunUserVolumeAccumulator
485 )
486 })
487 }
488
489 #[inline]
490 pub fn includes_meteora_damm_v2(&self) -> bool {
491 self.includes_group(|t| {
492 matches!(
493 t,
494 EventType::MeteoraDammV2Swap
495 | EventType::MeteoraDammV2AddLiquidity
496 | EventType::MeteoraDammV2CreatePosition
497 | EventType::MeteoraDammV2ClosePosition
498 | EventType::MeteoraDammV2RemoveLiquidity
499 )
500 })
501 }
502
503 #[inline]
504 pub fn includes_pump_fees(&self) -> bool {
505 self.includes_group(|t| {
506 matches!(
507 t,
508 EventType::PumpFeesCreateFeeSharingConfig
509 | EventType::PumpFeesInitializeFeeConfig
510 | EventType::PumpFeesResetFeeSharingConfig
511 | EventType::PumpFeesRevokeFeeSharingAuthority
512 | EventType::PumpFeesTransferFeeSharingAuthority
513 | EventType::PumpFeesUpdateAdmin
514 | EventType::PumpFeesUpdateFeeConfig
515 | EventType::PumpFeesUpdateFeeShares
516 | EventType::PumpFeesUpsertFeeTiers
517 )
518 })
519 }
520
521 #[inline]
523 pub fn includes_pumpswap(&self) -> bool {
524 self.includes_group(|t| {
525 matches!(
526 t,
527 EventType::PumpSwapTrade
528 | EventType::PumpSwapBuy
529 | EventType::PumpSwapSell
530 | EventType::PumpSwapCreatePool
531 | EventType::PumpSwapLiquidityAdded
532 | EventType::PumpSwapLiquidityRemoved
533 )
534 })
535 }
536
537 #[inline]
539 pub fn includes_raydium_launchpad(&self) -> bool {
540 self.includes_group(|t| {
541 matches!(
542 t,
543 EventType::BonkTrade | EventType::BonkPoolCreate | EventType::BonkMigrateAmm
544 )
545 })
546 }
547
548 #[inline]
549 pub fn includes_raydium_cpmm(&self) -> bool {
550 self.includes_group(|t| {
551 matches!(
552 t,
553 EventType::RaydiumCpmmSwap
554 | EventType::RaydiumCpmmDeposit
555 | EventType::RaydiumCpmmWithdraw
556 | EventType::RaydiumCpmmInitialize
557 )
558 })
559 }
560
561 #[inline]
562 pub fn includes_raydium_clmm(&self) -> bool {
563 self.includes_group(|t| {
564 matches!(
565 t,
566 EventType::RaydiumClmmSwap
567 | EventType::RaydiumClmmCreatePool
568 | EventType::RaydiumClmmOpenPosition
569 | EventType::RaydiumClmmClosePosition
570 | EventType::RaydiumClmmIncreaseLiquidity
571 | EventType::RaydiumClmmDecreaseLiquidity
572 | EventType::RaydiumClmmLiquidityChange
573 | EventType::RaydiumClmmConfigChange
574 | EventType::RaydiumClmmCreatePersonalPosition
575 | EventType::RaydiumClmmLiquidityCalculate
576 | EventType::RaydiumClmmOpenLimitOrder
577 | EventType::RaydiumClmmIncreaseLimitOrder
578 | EventType::RaydiumClmmDecreaseLimitOrder
579 | EventType::RaydiumClmmSettleLimitOrder
580 | EventType::RaydiumClmmUpdateRewardInfos
581 | EventType::RaydiumClmmOpenPositionWithTokenExtNft
582 | EventType::RaydiumClmmCollectFee
583 | EventType::AccountRaydiumClmmAmmConfig
584 | EventType::AccountRaydiumClmmPoolState
585 | EventType::AccountRaydiumClmmTickArrayState
586 )
587 })
588 }
589
590 #[inline]
591 pub fn includes_raydium_amm_v4(&self) -> bool {
592 self.includes_group(|t| {
593 matches!(
594 t,
595 EventType::RaydiumAmmV4Swap
596 | EventType::RaydiumAmmV4Deposit
597 | EventType::RaydiumAmmV4Withdraw
598 | EventType::RaydiumAmmV4Initialize2
599 | EventType::RaydiumAmmV4WithdrawPnl
600 )
601 })
602 }
603
604 #[inline]
605 pub fn includes_orca_whirlpool(&self) -> bool {
606 self.includes_group(|t| {
607 matches!(
608 t,
609 EventType::OrcaWhirlpoolSwap
610 | EventType::OrcaWhirlpoolLiquidityIncreased
611 | EventType::OrcaWhirlpoolLiquidityDecreased
612 | EventType::OrcaWhirlpoolPoolInitialized
613 )
614 })
615 }
616
617 #[inline]
618 pub fn includes_meteora_pools(&self) -> bool {
619 self.includes_group(|t| {
620 matches!(
621 t,
622 EventType::MeteoraPoolsSwap
623 | EventType::MeteoraPoolsAddLiquidity
624 | EventType::MeteoraPoolsRemoveLiquidity
625 | EventType::MeteoraPoolsBootstrapLiquidity
626 | EventType::MeteoraPoolsPoolCreated
627 | EventType::MeteoraPoolsSetPoolFees
628 )
629 })
630 }
631
632 #[inline]
633 pub fn includes_meteora_dlmm(&self) -> bool {
634 self.includes_group(|t| {
635 matches!(
636 t,
637 EventType::MeteoraDlmmSwap
638 | EventType::MeteoraDlmmAddLiquidity
639 | EventType::MeteoraDlmmRemoveLiquidity
640 | EventType::MeteoraDlmmInitializePool
641 | EventType::MeteoraDlmmInitializeBinArray
642 | EventType::MeteoraDlmmCreatePosition
643 | EventType::MeteoraDlmmClosePosition
644 | EventType::MeteoraDlmmClaimFee
645 )
646 })
647 }
648}
649
650#[inline]
651fn is_pumpfun_buy_family(event_type: EventType) -> bool {
652 matches!(event_type, EventType::PumpFunBuy | EventType::PumpFunBuyExactSolIn)
653}
654
655#[inline]
656pub fn event_type_from_dex_event(event: &crate::core::events::DexEvent) -> Option<EventType> {
657 use crate::core::events::DexEvent;
658 match event {
659 DexEvent::PumpFunCreate(_) => Some(EventType::PumpFunCreate),
660 DexEvent::PumpFunCreateV2(_) => Some(EventType::PumpFunCreateV2),
661 DexEvent::PumpFunTrade(_) => Some(EventType::PumpFunTrade),
662 DexEvent::PumpFunBuy(_) => Some(EventType::PumpFunBuy),
663 DexEvent::PumpFunSell(_) => Some(EventType::PumpFunSell),
664 DexEvent::PumpFunBuyExactSolIn(_) => Some(EventType::PumpFunBuyExactSolIn),
665 DexEvent::PumpFunMigrate(_) => Some(EventType::PumpFunMigrate),
666 DexEvent::PumpFeesCreateFeeSharingConfig(_) => {
667 Some(EventType::PumpFeesCreateFeeSharingConfig)
668 }
669 DexEvent::PumpFeesInitializeFeeConfig(_) => Some(EventType::PumpFeesInitializeFeeConfig),
670 DexEvent::PumpFeesResetFeeSharingConfig(_) => {
671 Some(EventType::PumpFeesResetFeeSharingConfig)
672 }
673 DexEvent::PumpFeesRevokeFeeSharingAuthority(_) => {
674 Some(EventType::PumpFeesRevokeFeeSharingAuthority)
675 }
676 DexEvent::PumpFeesTransferFeeSharingAuthority(_) => {
677 Some(EventType::PumpFeesTransferFeeSharingAuthority)
678 }
679 DexEvent::PumpFeesUpdateAdmin(_) => Some(EventType::PumpFeesUpdateAdmin),
680 DexEvent::PumpFeesUpdateFeeConfig(_) => Some(EventType::PumpFeesUpdateFeeConfig),
681 DexEvent::PumpFeesUpdateFeeShares(_) => Some(EventType::PumpFeesUpdateFeeShares),
682 DexEvent::PumpFeesUpsertFeeTiers(_) => Some(EventType::PumpFeesUpsertFeeTiers),
683 DexEvent::PumpFunMigrateBondingCurveCreator(_) => {
684 Some(EventType::PumpFunMigrateBondingCurveCreator)
685 }
686 DexEvent::PumpFunGlobalAccount(_) => Some(EventType::AccountPumpFunGlobal),
687 DexEvent::PumpFunBondingCurveAccount(_) => Some(EventType::AccountPumpFunBondingCurve),
688 DexEvent::PumpFunFeeConfigAccount(_) => Some(EventType::AccountPumpFunFeeConfig),
689 DexEvent::PumpFunSharingConfigAccount(_) => Some(EventType::AccountPumpFunSharingConfig),
690 DexEvent::PumpFunGlobalVolumeAccumulatorAccount(_) => {
691 Some(EventType::AccountPumpFunGlobalVolumeAccumulator)
692 }
693 DexEvent::PumpFunUserVolumeAccumulatorAccount(_) => {
694 Some(EventType::AccountPumpFunUserVolumeAccumulator)
695 }
696 DexEvent::PumpSwapTrade(_) => Some(EventType::PumpSwapTrade),
697 DexEvent::PumpSwapBuy(_) => Some(EventType::PumpSwapBuy),
698 DexEvent::PumpSwapSell(_) => Some(EventType::PumpSwapSell),
699 DexEvent::PumpSwapCreatePool(_) => Some(EventType::PumpSwapCreatePool),
700 DexEvent::PumpSwapLiquidityAdded(_) => Some(EventType::PumpSwapLiquidityAdded),
701 DexEvent::PumpSwapLiquidityRemoved(_) => Some(EventType::PumpSwapLiquidityRemoved),
702 DexEvent::MeteoraDammV2Swap(_) => Some(EventType::MeteoraDammV2Swap),
703 DexEvent::MeteoraDammV2CreatePosition(_) => Some(EventType::MeteoraDammV2CreatePosition),
704 DexEvent::MeteoraDammV2ClosePosition(_) => Some(EventType::MeteoraDammV2ClosePosition),
705 DexEvent::MeteoraDammV2AddLiquidity(_) => Some(EventType::MeteoraDammV2AddLiquidity),
706 DexEvent::MeteoraDammV2RemoveLiquidity(_) => Some(EventType::MeteoraDammV2RemoveLiquidity),
707 DexEvent::BonkTrade(_) => Some(EventType::BonkTrade),
708 DexEvent::BonkPoolCreate(_) => Some(EventType::BonkPoolCreate),
709 DexEvent::BonkMigrateAmm(_) => Some(EventType::BonkMigrateAmm),
710 DexEvent::RaydiumClmmSwap(_) => Some(EventType::RaydiumClmmSwap),
711 DexEvent::RaydiumClmmCreatePool(_) => Some(EventType::RaydiumClmmCreatePool),
712 DexEvent::RaydiumClmmOpenPosition(_) => Some(EventType::RaydiumClmmOpenPosition),
713 DexEvent::RaydiumClmmOpenPositionWithTokenExtNft(_) => {
714 Some(EventType::RaydiumClmmOpenPositionWithTokenExtNft)
715 }
716 DexEvent::RaydiumClmmClosePosition(_) => Some(EventType::RaydiumClmmClosePosition),
717 DexEvent::RaydiumClmmIncreaseLiquidity(_) => Some(EventType::RaydiumClmmIncreaseLiquidity),
718 DexEvent::RaydiumClmmDecreaseLiquidity(_) => Some(EventType::RaydiumClmmDecreaseLiquidity),
719 DexEvent::RaydiumClmmLiquidityChange(_) => Some(EventType::RaydiumClmmLiquidityChange),
720 DexEvent::RaydiumClmmConfigChange(_) => Some(EventType::RaydiumClmmConfigChange),
721 DexEvent::RaydiumClmmCreatePersonalPosition(_) => {
722 Some(EventType::RaydiumClmmCreatePersonalPosition)
723 }
724 DexEvent::RaydiumClmmLiquidityCalculate(_) => {
725 Some(EventType::RaydiumClmmLiquidityCalculate)
726 }
727 DexEvent::RaydiumClmmOpenLimitOrder(_) => Some(EventType::RaydiumClmmOpenLimitOrder),
728 DexEvent::RaydiumClmmIncreaseLimitOrder(_) => {
729 Some(EventType::RaydiumClmmIncreaseLimitOrder)
730 }
731 DexEvent::RaydiumClmmDecreaseLimitOrder(_) => {
732 Some(EventType::RaydiumClmmDecreaseLimitOrder)
733 }
734 DexEvent::RaydiumClmmSettleLimitOrder(_) => Some(EventType::RaydiumClmmSettleLimitOrder),
735 DexEvent::RaydiumClmmUpdateRewardInfos(_) => Some(EventType::RaydiumClmmUpdateRewardInfos),
736 DexEvent::RaydiumClmmCollectFee(_) => Some(EventType::RaydiumClmmCollectFee),
737 DexEvent::RaydiumClmmAmmConfigAccount(_) => Some(EventType::AccountRaydiumClmmAmmConfig),
738 DexEvent::RaydiumClmmPoolStateAccount(_) => Some(EventType::AccountRaydiumClmmPoolState),
739 DexEvent::RaydiumClmmTickArrayStateAccount(_) => {
740 Some(EventType::AccountRaydiumClmmTickArrayState)
741 }
742 DexEvent::RaydiumCpmmSwap(_) => Some(EventType::RaydiumCpmmSwap),
743 DexEvent::RaydiumCpmmDeposit(_) => Some(EventType::RaydiumCpmmDeposit),
744 DexEvent::RaydiumCpmmWithdraw(_) => Some(EventType::RaydiumCpmmWithdraw),
745 DexEvent::RaydiumCpmmInitialize(_) => Some(EventType::RaydiumCpmmInitialize),
746 DexEvent::RaydiumAmmV4Swap(_) => Some(EventType::RaydiumAmmV4Swap),
747 DexEvent::RaydiumAmmV4Deposit(_) => Some(EventType::RaydiumAmmV4Deposit),
748 DexEvent::RaydiumAmmV4Initialize2(_) => Some(EventType::RaydiumAmmV4Initialize2),
749 DexEvent::RaydiumAmmV4Withdraw(_) => Some(EventType::RaydiumAmmV4Withdraw),
750 DexEvent::RaydiumAmmV4WithdrawPnl(_) => Some(EventType::RaydiumAmmV4WithdrawPnl),
751 DexEvent::OrcaWhirlpoolSwap(_) => Some(EventType::OrcaWhirlpoolSwap),
752 DexEvent::OrcaWhirlpoolLiquidityIncreased(_) => {
753 Some(EventType::OrcaWhirlpoolLiquidityIncreased)
754 }
755 DexEvent::OrcaWhirlpoolLiquidityDecreased(_) => {
756 Some(EventType::OrcaWhirlpoolLiquidityDecreased)
757 }
758 DexEvent::OrcaWhirlpoolPoolInitialized(_) => Some(EventType::OrcaWhirlpoolPoolInitialized),
759 DexEvent::MeteoraPoolsSwap(_) => Some(EventType::MeteoraPoolsSwap),
760 DexEvent::MeteoraPoolsAddLiquidity(_) => Some(EventType::MeteoraPoolsAddLiquidity),
761 DexEvent::MeteoraPoolsRemoveLiquidity(_) => Some(EventType::MeteoraPoolsRemoveLiquidity),
762 DexEvent::MeteoraPoolsBootstrapLiquidity(_) => {
763 Some(EventType::MeteoraPoolsBootstrapLiquidity)
764 }
765 DexEvent::MeteoraPoolsPoolCreated(_) => Some(EventType::MeteoraPoolsPoolCreated),
766 DexEvent::MeteoraPoolsSetPoolFees(_) => Some(EventType::MeteoraPoolsSetPoolFees),
767 DexEvent::MeteoraDlmmSwap(_) => Some(EventType::MeteoraDlmmSwap),
768 DexEvent::MeteoraDlmmAddLiquidity(_) => Some(EventType::MeteoraDlmmAddLiquidity),
769 DexEvent::MeteoraDlmmRemoveLiquidity(_) => Some(EventType::MeteoraDlmmRemoveLiquidity),
770 DexEvent::MeteoraDlmmInitializePool(_) => Some(EventType::MeteoraDlmmInitializePool),
771 DexEvent::MeteoraDlmmInitializeBinArray(_) => {
772 Some(EventType::MeteoraDlmmInitializeBinArray)
773 }
774 DexEvent::MeteoraDlmmCreatePosition(_) => Some(EventType::MeteoraDlmmCreatePosition),
775 DexEvent::MeteoraDlmmClosePosition(_) => Some(EventType::MeteoraDlmmClosePosition),
776 DexEvent::MeteoraDlmmClaimFee(_) => Some(EventType::MeteoraDlmmClaimFee),
777 DexEvent::TokenAccount(_) => Some(EventType::TokenAccount),
778 DexEvent::NonceAccount(_) => Some(EventType::NonceAccount),
779 DexEvent::PumpSwapGlobalConfigAccount(_) => Some(EventType::AccountPumpSwapGlobalConfig),
780 DexEvent::PumpSwapPoolAccount(_) => Some(EventType::AccountPumpSwapPool),
781 DexEvent::BlockMeta(_) => Some(EventType::BlockMeta),
782 DexEvent::TokenInfo(_) | DexEvent::Error(_) => None,
783 }
784}
785
786#[cfg(test)]
787mod event_type_filter_tests {
788 use super::*;
789
790 #[test]
791 fn generic_trade_filters_cover_specific_trade_variants() {
792 let pump = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
793 assert!(pump.should_include(EventType::PumpFunTrade));
794 assert!(pump.should_include(EventType::PumpFunBuy));
795 assert!(pump.should_include(EventType::PumpFunSell));
796 assert!(pump.should_include(EventType::PumpFunBuyExactSolIn));
797
798 let pump_specific = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
799 assert!(pump_specific.should_include(EventType::PumpFunTrade));
800 assert!(pump_specific.should_include(EventType::PumpFunBuyExactSolIn));
801
802 let pump_exact_buy = EventTypeFilter::include_only(vec![EventType::PumpFunBuyExactSolIn]);
803 assert!(pump_exact_buy.should_include(EventType::PumpFunTrade));
804 assert!(pump_exact_buy.should_include(EventType::PumpFunBuy));
805
806 let pumpswap = EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]);
807 assert!(pumpswap.should_include(EventType::PumpSwapBuy));
808 assert!(pumpswap.should_include(EventType::PumpSwapSell));
809
810 let exclude_pumpswap = EventTypeFilter::exclude_types(vec![EventType::PumpSwapTrade]);
811 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapBuy));
812 assert!(!exclude_pumpswap.should_include(EventType::PumpSwapSell));
813 }
814
815 #[test]
816 fn all_protocol_groups_are_filterable() {
817 assert!(EventTypeFilter::include_only(vec![EventType::PumpFunTrade]).includes_pumpfun());
818 assert!(EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]).includes_pumpswap());
819 assert!(EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateFeeShares])
820 .includes_pump_fees());
821 assert!(
822 EventTypeFilter::include_only(vec![EventType::BonkTrade]).includes_raydium_launchpad()
823 );
824 assert!(
825 EventTypeFilter::include_only(vec![EventType::RaydiumCpmmSwap]).includes_raydium_cpmm()
826 );
827 assert!(
828 EventTypeFilter::include_only(vec![EventType::RaydiumClmmSwap]).includes_raydium_clmm()
829 );
830 assert!(EventTypeFilter::include_only(vec![EventType::RaydiumAmmV4Swap])
831 .includes_raydium_amm_v4());
832 assert!(EventTypeFilter::include_only(vec![EventType::OrcaWhirlpoolSwap])
833 .includes_orca_whirlpool());
834 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraPoolsSwap])
835 .includes_meteora_pools());
836 assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2Swap])
837 .includes_meteora_damm_v2());
838 assert!(
839 EventTypeFilter::include_only(vec![EventType::MeteoraDlmmSwap]).includes_meteora_dlmm()
840 );
841 }
842
843 #[test]
844 fn exclude_filters_do_not_skip_whole_protocol_groups() {
845 let raydium = EventTypeFilter::exclude_types(vec![EventType::RaydiumCpmmSwap]);
846 assert!(raydium.includes_raydium_cpmm());
847 assert!(!raydium.should_include(EventType::RaydiumCpmmSwap));
848 assert!(raydium.should_include(EventType::RaydiumCpmmDeposit));
849
850 let pump = EventTypeFilter::exclude_types(vec![EventType::PumpFunBuy]);
851 assert!(pump.includes_pumpfun());
852 assert!(!pump.should_include(EventType::PumpFunBuy));
853 assert!(!pump.should_include(EventType::PumpFunBuyExactSolIn));
854 assert!(pump.should_include(EventType::PumpFunSell));
855 }
856}
857
858#[derive(Debug, Clone)]
859pub struct SlotFilter {
860 pub min_slot: Option<u64>,
861 pub max_slot: Option<u64>,
862}
863
864impl SlotFilter {
865 pub fn new() -> Self {
866 Self { min_slot: None, max_slot: None }
867 }
868
869 pub fn min_slot(mut self, slot: u64) -> Self {
870 self.min_slot = Some(slot);
871 self
872 }
873
874 pub fn max_slot(mut self, slot: u64) -> Self {
875 self.max_slot = Some(slot);
876 self
877 }
878}
879
880impl Default for SlotFilter {
881 fn default() -> Self {
882 Self::new()
883 }
884}