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