use serde::{Deserialize, Serialize};
use yellowstone_grpc_proto::geyser::{
subscribe_request_filter_accounts_filter::Filter as AccountsFilterOneof,
subscribe_request_filter_accounts_filter_memcmp::Data as MemcmpDataOneof,
SubscribeRequestFilterAccountsFilter, SubscribeRequestFilterAccountsFilterMemcmp,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum OrderMode {
#[default]
Unordered,
Ordered,
StreamingOrdered,
MicroBatch,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientConfig {
pub enable_metrics: bool,
pub connection_timeout_ms: u64,
pub request_timeout_ms: u64,
pub enable_tls: bool,
pub max_retries: u32,
pub retry_delay_ms: u64,
pub max_concurrent_streams: u32,
pub keep_alive_interval_ms: u64,
pub keep_alive_timeout_ms: u64,
pub buffer_size: usize,
pub order_mode: OrderMode,
pub order_timeout_ms: u64,
pub micro_batch_us: u64,
}
impl Default for ClientConfig {
fn default() -> Self {
Self {
enable_metrics: false,
connection_timeout_ms: 8000,
request_timeout_ms: 15000,
enable_tls: true,
max_retries: 3,
retry_delay_ms: 1000,
max_concurrent_streams: 100,
keep_alive_interval_ms: 30000,
keep_alive_timeout_ms: 5000,
buffer_size: 100_000,
order_mode: OrderMode::Unordered,
order_timeout_ms: 100,
micro_batch_us: 100, }
}
}
impl ClientConfig {
pub fn low_latency() -> Self {
Self {
enable_metrics: false,
connection_timeout_ms: 5000,
request_timeout_ms: 10000,
enable_tls: true,
max_retries: 1,
retry_delay_ms: 100,
max_concurrent_streams: 200,
keep_alive_interval_ms: 10000,
keep_alive_timeout_ms: 2000,
buffer_size: 100_000,
order_mode: OrderMode::Unordered,
order_timeout_ms: 50,
micro_batch_us: 50, }
}
pub fn high_throughput() -> Self {
Self {
enable_metrics: true,
connection_timeout_ms: 10000,
request_timeout_ms: 30000,
enable_tls: true,
max_retries: 5,
retry_delay_ms: 2000,
max_concurrent_streams: 500,
keep_alive_interval_ms: 60000,
keep_alive_timeout_ms: 10000,
buffer_size: 200_000,
order_mode: OrderMode::Unordered,
order_timeout_ms: 200,
micro_batch_us: 200, }
}
}
#[derive(Debug, Clone)]
pub struct TransactionFilter {
pub account_include: Vec<String>,
pub account_exclude: Vec<String>,
pub account_required: Vec<String>,
}
impl TransactionFilter {
pub fn new() -> Self {
Self {
account_include: Vec::new(),
account_exclude: Vec::new(),
account_required: Vec::new(),
}
}
pub fn include_account(mut self, account: impl Into<String>) -> Self {
self.account_include.push(account.into());
self
}
pub fn exclude_account(mut self, account: impl Into<String>) -> Self {
self.account_exclude.push(account.into());
self
}
pub fn require_account(mut self, account: impl Into<String>) -> Self {
self.account_required.push(account.into());
self
}
pub fn from_program_ids(program_ids: Vec<String>) -> Self {
Self {
account_include: program_ids,
account_exclude: Vec::new(),
account_required: Vec::new(),
}
}
}
impl Default for TransactionFilter {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct AccountFilter {
pub account: Vec<String>,
pub owner: Vec<String>,
pub filters: Vec<SubscribeRequestFilterAccountsFilter>,
}
impl AccountFilter {
pub fn new() -> Self {
Self { account: Vec::new(), owner: Vec::new(), filters: Vec::new() }
}
pub fn add_account(mut self, account: impl Into<String>) -> Self {
self.account.push(account.into());
self
}
pub fn add_owner(mut self, owner: impl Into<String>) -> Self {
self.owner.push(owner.into());
self
}
pub fn add_filter(mut self, filter: SubscribeRequestFilterAccountsFilter) -> Self {
self.filters.push(filter);
self
}
pub fn from_program_owners(program_ids: Vec<String>) -> Self {
Self { account: Vec::new(), owner: program_ids, filters: Vec::new() }
}
}
impl Default for AccountFilter {
fn default() -> Self {
Self::new()
}
}
#[inline]
pub fn account_filter_memcmp(offset: u64, bytes: Vec<u8>) -> SubscribeRequestFilterAccountsFilter {
SubscribeRequestFilterAccountsFilter {
filter: Some(AccountsFilterOneof::Memcmp(SubscribeRequestFilterAccountsFilterMemcmp {
offset,
data: Some(MemcmpDataOneof::Bytes(bytes)),
})),
}
}
#[derive(Debug, Clone)]
pub struct AccountFilterData {
pub memcmp: Option<AccountFilterMemcmp>,
pub datasize: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct AccountFilterMemcmp {
pub offset: u64,
pub bytes: Vec<u8>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Protocol {
PumpFun,
PumpSwap,
PumpFees,
Bonk,
RaydiumLaunchpad,
RaydiumCpmm,
RaydiumClmm,
RaydiumAmmV4,
OrcaWhirlpool,
MeteoraPools,
MeteoraDammV2,
MeteoraDlmm,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventType {
BlockMeta,
BonkTrade,
BonkPoolCreate,
BonkMigrateAmm,
PumpFunTrade, PumpFunBuy, PumpFunSell, PumpFunBuyExactSolIn, PumpFunCreate,
PumpFunCreateV2, PumpFunComplete,
PumpFunMigrate,
PumpFeesCreateFeeSharingConfig,
PumpFeesInitializeFeeConfig,
PumpFeesResetFeeSharingConfig,
PumpFeesRevokeFeeSharingAuthority,
PumpFeesTransferFeeSharingAuthority,
PumpFeesUpdateAdmin,
PumpFeesUpdateFeeConfig,
PumpFeesUpdateFeeShares,
PumpFeesUpsertFeeTiers,
PumpFunMigrateBondingCurveCreator,
PumpSwapTrade,
PumpSwapBuy,
PumpSwapSell,
PumpSwapCreatePool,
PumpSwapLiquidityAdded,
PumpSwapLiquidityRemoved,
RaydiumCpmmSwap,
RaydiumCpmmDeposit,
RaydiumCpmmWithdraw,
RaydiumCpmmInitialize,
RaydiumClmmSwap,
RaydiumClmmCreatePool,
RaydiumClmmOpenPosition,
RaydiumClmmClosePosition,
RaydiumClmmIncreaseLiquidity,
RaydiumClmmDecreaseLiquidity,
RaydiumClmmOpenPositionWithTokenExtNft,
RaydiumClmmCollectFee,
RaydiumAmmV4Swap,
RaydiumAmmV4Deposit,
RaydiumAmmV4Withdraw,
RaydiumAmmV4Initialize2,
RaydiumAmmV4WithdrawPnl,
OrcaWhirlpoolSwap,
OrcaWhirlpoolLiquidityIncreased,
OrcaWhirlpoolLiquidityDecreased,
OrcaWhirlpoolPoolInitialized,
MeteoraPoolsSwap,
MeteoraPoolsAddLiquidity,
MeteoraPoolsRemoveLiquidity,
MeteoraPoolsBootstrapLiquidity,
MeteoraPoolsPoolCreated,
MeteoraPoolsSetPoolFees,
MeteoraDammV2Swap,
MeteoraDammV2AddLiquidity,
MeteoraDammV2RemoveLiquidity,
MeteoraDammV2CreatePosition,
MeteoraDammV2ClosePosition,
MeteoraDlmmSwap,
MeteoraDlmmAddLiquidity,
MeteoraDlmmRemoveLiquidity,
MeteoraDlmmInitializePool,
MeteoraDlmmInitializeBinArray,
MeteoraDlmmCreatePosition,
MeteoraDlmmClosePosition,
MeteoraDlmmClaimFee,
TokenAccount,
NonceAccount,
AccountPumpFunGlobal,
AccountPumpSwapGlobalConfig,
AccountPumpSwapPool,
}
#[derive(Debug, Clone)]
pub struct EventTypeFilter {
pub include_only: Option<Vec<EventType>>,
pub exclude_types: Option<Vec<EventType>>,
}
impl EventTypeFilter {
pub fn include_only(types: Vec<EventType>) -> Self {
Self { include_only: Some(types), exclude_types: None }
}
pub fn exclude_types(types: Vec<EventType>) -> Self {
Self { include_only: None, exclude_types: Some(types) }
}
#[inline]
fn includes_group<F>(&self, mut is_group: F) -> bool
where
F: FnMut(&EventType) -> bool,
{
if let Some(ref include_only) = self.include_only {
return include_only.iter().any(&mut is_group);
}
true
}
pub fn should_include(&self, event_type: EventType) -> bool {
if let Some(ref include_only) = self.include_only {
if include_only.contains(&event_type) {
return true;
}
if event_type == EventType::PumpFunTrade {
return include_only.iter().any(|t| {
matches!(
t,
EventType::PumpFunBuy
| EventType::PumpFunSell
| EventType::PumpFunBuyExactSolIn
)
});
}
if matches!(
event_type,
EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
) {
return include_only.contains(&EventType::PumpFunTrade);
}
if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell) {
return include_only.contains(&EventType::PumpSwapTrade);
}
return false;
}
if let Some(ref exclude_types) = self.exclude_types {
if exclude_types.contains(&event_type) {
return false;
}
if matches!(
event_type,
EventType::PumpFunBuy | EventType::PumpFunSell | EventType::PumpFunBuyExactSolIn
) && exclude_types.contains(&EventType::PumpFunTrade)
{
return false;
}
if matches!(event_type, EventType::PumpSwapBuy | EventType::PumpSwapSell)
&& exclude_types.contains(&EventType::PumpSwapTrade)
{
return false;
}
return true;
}
true
}
pub fn should_include_dex_event(&self, event: &crate::core::events::DexEvent) -> bool {
let Some(event_type) = event_type_from_dex_event(event) else { return true };
self.should_include(event_type)
}
#[inline]
pub fn includes_pumpfun(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::PumpFunTrade
| EventType::PumpFunBuy
| EventType::PumpFunSell
| EventType::PumpFunBuyExactSolIn
| EventType::PumpFunCreate
| EventType::PumpFunCreateV2
| EventType::PumpFunComplete
| EventType::PumpFunMigrate
| EventType::PumpFunMigrateBondingCurveCreator
| EventType::AccountPumpFunGlobal
)
})
}
#[inline]
pub fn includes_meteora_damm_v2(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::MeteoraDammV2Swap
| EventType::MeteoraDammV2AddLiquidity
| EventType::MeteoraDammV2CreatePosition
| EventType::MeteoraDammV2ClosePosition
| EventType::MeteoraDammV2RemoveLiquidity
)
})
}
#[inline]
pub fn includes_pump_fees(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::PumpFeesCreateFeeSharingConfig
| EventType::PumpFeesInitializeFeeConfig
| EventType::PumpFeesResetFeeSharingConfig
| EventType::PumpFeesRevokeFeeSharingAuthority
| EventType::PumpFeesTransferFeeSharingAuthority
| EventType::PumpFeesUpdateAdmin
| EventType::PumpFeesUpdateFeeConfig
| EventType::PumpFeesUpdateFeeShares
| EventType::PumpFeesUpsertFeeTiers
)
})
}
#[inline]
pub fn includes_pumpswap(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::PumpSwapTrade
| EventType::PumpSwapBuy
| EventType::PumpSwapSell
| EventType::PumpSwapCreatePool
| EventType::PumpSwapLiquidityAdded
| EventType::PumpSwapLiquidityRemoved
)
})
}
#[inline]
pub fn includes_raydium_launchpad(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::BonkTrade | EventType::BonkPoolCreate | EventType::BonkMigrateAmm
)
})
}
#[inline]
pub fn includes_raydium_cpmm(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::RaydiumCpmmSwap
| EventType::RaydiumCpmmDeposit
| EventType::RaydiumCpmmWithdraw
| EventType::RaydiumCpmmInitialize
)
})
}
#[inline]
pub fn includes_raydium_clmm(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::RaydiumClmmSwap
| EventType::RaydiumClmmCreatePool
| EventType::RaydiumClmmOpenPosition
| EventType::RaydiumClmmClosePosition
| EventType::RaydiumClmmIncreaseLiquidity
| EventType::RaydiumClmmDecreaseLiquidity
| EventType::RaydiumClmmOpenPositionWithTokenExtNft
| EventType::RaydiumClmmCollectFee
)
})
}
#[inline]
pub fn includes_raydium_amm_v4(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::RaydiumAmmV4Swap
| EventType::RaydiumAmmV4Deposit
| EventType::RaydiumAmmV4Withdraw
| EventType::RaydiumAmmV4Initialize2
| EventType::RaydiumAmmV4WithdrawPnl
)
})
}
#[inline]
pub fn includes_orca_whirlpool(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::OrcaWhirlpoolSwap
| EventType::OrcaWhirlpoolLiquidityIncreased
| EventType::OrcaWhirlpoolLiquidityDecreased
| EventType::OrcaWhirlpoolPoolInitialized
)
})
}
#[inline]
pub fn includes_meteora_pools(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::MeteoraPoolsSwap
| EventType::MeteoraPoolsAddLiquidity
| EventType::MeteoraPoolsRemoveLiquidity
| EventType::MeteoraPoolsBootstrapLiquidity
| EventType::MeteoraPoolsPoolCreated
| EventType::MeteoraPoolsSetPoolFees
)
})
}
#[inline]
pub fn includes_meteora_dlmm(&self) -> bool {
self.includes_group(|t| {
matches!(
t,
EventType::MeteoraDlmmSwap
| EventType::MeteoraDlmmAddLiquidity
| EventType::MeteoraDlmmRemoveLiquidity
| EventType::MeteoraDlmmInitializePool
| EventType::MeteoraDlmmInitializeBinArray
| EventType::MeteoraDlmmCreatePosition
| EventType::MeteoraDlmmClosePosition
| EventType::MeteoraDlmmClaimFee
)
})
}
}
#[inline]
pub fn event_type_from_dex_event(event: &crate::core::events::DexEvent) -> Option<EventType> {
use crate::core::events::DexEvent;
match event {
DexEvent::PumpFunCreate(_) => Some(EventType::PumpFunCreate),
DexEvent::PumpFunCreateV2(_) => Some(EventType::PumpFunCreateV2),
DexEvent::PumpFunTrade(_) => Some(EventType::PumpFunTrade),
DexEvent::PumpFunBuy(_) => Some(EventType::PumpFunBuy),
DexEvent::PumpFunSell(_) => Some(EventType::PumpFunSell),
DexEvent::PumpFunBuyExactSolIn(_) => Some(EventType::PumpFunBuyExactSolIn),
DexEvent::PumpFunMigrate(_) => Some(EventType::PumpFunMigrate),
DexEvent::PumpFeesCreateFeeSharingConfig(_) => {
Some(EventType::PumpFeesCreateFeeSharingConfig)
}
DexEvent::PumpFeesInitializeFeeConfig(_) => Some(EventType::PumpFeesInitializeFeeConfig),
DexEvent::PumpFeesResetFeeSharingConfig(_) => {
Some(EventType::PumpFeesResetFeeSharingConfig)
}
DexEvent::PumpFeesRevokeFeeSharingAuthority(_) => {
Some(EventType::PumpFeesRevokeFeeSharingAuthority)
}
DexEvent::PumpFeesTransferFeeSharingAuthority(_) => {
Some(EventType::PumpFeesTransferFeeSharingAuthority)
}
DexEvent::PumpFeesUpdateAdmin(_) => Some(EventType::PumpFeesUpdateAdmin),
DexEvent::PumpFeesUpdateFeeConfig(_) => Some(EventType::PumpFeesUpdateFeeConfig),
DexEvent::PumpFeesUpdateFeeShares(_) => Some(EventType::PumpFeesUpdateFeeShares),
DexEvent::PumpFeesUpsertFeeTiers(_) => Some(EventType::PumpFeesUpsertFeeTiers),
DexEvent::PumpFunMigrateBondingCurveCreator(_) => {
Some(EventType::PumpFunMigrateBondingCurveCreator)
}
DexEvent::PumpFunGlobalAccount(_) => Some(EventType::AccountPumpFunGlobal),
DexEvent::PumpSwapTrade(_) => Some(EventType::PumpSwapTrade),
DexEvent::PumpSwapBuy(_) => Some(EventType::PumpSwapBuy),
DexEvent::PumpSwapSell(_) => Some(EventType::PumpSwapSell),
DexEvent::PumpSwapCreatePool(_) => Some(EventType::PumpSwapCreatePool),
DexEvent::PumpSwapLiquidityAdded(_) => Some(EventType::PumpSwapLiquidityAdded),
DexEvent::PumpSwapLiquidityRemoved(_) => Some(EventType::PumpSwapLiquidityRemoved),
DexEvent::MeteoraDammV2Swap(_) => Some(EventType::MeteoraDammV2Swap),
DexEvent::MeteoraDammV2CreatePosition(_) => Some(EventType::MeteoraDammV2CreatePosition),
DexEvent::MeteoraDammV2ClosePosition(_) => Some(EventType::MeteoraDammV2ClosePosition),
DexEvent::MeteoraDammV2AddLiquidity(_) => Some(EventType::MeteoraDammV2AddLiquidity),
DexEvent::MeteoraDammV2RemoveLiquidity(_) => Some(EventType::MeteoraDammV2RemoveLiquidity),
DexEvent::BonkTrade(_) => Some(EventType::BonkTrade),
DexEvent::BonkPoolCreate(_) => Some(EventType::BonkPoolCreate),
DexEvent::BonkMigrateAmm(_) => Some(EventType::BonkMigrateAmm),
DexEvent::RaydiumClmmSwap(_) => Some(EventType::RaydiumClmmSwap),
DexEvent::RaydiumClmmCreatePool(_) => Some(EventType::RaydiumClmmCreatePool),
DexEvent::RaydiumClmmOpenPosition(_) => Some(EventType::RaydiumClmmOpenPosition),
DexEvent::RaydiumClmmOpenPositionWithTokenExtNft(_) => {
Some(EventType::RaydiumClmmOpenPositionWithTokenExtNft)
}
DexEvent::RaydiumClmmClosePosition(_) => Some(EventType::RaydiumClmmClosePosition),
DexEvent::RaydiumClmmIncreaseLiquidity(_) => Some(EventType::RaydiumClmmIncreaseLiquidity),
DexEvent::RaydiumClmmDecreaseLiquidity(_) => Some(EventType::RaydiumClmmDecreaseLiquidity),
DexEvent::RaydiumClmmCollectFee(_) => Some(EventType::RaydiumClmmCollectFee),
DexEvent::RaydiumCpmmSwap(_) => Some(EventType::RaydiumCpmmSwap),
DexEvent::RaydiumCpmmDeposit(_) => Some(EventType::RaydiumCpmmDeposit),
DexEvent::RaydiumCpmmWithdraw(_) => Some(EventType::RaydiumCpmmWithdraw),
DexEvent::RaydiumCpmmInitialize(_) => Some(EventType::RaydiumCpmmInitialize),
DexEvent::RaydiumAmmV4Swap(_) => Some(EventType::RaydiumAmmV4Swap),
DexEvent::RaydiumAmmV4Deposit(_) => Some(EventType::RaydiumAmmV4Deposit),
DexEvent::RaydiumAmmV4Initialize2(_) => Some(EventType::RaydiumAmmV4Initialize2),
DexEvent::RaydiumAmmV4Withdraw(_) => Some(EventType::RaydiumAmmV4Withdraw),
DexEvent::RaydiumAmmV4WithdrawPnl(_) => Some(EventType::RaydiumAmmV4WithdrawPnl),
DexEvent::OrcaWhirlpoolSwap(_) => Some(EventType::OrcaWhirlpoolSwap),
DexEvent::OrcaWhirlpoolLiquidityIncreased(_) => {
Some(EventType::OrcaWhirlpoolLiquidityIncreased)
}
DexEvent::OrcaWhirlpoolLiquidityDecreased(_) => {
Some(EventType::OrcaWhirlpoolLiquidityDecreased)
}
DexEvent::OrcaWhirlpoolPoolInitialized(_) => Some(EventType::OrcaWhirlpoolPoolInitialized),
DexEvent::MeteoraPoolsSwap(_) => Some(EventType::MeteoraPoolsSwap),
DexEvent::MeteoraPoolsAddLiquidity(_) => Some(EventType::MeteoraPoolsAddLiquidity),
DexEvent::MeteoraPoolsRemoveLiquidity(_) => Some(EventType::MeteoraPoolsRemoveLiquidity),
DexEvent::MeteoraPoolsBootstrapLiquidity(_) => {
Some(EventType::MeteoraPoolsBootstrapLiquidity)
}
DexEvent::MeteoraPoolsPoolCreated(_) => Some(EventType::MeteoraPoolsPoolCreated),
DexEvent::MeteoraPoolsSetPoolFees(_) => Some(EventType::MeteoraPoolsSetPoolFees),
DexEvent::MeteoraDlmmSwap(_) => Some(EventType::MeteoraDlmmSwap),
DexEvent::MeteoraDlmmAddLiquidity(_) => Some(EventType::MeteoraDlmmAddLiquidity),
DexEvent::MeteoraDlmmRemoveLiquidity(_) => Some(EventType::MeteoraDlmmRemoveLiquidity),
DexEvent::MeteoraDlmmInitializePool(_) => Some(EventType::MeteoraDlmmInitializePool),
DexEvent::MeteoraDlmmInitializeBinArray(_) => {
Some(EventType::MeteoraDlmmInitializeBinArray)
}
DexEvent::MeteoraDlmmCreatePosition(_) => Some(EventType::MeteoraDlmmCreatePosition),
DexEvent::MeteoraDlmmClosePosition(_) => Some(EventType::MeteoraDlmmClosePosition),
DexEvent::MeteoraDlmmClaimFee(_) => Some(EventType::MeteoraDlmmClaimFee),
DexEvent::TokenAccount(_) => Some(EventType::TokenAccount),
DexEvent::NonceAccount(_) => Some(EventType::NonceAccount),
DexEvent::PumpSwapGlobalConfigAccount(_) => Some(EventType::AccountPumpSwapGlobalConfig),
DexEvent::PumpSwapPoolAccount(_) => Some(EventType::AccountPumpSwapPool),
DexEvent::BlockMeta(_) => Some(EventType::BlockMeta),
DexEvent::TokenInfo(_) | DexEvent::Error(_) => None,
}
}
#[cfg(test)]
mod event_type_filter_tests {
use super::*;
#[test]
fn generic_trade_filters_cover_specific_trade_variants() {
let pump = EventTypeFilter::include_only(vec![EventType::PumpFunTrade]);
assert!(pump.should_include(EventType::PumpFunTrade));
assert!(pump.should_include(EventType::PumpFunBuy));
assert!(pump.should_include(EventType::PumpFunSell));
assert!(pump.should_include(EventType::PumpFunBuyExactSolIn));
let pump_specific = EventTypeFilter::include_only(vec![EventType::PumpFunBuy]);
assert!(pump_specific.should_include(EventType::PumpFunTrade));
let pumpswap = EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]);
assert!(pumpswap.should_include(EventType::PumpSwapBuy));
assert!(pumpswap.should_include(EventType::PumpSwapSell));
let exclude_pumpswap = EventTypeFilter::exclude_types(vec![EventType::PumpSwapTrade]);
assert!(!exclude_pumpswap.should_include(EventType::PumpSwapBuy));
assert!(!exclude_pumpswap.should_include(EventType::PumpSwapSell));
}
#[test]
fn all_protocol_groups_are_filterable() {
assert!(EventTypeFilter::include_only(vec![EventType::PumpFunTrade]).includes_pumpfun());
assert!(EventTypeFilter::include_only(vec![EventType::PumpSwapTrade]).includes_pumpswap());
assert!(EventTypeFilter::include_only(vec![EventType::PumpFeesUpdateFeeShares])
.includes_pump_fees());
assert!(
EventTypeFilter::include_only(vec![EventType::BonkTrade]).includes_raydium_launchpad()
);
assert!(
EventTypeFilter::include_only(vec![EventType::RaydiumCpmmSwap]).includes_raydium_cpmm()
);
assert!(
EventTypeFilter::include_only(vec![EventType::RaydiumClmmSwap]).includes_raydium_clmm()
);
assert!(EventTypeFilter::include_only(vec![EventType::RaydiumAmmV4Swap])
.includes_raydium_amm_v4());
assert!(EventTypeFilter::include_only(vec![EventType::OrcaWhirlpoolSwap])
.includes_orca_whirlpool());
assert!(EventTypeFilter::include_only(vec![EventType::MeteoraPoolsSwap])
.includes_meteora_pools());
assert!(EventTypeFilter::include_only(vec![EventType::MeteoraDammV2Swap])
.includes_meteora_damm_v2());
assert!(
EventTypeFilter::include_only(vec![EventType::MeteoraDlmmSwap]).includes_meteora_dlmm()
);
}
#[test]
fn exclude_filters_do_not_skip_whole_protocol_groups() {
let raydium = EventTypeFilter::exclude_types(vec![EventType::RaydiumCpmmSwap]);
assert!(raydium.includes_raydium_cpmm());
assert!(!raydium.should_include(EventType::RaydiumCpmmSwap));
assert!(raydium.should_include(EventType::RaydiumCpmmDeposit));
let pump = EventTypeFilter::exclude_types(vec![EventType::PumpFunBuy]);
assert!(pump.includes_pumpfun());
assert!(!pump.should_include(EventType::PumpFunBuy));
assert!(pump.should_include(EventType::PumpFunSell));
}
}
#[derive(Debug, Clone)]
pub struct SlotFilter {
pub min_slot: Option<u64>,
pub max_slot: Option<u64>,
}
impl SlotFilter {
pub fn new() -> Self {
Self { min_slot: None, max_slot: None }
}
pub fn min_slot(mut self, slot: u64) -> Self {
self.min_slot = Some(slot);
self
}
pub fn max_slot(mut self, slot: u64) -> Self {
self.max_slot = Some(slot);
self
}
}
impl Default for SlotFilter {
fn default() -> Self {
Self::new()
}
}