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