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