mirror of
https://github.com/0xfnzero/solana-streamer.git
synced 2026-08-16 02:18:05 +00:00
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:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user