refactor: restructure event handling from trait objects to enum pattern

- Convert UnifiedEvent from trait object (Box<dyn UnifiedEvent>) to concrete enum type
  - Remove match_event! macro in favor of native match expressions
  - Simplify event metadata access: event.event_type() -> event.metadata().event_type
  - Unify event callback signatures: Fn(Box<dyn UnifiedEvent>) -> Fn(UnifiedEvent)
  - Update all example code to use the new enum-based event system
  - Optimize type system to reduce runtime overhead and improve type safety

  Affected scope:
  - Core event parser and processor
  - All protocol event definitions (PumpFun, PumpSwap, Bonk, Raydium series, etc.)
  - gRPC and Shred streaming modules
  - All example code
This commit is contained in:
ysq
2025-10-10 18:19:44 +08:00
parent 77caa39f0c
commit 312a675a40
43 changed files with 1013 additions and 1839 deletions
@@ -1,4 +1,3 @@
use crate::impl_unified_event;
use crate::streaming::common::SimdUtils;
use crate::streaming::event_parser::common::filter::EventTypeFilter;
use crate::streaming::event_parser::common::high_performance_clock::elapsed_micros_since;
@@ -46,7 +45,6 @@ pub struct TokenAccountEvent {
pub amount: Option<u64>,
pub token_owner: Pubkey,
}
impl_unified_event!(TokenAccountEvent,);
/// Nonce account event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
@@ -60,7 +58,6 @@ pub struct NonceAccountEvent {
pub nonce: String,
pub authority: String,
}
impl_unified_event!(NonceAccountEvent,);
/// Nonce account event
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
@@ -74,11 +71,10 @@ pub struct TokenInfoEvent {
pub supply: u64,
pub decimals: u8,
}
impl_unified_event!(TokenInfoEvent,);
/// 账户事件解析器
pub type AccountEventParserFn =
fn(account: &AccountPretty, metadata: EventMetadata) -> Option<Box<dyn UnifiedEvent>>;
fn(account: &AccountPretty, metadata: EventMetadata) -> Option<UnifiedEvent>;
static PROTOCOL_CONFIGS_CACHE: OnceLock<HashMap<Protocol, Vec<AccountEventParseConfig>>> =
OnceLock::new();
@@ -256,7 +252,7 @@ impl AccountEventParser {
protocols: &[Protocol],
account: AccountPretty,
event_type_filter: Option<&EventTypeFilter>,
) -> Option<Box<dyn UnifiedEvent>> {
) -> Option<UnifiedEvent> {
let configs = Self::configs(protocols, event_type_filter);
for config in configs {
if config.program_id == Pubkey::default()
@@ -275,13 +271,11 @@ impl AccountEventParser {
event_type: config.event_type,
program_id: config.program_id,
recv_us: account.recv_us,
handle_us: elapsed_micros_since(account.recv_us),
..Default::default()
},
);
if let Some(mut event) = event {
event.set_handle_us(elapsed_micros_since(account.recv_us));
return Some(event);
}
return event;
}
}
None
@@ -290,7 +284,7 @@ impl AccountEventParser {
pub fn parse_token_account_event(
account: &AccountPretty,
metadata: EventMetadata,
) -> Option<Box<dyn UnifiedEvent>> {
) -> Option<UnifiedEvent> {
let pubkey = account.pubkey;
let executable = account.executable;
let lamports = account.lamports;
@@ -310,8 +304,8 @@ impl AccountEventParser {
decimals: mint.decimals,
};
let recv_delta = elapsed_micros_since(account.recv_us);
event.set_handle_us(recv_delta);
return Some(Box::new(event));
event.metadata.handle_us = recv_delta;
return Some(UnifiedEvent::TokenInfoEvent(event));
}
}
// Spl Token2022 Mint
@@ -328,8 +322,8 @@ impl AccountEventParser {
decimals: mint.base.decimals,
};
let recv_delta = elapsed_micros_since(account.recv_us);
event.set_handle_us(recv_delta);
return Some(Box::new(event));
event.metadata.handle_us = recv_delta;
return Some(UnifiedEvent::TokenInfoEvent(event));
}
}
let amount = if account.owner.to_bytes() == spl_token_2022::ID.to_bytes() {
@@ -351,14 +345,14 @@ impl AccountEventParser {
token_owner: account.owner,
};
let recv_delta = elapsed_micros_since(account.recv_us);
event.set_handle_us(recv_delta);
Some(Box::new(event))
event.metadata.handle_us = recv_delta;
Some(UnifiedEvent::TokenAccountEvent(event))
}
pub fn parse_nonce_account_event(
account: &AccountPretty,
metadata: EventMetadata,
) -> Option<Box<dyn UnifiedEvent>> {
) -> Option<UnifiedEvent> {
if let Ok(info) = parse_nonce(&account.data) {
match info {
solana_account_decoder::parse_nonce::UiNonceState::Initialized(details) => {
@@ -372,8 +366,8 @@ impl AccountEventParser {
nonce: details.blockhash,
authority: details.authority,
};
event.set_handle_us(elapsed_micros_since(account.recv_us));
return Some(Box::new(event));
event.metadata.handle_us = elapsed_micros_since(account.recv_us);
return Some(UnifiedEvent::NonceAccountEvent(event));
}
solana_account_decoder::parse_nonce::UiNonceState::Uninitialized => {}
}
@@ -10,9 +10,9 @@ impl CommonEventParser {
block_hash: String,
block_time_ms: i64,
recv_us: i64,
) -> Box<dyn UnifiedEvent> {
) -> UnifiedEvent {
let mut block_meta_event = BlockMetaEvent::new(slot, block_hash, block_time_ms, recv_us);
block_meta_event.set_handle_us(elapsed_micros_since(recv_us));
Box::new(block_meta_event)
block_meta_event.metadata.handle_us = elapsed_micros_since(recv_us);
UnifiedEvent::BlockMetaEvent(block_meta_event)
}
}
+92 -78
View File
@@ -12,9 +12,8 @@ use crate::streaming::{
is_dev_address_in_signature,
},
protocols::{
bonk::{parser::BONK_PROGRAM_ID, BonkPoolCreateEvent, BonkTradeEvent},
pumpfun::{parser::PUMPFUN_PROGRAM_ID, PumpFunCreateTokenEvent, PumpFunTradeEvent},
pumpswap::{parser::PUMPSWAP_PROGRAM_ID, PumpSwapBuyEvent, PumpSwapSellEvent},
bonk::parser::BONK_PROGRAM_ID, pumpfun::parser::PUMPFUN_PROGRAM_ID,
pumpswap::parser::PUMPSWAP_PROGRAM_ID,
raydium_amm_v4::parser::RAYDIUM_AMM_V4_PROGRAM_ID,
raydium_clmm::parser::RAYDIUM_CLMM_PROGRAM_ID,
raydium_cpmm::parser::RAYDIUM_CPMM_PROGRAM_ID,
@@ -23,7 +22,10 @@ use crate::streaming::{
},
};
use prost_types::Timestamp;
use solana_sdk::{bs58, message::compiled_instruction::CompiledInstruction, pubkey::Pubkey, signature::Signature, transaction::VersionedTransaction};
use solana_sdk::{
bs58, message::compiled_instruction::CompiledInstruction, pubkey::Pubkey, signature::Signature,
transaction::VersionedTransaction,
};
use solana_transaction_status::{
EncodedConfirmedTransactionWithStatusMeta, InnerInstruction, InnerInstructions, UiInstruction,
};
@@ -81,11 +83,11 @@ impl Default for AccountPubkeyCache {
/// 内联指令事件解析器
pub type InnerInstructionEventParser =
fn(data: &[u8], metadata: EventMetadata) -> Option<Box<dyn UnifiedEvent>>;
fn(data: &[u8], metadata: EventMetadata) -> Option<UnifiedEvent>;
/// 指令事件解析器
pub type InstructionEventParser =
fn(data: &[u8], accounts: &[Pubkey], metadata: EventMetadata) -> Option<Box<dyn UnifiedEvent>>;
fn(data: &[u8], accounts: &[Pubkey], metadata: EventMetadata) -> Option<UnifiedEvent>;
/// 通用事件解析器配置
#[derive(Debug, Clone)]
@@ -200,7 +202,7 @@ impl EventParser {
inner_instructions: &[yellowstone_grpc_proto::prelude::InnerInstructions],
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
// 获取交易的指令和账户
let mut accounts = accounts.to_vec();
@@ -283,7 +285,7 @@ impl EventParser {
inner_instructions: &[InnerInstructions],
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
// 获取交易的指令和账户
let compiled_instructions = transaction.message.instructions();
@@ -356,11 +358,11 @@ impl EventParser {
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
inner_instructions: &[InnerInstructions],
callback: Arc<dyn Fn(Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn Fn(UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
// 创建适配器回调,将所有权回调转换为引用回调
let adapter_callback = Arc::new(move |event: &Box<dyn UnifiedEvent>| {
callback(event.clone_boxed());
let adapter_callback = Arc::new(move |event: &UnifiedEvent| {
callback(event.clone());
});
self.parse_versioned_transaction(
&versioned_tx,
@@ -387,7 +389,7 @@ impl EventParser {
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
inner_instructions: &[InnerInstructions],
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
let accounts: Vec<Pubkey> = versioned_tx.message.static_account_keys().to_vec();
self.parse_instruction_events_from_versioned_transaction(
@@ -415,11 +417,11 @@ impl EventParser {
recv_us: i64,
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
callback: Arc<dyn Fn(Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn Fn(UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
// 创建适配器回调,将所有权回调转换为引用回调
let adapter_callback = Arc::new(move |event: &Box<dyn UnifiedEvent>| {
callback(event.clone_boxed());
let adapter_callback = Arc::new(move |event: &UnifiedEvent| {
callback(event.clone());
});
// 调用原始方法
self.parse_grpc_transaction(
@@ -444,7 +446,7 @@ impl EventParser {
recv_us: i64,
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
if let Some(transition) = grpc_tx.transaction {
if let Some(message) = &transition.message {
@@ -508,7 +510,7 @@ impl EventParser {
&self,
signature: Signature,
transaction: EncodedConfirmedTransactionWithStatusMeta,
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
let versioned_tx = match transaction.transaction.transaction.decode() {
Some(tx) => tx,
@@ -628,7 +630,7 @@ impl EventParser {
outer_index: i64,
inner_index: Option<i64>,
transaction_index: Option<u64>,
) -> Option<Box<dyn UnifiedEvent>> {
) -> Option<UnifiedEvent> {
if let Some(parser) = config.inner_instruction_parser {
let timestamp = block_time.unwrap_or(Timestamp { seconds: 0, nanos: 0 });
let block_time_ms = timestamp.seconds * 1000 + (timestamp.nanos as i64) / 1_000_000;
@@ -665,7 +667,7 @@ impl EventParser {
outer_index: i64,
inner_index: Option<i64>,
transaction_index: Option<u64>,
) -> Option<Box<dyn UnifiedEvent>> {
) -> Option<UnifiedEvent> {
if let Some(parser) = config.instruction_parser {
let timestamp = block_time.unwrap_or(Timestamp { seconds: 0, nanos: 0 });
let block_time_ms = timestamp.seconds * 1000 + (timestamp.nanos as i64) / 1_000_000;
@@ -701,7 +703,7 @@ impl EventParser {
inner_index: Option<i64>,
transaction_index: Option<u64>,
config: &GenericEventParseConfig,
) -> Vec<Box<dyn UnifiedEvent>> {
) -> Vec<UnifiedEvent> {
// Use SIMD-optimized data validation with correct discriminator length
let discriminator_len = config.inner_instruction_discriminator.len();
if !SimdUtils::validate_instruction_data_simd(
@@ -751,7 +753,7 @@ impl EventParser {
inner_index: Option<i64>,
transaction_index: Option<u64>,
config: &GenericEventParseConfig,
) -> Vec<Box<dyn UnifiedEvent>> {
) -> Vec<UnifiedEvent> {
// Use SIMD-optimized data validation with correct discriminator length
let discriminator_len = config.inner_instruction_discriminator.len();
if !SimdUtils::validate_instruction_data_simd(
@@ -803,7 +805,7 @@ impl EventParser {
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
inner_instructions: Option<&InnerInstructions>,
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
let program_id = accounts[instruction.program_id_index as usize];
if !self.should_handle(&program_id) {
@@ -860,7 +862,7 @@ impl EventParser {
for (_disc, config, mut event) in all_results {
// 阻塞处理:原有的同步逻辑
let mut inner_instruction_event: Option<Box<dyn UnifiedEvent>> = None;
let mut inner_instruction_event: Option<UnifiedEvent> = None;
if inner_instructions.is_some() {
let inner_instructions_ref = inner_instructions.unwrap();
@@ -887,9 +889,9 @@ impl EventParser {
});
let swap_data_handle = s.spawn(|| {
if !event.swap_data_is_parsed() {
if !event.metadata().swap_data.is_some() {
parse_swap_data_from_next_instructions(
&*event,
&event,
inner_instructions_ref,
inner_index.unwrap_or(-1_i64) as i8,
&accounts,
@@ -905,7 +907,7 @@ impl EventParser {
inner_instruction_event = inner_event_result;
if let Some(swap_data) = swap_data_result {
event.set_swap_data(swap_data);
event.metadata_mut().set_swap_data(swap_data);
}
}
@@ -916,10 +918,10 @@ impl EventParser {
// 合并事件
if let Some(inner_instruction_event) = inner_instruction_event {
event.merge(&*inner_instruction_event);
// event.merge(&*inner_instruction_event);
}
// 设置处理时间(使用高性能时钟)
event.set_handle_us(elapsed_micros_since(recv_us));
event.metadata_mut().handle_us = elapsed_micros_since(recv_us);
event = process_event(event, bot_wallet);
callback(&event);
}
@@ -942,7 +944,7 @@ impl EventParser {
bot_wallet: Option<Pubkey>,
transaction_index: Option<u64>,
inner_instructions: Option<&yellowstone_grpc_proto::prelude::InnerInstructions>,
callback: Arc<dyn for<'a> Fn(&'a Box<dyn UnifiedEvent>) + Send + Sync>,
callback: Arc<dyn for<'a> Fn(&'a UnifiedEvent) + Send + Sync>,
) -> anyhow::Result<()> {
let program_id = accounts[instruction.program_id_index as usize];
if !self.should_handle(&program_id) {
@@ -999,7 +1001,7 @@ impl EventParser {
for (_disc, config, mut event) in all_results {
// 阻塞处理:原有的同步逻辑
let mut inner_instruction_event: Option<Box<dyn UnifiedEvent>> = None;
let mut inner_instruction_event: Option<UnifiedEvent> = None;
if inner_instructions.is_some() {
let inner_instructions_ref = inner_instructions.unwrap();
@@ -1026,9 +1028,9 @@ impl EventParser {
});
let swap_data_handle = s.spawn(|| {
if !event.swap_data_is_parsed() {
if !event.metadata().swap_data.is_some() {
parse_swap_data_from_next_grpc_instructions(
&*event,
&event,
inner_instructions_ref,
inner_index.unwrap_or(-1_i64) as i8,
&accounts,
@@ -1044,7 +1046,7 @@ impl EventParser {
inner_instruction_event = inner_event_result;
if let Some(swap_data) = swap_data_result {
event.set_swap_data(swap_data);
event.metadata_mut().set_swap_data(swap_data);
}
}
@@ -1055,10 +1057,10 @@ impl EventParser {
// 合并事件
if let Some(inner_instruction_event) = inner_instruction_event {
event.merge(&*inner_instruction_event);
// event.merge(&*inner_instruction_event);
}
// 设置处理时间(使用高性能时钟)
event.set_handle_us(elapsed_micros_since(recv_us));
event.metadata_mut().handle_us = elapsed_micros_since(recv_us);
event = process_event(event, bot_wallet);
callback(&event);
}
@@ -1074,54 +1076,66 @@ impl EventParser {
// }
}
fn process_event(
mut event: Box<dyn UnifiedEvent>,
bot_wallet: Option<Pubkey>,
) -> Box<dyn UnifiedEvent> {
let signature = *event.signature(); // Copy the signature to avoid borrowing issues
if let Some(token_info) = event.as_any().downcast_ref::<PumpFunCreateTokenEvent>() {
add_dev_address(&signature, token_info.user);
if token_info.creator != Pubkey::default() && token_info.creator != token_info.user {
add_dev_address(&signature, token_info.creator);
fn process_event(mut event: UnifiedEvent, bot_wallet: Option<Pubkey>) -> UnifiedEvent {
let signature = event.metadata().signature; // Copy the signature to avoid borrowing issues
match event {
UnifiedEvent::PumpFunCreateTokenEvent(token_info) => {
add_dev_address(&signature, token_info.user);
if token_info.creator != Pubkey::default() && token_info.creator != token_info.user {
add_dev_address(&signature, token_info.creator);
}
UnifiedEvent::PumpFunCreateTokenEvent(token_info)
}
} else if let Some(trade_info) = event.as_any_mut().downcast_mut::<PumpFunTradeEvent>() {
if is_dev_address_in_signature(&signature, &trade_info.user)
|| is_dev_address_in_signature(&signature, &trade_info.creator)
{
trade_info.is_dev_create_token_trade = true;
} else if Some(trade_info.user) == bot_wallet {
trade_info.is_bot = true;
} else {
trade_info.is_dev_create_token_trade = false;
UnifiedEvent::PumpFunTradeEvent(mut trade_info) => {
if is_dev_address_in_signature(&signature, &trade_info.user)
|| is_dev_address_in_signature(&signature, &trade_info.creator)
{
trade_info.is_dev_create_token_trade = true;
} else if Some(trade_info.user) == bot_wallet {
trade_info.is_bot = true;
} else {
trade_info.is_dev_create_token_trade = false;
}
if trade_info.metadata.swap_data.is_some() {
trade_info.metadata.swap_data.as_mut().unwrap().from_amount =
if trade_info.is_buy { trade_info.sol_amount } else { trade_info.token_amount };
trade_info.metadata.swap_data.as_mut().unwrap().to_amount =
if trade_info.is_buy { trade_info.token_amount } else { trade_info.sol_amount };
}
UnifiedEvent::PumpFunTradeEvent(trade_info)
}
if trade_info.metadata.swap_data.is_some() {
trade_info.metadata.swap_data.as_mut().unwrap().from_amount =
if trade_info.is_buy { trade_info.sol_amount } else { trade_info.token_amount };
trade_info.metadata.swap_data.as_mut().unwrap().to_amount =
if trade_info.is_buy { trade_info.token_amount } else { trade_info.sol_amount };
UnifiedEvent::PumpSwapBuyEvent(mut trade_info) => {
if trade_info.metadata.swap_data.is_some() {
trade_info.metadata.swap_data.as_mut().unwrap().from_amount =
trade_info.user_quote_amount_in;
trade_info.metadata.swap_data.as_mut().unwrap().to_amount =
trade_info.base_amount_out;
}
UnifiedEvent::PumpSwapBuyEvent(trade_info)
}
} else if let Some(trade_info) = event.as_any_mut().downcast_mut::<PumpSwapBuyEvent>() {
if trade_info.metadata.swap_data.is_some() {
trade_info.metadata.swap_data.as_mut().unwrap().from_amount =
trade_info.user_quote_amount_in;
trade_info.metadata.swap_data.as_mut().unwrap().to_amount = trade_info.base_amount_out;
UnifiedEvent::PumpSwapSellEvent(mut trade_info) => {
if trade_info.metadata.swap_data.is_some() {
trade_info.metadata.swap_data.as_mut().unwrap().from_amount =
trade_info.base_amount_in;
trade_info.metadata.swap_data.as_mut().unwrap().to_amount =
trade_info.user_quote_amount_out;
}
UnifiedEvent::PumpSwapSellEvent(trade_info)
}
} else if let Some(trade_info) = event.as_any_mut().downcast_mut::<PumpSwapSellEvent>() {
if trade_info.metadata.swap_data.is_some() {
trade_info.metadata.swap_data.as_mut().unwrap().from_amount = trade_info.base_amount_in;
trade_info.metadata.swap_data.as_mut().unwrap().to_amount =
trade_info.user_quote_amount_out;
UnifiedEvent::BonkPoolCreateEvent(pool_info) => {
add_bonk_dev_address(&signature, pool_info.creator);
UnifiedEvent::BonkPoolCreateEvent(pool_info)
}
} else if let Some(pool_info) = event.as_any().downcast_ref::<BonkPoolCreateEvent>() {
add_bonk_dev_address(&signature, pool_info.creator);
} else if let Some(trade_info) = event.as_any_mut().downcast_mut::<BonkTradeEvent>() {
if is_bonk_dev_address_in_signature(&signature, &trade_info.payer) {
trade_info.is_dev_create_token_trade = true;
} else if Some(trade_info.payer) == bot_wallet {
trade_info.is_bot = true;
} else {
trade_info.is_dev_create_token_trade = false;
UnifiedEvent::BonkTradeEvent(mut trade_info) => {
if is_bonk_dev_address_in_signature(&signature, &trade_info.payer) {
trade_info.is_dev_create_token_trade = true;
} else if Some(trade_info.payer) == bot_wallet {
trade_info.is_bot = true;
} else {
trade_info.is_dev_create_token_trade = false;
}
UnifiedEvent::BonkTradeEvent(trade_info)
}
_ => event,
}
event
}
+169 -47
View File
@@ -1,59 +1,181 @@
use crate::streaming::event_parser::common::EventType;
use crate::streaming::event_parser::common::SwapData;
use solana_sdk::signature::Signature;
use crate::streaming::event_parser::common::EventMetadata;
use crate::streaming::event_parser::core::account_event_parser::{
NonceAccountEvent, TokenAccountEvent, TokenInfoEvent,
};
use crate::streaming::event_parser::protocols::block::block_meta_event::BlockMetaEvent;
use crate::streaming::event_parser::protocols::bonk::events::*;
use crate::streaming::event_parser::protocols::pumpfun::events::*;
use crate::streaming::event_parser::protocols::pumpswap::events::*;
use crate::streaming::event_parser::protocols::raydium_amm_v4::events::*;
use crate::streaming::event_parser::protocols::raydium_clmm::events::*;
use crate::streaming::event_parser::protocols::raydium_cpmm::events::*;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
/// Unified Event Interface - All protocol events must implement this trait
pub trait UnifiedEvent: Debug + Send + Sync {
/// Get event type
fn event_type(&self) -> EventType;
/// Unified Event Enum - Replaces the trait-based approach with a type-safe enum
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum UnifiedEvent {
// Bonk events
BonkTradeEvent(BonkTradeEvent),
BonkPoolCreateEvent(BonkPoolCreateEvent),
BonkMigrateToAmmEvent(BonkMigrateToAmmEvent),
BonkMigrateToCpswapEvent(BonkMigrateToCpswapEvent),
BonkPoolStateAccountEvent(BonkPoolStateAccountEvent),
BonkGlobalConfigAccountEvent(BonkGlobalConfigAccountEvent),
BonkPlatformConfigAccountEvent(BonkPlatformConfigAccountEvent),
/// Get transaction signature
fn signature(&self) -> &Signature;
// PumpFun events
PumpFunCreateTokenEvent(PumpFunCreateTokenEvent),
PumpFunTradeEvent(PumpFunTradeEvent),
PumpFunMigrateEvent(PumpFunMigrateEvent),
PumpFunBondingCurveAccountEvent(PumpFunBondingCurveAccountEvent),
PumpFunGlobalAccountEvent(PumpFunGlobalAccountEvent),
/// Get slot number
fn slot(&self) -> u64;
// PumpSwap events
PumpSwapBuyEvent(PumpSwapBuyEvent),
PumpSwapSellEvent(PumpSwapSellEvent),
PumpSwapCreatePoolEvent(PumpSwapCreatePoolEvent),
PumpSwapDepositEvent(PumpSwapDepositEvent),
PumpSwapWithdrawEvent(PumpSwapWithdrawEvent),
PumpSwapGlobalConfigAccountEvent(PumpSwapGlobalConfigAccountEvent),
PumpSwapPoolAccountEvent(PumpSwapPoolAccountEvent),
/// Get program received timestamp (milliseconds)
fn recv_us(&self) -> i64;
// Raydium AMM V4 events
RaydiumAmmV4SwapEvent(RaydiumAmmV4SwapEvent),
RaydiumAmmV4DepositEvent(RaydiumAmmV4DepositEvent),
RaydiumAmmV4WithdrawEvent(RaydiumAmmV4WithdrawEvent),
RaydiumAmmV4WithdrawPnlEvent(RaydiumAmmV4WithdrawPnlEvent),
RaydiumAmmV4Initialize2Event(RaydiumAmmV4Initialize2Event),
RaydiumAmmV4AmmInfoAccountEvent(RaydiumAmmV4AmmInfoAccountEvent),
/// Processing time consumption (milliseconds)
fn handle_us(&self) -> i64;
// Raydium CLMM events
RaydiumClmmSwapEvent(RaydiumClmmSwapEvent),
RaydiumClmmSwapV2Event(RaydiumClmmSwapV2Event),
RaydiumClmmClosePositionEvent(RaydiumClmmClosePositionEvent),
RaydiumClmmIncreaseLiquidityV2Event(RaydiumClmmIncreaseLiquidityV2Event),
RaydiumClmmDecreaseLiquidityV2Event(RaydiumClmmDecreaseLiquidityV2Event),
RaydiumClmmCreatePoolEvent(RaydiumClmmCreatePoolEvent),
RaydiumClmmOpenPositionWithToken22NftEvent(RaydiumClmmOpenPositionWithToken22NftEvent),
RaydiumClmmOpenPositionV2Event(RaydiumClmmOpenPositionV2Event),
RaydiumClmmAmmConfigAccountEvent(RaydiumClmmAmmConfigAccountEvent),
RaydiumClmmPoolStateAccountEvent(RaydiumClmmPoolStateAccountEvent),
RaydiumClmmTickArrayStateAccountEvent(RaydiumClmmTickArrayStateAccountEvent),
/// Set processing time consumption (milliseconds)
fn set_handle_us(&mut self, handle_us: i64);
// Raydium CPMM events
RaydiumCpmmSwapEvent(RaydiumCpmmSwapEvent),
RaydiumCpmmDepositEvent(RaydiumCpmmDepositEvent),
RaydiumCpmmWithdrawEvent(RaydiumCpmmWithdrawEvent),
RaydiumCpmmInitializeEvent(RaydiumCpmmInitializeEvent),
RaydiumCpmmAmmConfigAccountEvent(RaydiumCpmmAmmConfigAccountEvent),
RaydiumCpmmPoolStateAccountEvent(RaydiumCpmmPoolStateAccountEvent),
/// Convert event to Any for downcasting
fn as_any(&self) -> &dyn std::any::Any;
/// Convert event to mutable Any for downcasting
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
/// Clone the event
fn clone_boxed(&self) -> Box<dyn UnifiedEvent>;
/// Merge events (optional implementation)
fn merge(&mut self, _other: &dyn UnifiedEvent) {
// Default implementation: no merging operation
}
/// Set swap data
fn set_swap_data(&mut self, swap_data: SwapData);
/// swap_data is parsed
fn swap_data_is_parsed(&self) -> bool;
/// Get index
fn outer_index(&self) -> i64;
fn inner_index(&self) -> Option<i64>;
/// Get transaction index in slot
fn transaction_index(&self) -> Option<u64>;
// Common events
TokenAccountEvent(TokenAccountEvent),
NonceAccountEvent(NonceAccountEvent),
TokenInfoEvent(TokenInfoEvent),
BlockMetaEvent(BlockMetaEvent),
}
// 为Box<dyn UnifiedEvent>实现Clone
impl Clone for Box<dyn UnifiedEvent> {
fn clone(&self) -> Self {
self.clone_boxed()
impl UnifiedEvent {
pub fn metadata(&self) -> &EventMetadata {
match self {
UnifiedEvent::BonkTradeEvent(e) => &e.metadata,
UnifiedEvent::BonkPoolCreateEvent(e) => &e.metadata,
UnifiedEvent::BonkMigrateToAmmEvent(e) => &e.metadata,
UnifiedEvent::BonkMigrateToCpswapEvent(e) => &e.metadata,
UnifiedEvent::BonkPoolStateAccountEvent(e) => &e.metadata,
UnifiedEvent::BonkGlobalConfigAccountEvent(e) => &e.metadata,
UnifiedEvent::BonkPlatformConfigAccountEvent(e) => &e.metadata,
UnifiedEvent::PumpFunCreateTokenEvent(e) => &e.metadata,
UnifiedEvent::PumpFunTradeEvent(e) => &e.metadata,
UnifiedEvent::PumpFunMigrateEvent(e) => &e.metadata,
UnifiedEvent::PumpFunBondingCurveAccountEvent(e) => &e.metadata,
UnifiedEvent::PumpFunGlobalAccountEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapBuyEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapSellEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapCreatePoolEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapDepositEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapWithdrawEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapGlobalConfigAccountEvent(e) => &e.metadata,
UnifiedEvent::PumpSwapPoolAccountEvent(e) => &e.metadata,
UnifiedEvent::RaydiumAmmV4SwapEvent(e) => &e.metadata,
UnifiedEvent::RaydiumAmmV4DepositEvent(e) => &e.metadata,
UnifiedEvent::RaydiumAmmV4WithdrawEvent(e) => &e.metadata,
UnifiedEvent::RaydiumAmmV4WithdrawPnlEvent(e) => &e.metadata,
UnifiedEvent::RaydiumAmmV4Initialize2Event(e) => &e.metadata,
UnifiedEvent::RaydiumAmmV4AmmInfoAccountEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmSwapEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmSwapV2Event(e) => &e.metadata,
UnifiedEvent::RaydiumClmmClosePositionEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmIncreaseLiquidityV2Event(e) => &e.metadata,
UnifiedEvent::RaydiumClmmDecreaseLiquidityV2Event(e) => &e.metadata,
UnifiedEvent::RaydiumClmmCreatePoolEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmOpenPositionWithToken22NftEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmOpenPositionV2Event(e) => &e.metadata,
UnifiedEvent::RaydiumClmmAmmConfigAccountEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmPoolStateAccountEvent(e) => &e.metadata,
UnifiedEvent::RaydiumClmmTickArrayStateAccountEvent(e) => &e.metadata,
UnifiedEvent::RaydiumCpmmSwapEvent(e) => &e.metadata,
UnifiedEvent::RaydiumCpmmDepositEvent(e) => &e.metadata,
UnifiedEvent::RaydiumCpmmWithdrawEvent(e) => &e.metadata,
UnifiedEvent::RaydiumCpmmInitializeEvent(e) => &e.metadata,
UnifiedEvent::RaydiumCpmmAmmConfigAccountEvent(e) => &e.metadata,
UnifiedEvent::RaydiumCpmmPoolStateAccountEvent(e) => &e.metadata,
UnifiedEvent::TokenAccountEvent(e) => &e.metadata,
UnifiedEvent::NonceAccountEvent(e) => &e.metadata,
UnifiedEvent::TokenInfoEvent(e) => &e.metadata,
UnifiedEvent::BlockMetaEvent(e) => &e.metadata,
}
}
pub fn metadata_mut(&mut self) -> &mut EventMetadata {
match self {
UnifiedEvent::BonkTradeEvent(e) => &mut e.metadata,
UnifiedEvent::BonkPoolCreateEvent(e) => &mut e.metadata,
UnifiedEvent::BonkMigrateToAmmEvent(e) => &mut e.metadata,
UnifiedEvent::BonkMigrateToCpswapEvent(e) => &mut e.metadata,
UnifiedEvent::BonkPoolStateAccountEvent(e) => &mut e.metadata,
UnifiedEvent::BonkGlobalConfigAccountEvent(e) => &mut e.metadata,
UnifiedEvent::BonkPlatformConfigAccountEvent(e) => &mut e.metadata,
UnifiedEvent::PumpFunCreateTokenEvent(e) => &mut e.metadata,
UnifiedEvent::PumpFunTradeEvent(e) => &mut e.metadata,
UnifiedEvent::PumpFunMigrateEvent(e) => &mut e.metadata,
UnifiedEvent::PumpFunBondingCurveAccountEvent(e) => &mut e.metadata,
UnifiedEvent::PumpFunGlobalAccountEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapBuyEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapSellEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapCreatePoolEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapDepositEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapWithdrawEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapGlobalConfigAccountEvent(e) => &mut e.metadata,
UnifiedEvent::PumpSwapPoolAccountEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumAmmV4SwapEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumAmmV4DepositEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumAmmV4WithdrawEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumAmmV4WithdrawPnlEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumAmmV4Initialize2Event(e) => &mut e.metadata,
UnifiedEvent::RaydiumAmmV4AmmInfoAccountEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmSwapEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmSwapV2Event(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmClosePositionEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmIncreaseLiquidityV2Event(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmDecreaseLiquidityV2Event(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmCreatePoolEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmOpenPositionWithToken22NftEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmOpenPositionV2Event(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmAmmConfigAccountEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmPoolStateAccountEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumClmmTickArrayStateAccountEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumCpmmSwapEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumCpmmDepositEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumCpmmWithdrawEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumCpmmInitializeEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumCpmmAmmConfigAccountEvent(e) => &mut e.metadata,
UnifiedEvent::RaydiumCpmmPoolStateAccountEvent(e) => &mut e.metadata,
UnifiedEvent::TokenAccountEvent(e) => &mut e.metadata,
UnifiedEvent::NonceAccountEvent(e) => &mut e.metadata,
UnifiedEvent::TokenInfoEvent(e) => &mut e.metadata,
UnifiedEvent::BlockMetaEvent(e) => &mut e.metadata,
}
}
}