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