diff --git a/Cargo.toml b/Cargo.toml index b205594..da322de 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "solana-streamer-sdk" -version = "1.5.4" +version = "1.5.5" edition = "2021" authors = ["William ", "sgxiang ", "wei <1415121722@qq.com>"] repository = "https://github.com/0xfnzero/solana-streamer" @@ -15,13 +15,13 @@ crate-type = ["cdylib", "rlib"] [features] default = ["sdk-parse-borsh"] sdk-parse-borsh = ["sol-parser-sdk/parse-borsh"] -# If both parser backend features are enabled, sol-parser-sdk 0.5.4+ uses zero-copy. +# If both parser backend features are enabled, sol-parser-sdk 0.5.5+ uses zero-copy. sdk-parse-zero-copy = ["sol-parser-sdk/parse-zero-copy"] sdk-perf-stats = ["sol-parser-sdk/perf-stats"] sdk-ultra-perf = ["sol-parser-sdk/ultra-perf"] [dependencies] -sol-parser-sdk = { version = "0.5.4", default-features = false } +sol-parser-sdk = { version = "0.5.5", default-features = false } solana-sdk = "3.0.0" solana-client = "3.1.12" solana-transaction-status = "3.1.12" diff --git a/README.md b/README.md index deaa834..bc9e453 100755 --- a/README.md +++ b/README.md @@ -77,13 +77,14 @@ - **PumpFun**: Meme coin trading platform events - **Pump Fees**: Pump fee-sharing configuration events - **PumpSwap**: PumpFun's swap protocol events -- **Raydium Launchpad / Bonk**: Token launch platform events (letsbonk.fun / LaunchLab) +- **Raydium LaunchLab**: Token launch platform events; `Protocol::Bonk` and `Protocol::RaydiumLaunchpad` remain compatible aliases - **Raydium CPMM**: Raydium's Concentrated Pool Market Maker events - **Raydium CLMM**: Raydium's Concentrated Liquidity Market Maker events - **Raydium AMM V4**: Raydium's Automated Market Maker V4 events - **Meteora DAMM v2**: Meteora DAMM v2 swap and liquidity events - **Orca Whirlpool**: Orca Whirlpool swap and liquidity events - **Meteora Pools**: Meteora Pools swap, liquidity, bootstrap, and fee events +- **Meteora DBC**: Meteora Dynamic Bonding Curve log-side swap, initialize-pool, and curve-complete events - **Meteora DLMM**: Meteora DLMM swap, liquidity, pool, bin-array, and fee events ### Advanced Features @@ -123,30 +124,34 @@ Add the dependency to your `Cargo.toml`: ```toml # Add to your Cargo.toml -solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.4" } +solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.5" } ``` ### Use crates.io ```toml # Add to your Cargo.toml -solana-streamer-sdk = "1.5.4" +solana-streamer-sdk = "1.5.5" ``` Parser backend features: ```toml # Default: sol-parser-sdk parse-borsh backend -solana-streamer-sdk = "1.5.4" +solana-streamer-sdk = "1.5.5" # Zero-copy parser backend for latency-sensitive bots -solana-streamer-sdk = { version = "1.5.4", default-features = false, features = ["sdk-parse-zero-copy"] } +solana-streamer-sdk = { version = "1.5.5", default-features = false, features = ["sdk-parse-zero-copy"] } ``` -If both `sdk-parse-borsh` and `sdk-parse-zero-copy` are enabled, `sol-parser-sdk 0.5.4+` uses the zero-copy backend. +If both `sdk-parse-borsh` and `sdk-parse-zero-copy` are enabled, `sol-parser-sdk 0.5.5+` uses the zero-copy backend. ## 🔄 Migration Guide +### Upgrading to v1.5.5 + +Version 1.5.5 uses `sol-parser-sdk 0.5.5` from crates.io. The SDK now exposes Raydium LaunchLab as `RaydiumLaunchlab*`; streamer keeps the existing `Bonk*` event structs and `Protocol::Bonk` / `Protocol::RaydiumLaunchpad` aliases for source compatibility, while routing parser calls and upstream gRPC event filters to the new LaunchLab SDK variants. This release also syncs the CLMM/CPMM/Orca account bridges, Meteora DAMM v2 initialize-pool events, Meteora DBC events, and parser warmup on client creation. + ### Upgrading to v1.5.4 Version 1.5.4 uses `sol-parser-sdk 0.5.4` from crates.io. Pump.fun `create` and `create_v2` are delivered as one canonical `PumpFunCreateTokenEvent`; subscribing to either `PumpFunCreateToken` or `PumpFunCreateV2Token` receives the same complete create-family data. This prevents duplicate new-mint callbacks from gRPC log + instruction parsing while preserving create_v2 account fields on the canonical create event. @@ -442,15 +447,16 @@ Note: Multiple subscription attempts on the same client return an error. - **PumpFun**: Primary meme coin trading platform - **Pump Fees**: Pump fee-sharing configuration events - **PumpSwap**: PumpFun's swap protocol -- **Raydium Launchpad / Bonk**: Token launch platform (letsbonk.fun / LaunchLab) +- **Raydium LaunchLab**: Token launch platform; `Bonk` and `RaydiumLaunchpad` are kept as compatibility aliases - **Raydium CPMM**: Raydium's Concentrated Pool Market Maker protocol - **Raydium CLMM**: Raydium's Concentrated Liquidity Market Maker protocol - **Raydium AMM V4**: Raydium's Automated Market Maker V4 protocol - **Meteora DAMM v2**: Meteora DAMM v2 protocol - **Orca Whirlpool**: Orca Whirlpool protocol - **Meteora Pools**: Meteora Pools protocol +- **Meteora DBC**: Meteora Dynamic Bonding Curve protocol - **Meteora DLMM**: Meteora Dynamic Liquidity Market Maker protocol -- **Common events**: Token accounts, token metadata, nonce accounts, block metadata, and ComputeBudget events +- **Common/account events**: Token accounts, token metadata, nonce accounts, block metadata, ComputeBudget events, and supported protocol account states such as Raydium CLMM/CPMM, Pump/PumpSwap, and Orca Whirlpool accounts ## 🌐 Event Streaming Services diff --git a/README_CN.md b/README_CN.md index c8531d8..78d9c67 100644 --- a/README_CN.md +++ b/README_CN.md @@ -76,13 +76,14 @@ - **PumpFun**: 迷因币交易平台事件 - **Pump Fees**: Pump 费用分成配置事件 - **PumpSwap**: PumpFun 的交换协议事件 -- **Raydium Launchpad / Bonk**: 代币发射平台事件 (letsbonk.fun / LaunchLab) +- **Raydium LaunchLab**: 代币发射平台事件;`Protocol::Bonk` 和 `Protocol::RaydiumLaunchpad` 仍作为兼容别名保留 - **Raydium CPMM**: Raydium 集中池做市商事件 - **Raydium CLMM**: Raydium 集中流动性做市商事件 - **Raydium AMM V4**: Raydium 自动做市商 V4 事件 - **Meteora DAMM v2**: Meteora DAMM v2 交易和流动性事件 - **Orca Whirlpool**: Orca Whirlpool 交易和流动性事件 - **Meteora Pools**: Meteora Pools 交易、流动性、启动流动性和费用事件 +- **Meteora DBC**: Meteora Dynamic Bonding Curve 的 log-side swap、initialize-pool 和 curve-complete 事件 - **Meteora DLMM**: Meteora DLMM 交易、流动性、池、bin array 和费用事件 ### 高级功能 @@ -122,30 +123,34 @@ git clone https://github.com/0xfnzero/solana-streamer ```toml # 添加到您的 Cargo.toml -solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.4" } +solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.5" } ``` ### 使用 crates.io ```toml # 添加到您的 Cargo.toml -solana-streamer-sdk = "1.5.4" +solana-streamer-sdk = "1.5.5" ``` 解析后端 feature: ```toml # 默认:sol-parser-sdk parse-borsh 后端 -solana-streamer-sdk = "1.5.4" +solana-streamer-sdk = "1.5.5" # 面向低延迟 Bot 的 zero-copy 解析后端 -solana-streamer-sdk = { version = "1.5.4", default-features = false, features = ["sdk-parse-zero-copy"] } +solana-streamer-sdk = { version = "1.5.5", default-features = false, features = ["sdk-parse-zero-copy"] } ``` -如果同时启用 `sdk-parse-borsh` 和 `sdk-parse-zero-copy`,`sol-parser-sdk 0.5.4+` 会优先使用 zero-copy 后端。 +如果同时启用 `sdk-parse-borsh` 和 `sdk-parse-zero-copy`,`sol-parser-sdk 0.5.5+` 会优先使用 zero-copy 后端。 ## 🔄 迁移指南 +### 升级到 v1.5.5 + +v1.5.5 使用 crates.io 上的 `sol-parser-sdk 0.5.5`。底层 SDK 已将 Raydium LaunchLab 事件统一暴露为 `RaydiumLaunchlab*`;streamer 仍保留现有 `Bonk*` 事件结构以及 `Protocol::Bonk` / `Protocol::RaydiumLaunchpad` 兼容别名,同时把解析调用和上游 gRPC 事件过滤映射到新的 LaunchLab SDK variant。该版本也同步了 CLMM/CPMM/Orca account bridge、Meteora DAMM v2 initialize-pool、Meteora DBC 事件,以及客户端创建时的 parser warmup。 + ### 升级到 v1.5.4 v1.5.4 使用 crates.io 上的 `sol-parser-sdk 0.5.4`。Pump.fun `create` 和 `create_v2` 会统一投递为 canonical `PumpFunCreateTokenEvent`;订阅 `PumpFunCreateToken` 或 `PumpFunCreateV2Token` 任意一个,都能收到同一份完整 create-family 数据。该版本避免 gRPC log + instruction 双路径解析导致新 mint 回调重复,同时在 canonical create 事件上保留 create_v2 账户字段。 @@ -441,15 +446,16 @@ grpc.update_subscription( - **PumpFun**: 主要迷因币交易平台 - **Pump Fees**: Pump 费用分成配置事件 - **PumpSwap**: PumpFun 的交换协议 -- **Raydium Launchpad / Bonk**: 代币发射平台 (letsbonk.fun / LaunchLab) +- **Raydium LaunchLab**: 代币发射平台;`Bonk` 和 `RaydiumLaunchpad` 作为兼容别名保留 - **Raydium CPMM**: Raydium 集中池做市商协议 - **Raydium CLMM**: Raydium 集中流动性做市商协议 - **Raydium AMM V4**: Raydium 自动做市商 V4 协议 - **Meteora DAMM v2**: Meteora DAMM v2 协议 - **Orca Whirlpool**: Orca Whirlpool 协议 - **Meteora Pools**: Meteora Pools 协议 +- **Meteora DBC**: Meteora Dynamic Bonding Curve 协议 - **Meteora DLMM**: Meteora 动态流动性做市商协议 -- **通用事件**: Token 账户、Token 元信息、Nonce 账户、区块元数据和 ComputeBudget 事件 +- **通用/账户事件**: Token 账户、Token 元信息、Nonce 账户、区块元数据、ComputeBudget 事件,以及 Raydium CLMM/CPMM、Pump/PumpSwap、Orca Whirlpool 等已支持协议账户状态 ## 🌐 事件流服务 diff --git a/examples/debug_pump_tx.rs b/examples/debug_pump_tx.rs index bfca9d4..b14cbce 100644 --- a/examples/debug_pump_tx.rs +++ b/examples/debug_pump_tx.rs @@ -125,7 +125,7 @@ async fn main() -> Result<()> { accounts.extend(address_table_lookups); let slot = transaction.slot; - let block_time = transaction.block_time.map(|t| Timestamp { seconds: t as i64, nanos: 0 }); + let block_time = transaction.block_time.map(|t| Timestamp { seconds: t, nanos: 0 }); let recv_us = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_micros() as i64; diff --git a/examples/debug_pumpswap_tx.rs b/examples/debug_pumpswap_tx.rs index 9116439..41f2bd4 100644 --- a/examples/debug_pumpswap_tx.rs +++ b/examples/debug_pumpswap_tx.rs @@ -104,7 +104,7 @@ async fn main() -> Result<()> { accounts.extend(address_table_lookups); let slot = transaction.slot; - let block_time = transaction.block_time.map(|t| Timestamp { seconds: t as i64, nanos: 0 }); + let block_time = transaction.block_time.map(|t| Timestamp { seconds: t, nanos: 0 }); let recv_us = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_micros() as i64; diff --git a/examples/grpc_example.rs b/examples/grpc_example.rs index db57d43..9135c67 100644 --- a/examples/grpc_example.rs +++ b/examples/grpc_example.rs @@ -31,9 +31,11 @@ async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration. - let mut config: ClientConfig = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( "https://solana-yellowstone-grpc.publicnode.com:443".to_string(), None, diff --git a/examples/mint_all_ata_account_listen_example.rs b/examples/mint_all_ata_account_listen_example.rs index 9c7ac74..88237a7 100644 --- a/examples/mint_all_ata_account_listen_example.rs +++ b/examples/mint_all_ata_account_listen_example.rs @@ -26,9 +26,11 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration. - let mut config: ClientConfig = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( "https://solana-yellowstone-grpc.publicnode.com:443".to_string(), None, @@ -103,10 +105,9 @@ async fn test_grpc() -> Result<(), Box> { } fn create_event_callback() -> impl Fn(DexEvent) { - |event: DexEvent| match event { - DexEvent::TokenAccountEvent(e) => { + |event: DexEvent| { + if let DexEvent::TokenAccountEvent(e) = event { println!("TokenAccount: {:?} amount: {:?}", e.pubkey, e.amount); } - _ => {} } } diff --git a/examples/nonce_listen_example.rs b/examples/nonce_listen_example.rs index 23b56d6..e2a9d75 100644 --- a/examples/nonce_listen_example.rs +++ b/examples/nonce_listen_example.rs @@ -18,9 +18,11 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration. - let mut config: ClientConfig = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( "https://solana-yellowstone-grpc.publicnode.com:443".to_string(), None, diff --git a/examples/parse_tx_events.rs b/examples/parse_tx_events.rs index 926a869..de77bc9 100644 --- a/examples/parse_tx_events.rs +++ b/examples/parse_tx_events.rs @@ -139,7 +139,7 @@ async fn parse_local_ix_path( accounts.extend(address_table_lookups); let slot = transaction.slot; - let block_time = transaction.block_time.map(|t| Timestamp { seconds: t as i64, nanos: 0 }); + let block_time = transaction.block_time.map(|t| Timestamp { seconds: t, nanos: 0 }); let bot_wallet = None; let tx_index = None; diff --git a/examples/pumpfun_quick_test.rs b/examples/pumpfun_quick_test.rs index 59cde14..222ef22 100644 --- a/examples/pumpfun_quick_test.rs +++ b/examples/pumpfun_quick_test.rs @@ -18,9 +18,11 @@ async fn main() -> Result<(), Box> { println!("🚀 Quick Test - Subscribing to PumpFun events..."); - let mut config = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( std::env::var("GRPC_ENDPOINT") diff --git a/examples/pumpfun_trade_filter.rs b/examples/pumpfun_trade_filter.rs index 42e7d98..81e126e 100644 --- a/examples/pumpfun_trade_filter.rs +++ b/examples/pumpfun_trade_filter.rs @@ -25,9 +25,11 @@ async fn main() -> Result<(), Box> { println!("🚀 PumpFun Trade Event Filter (solana-streamer)\n"); - let mut config = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( std::env::var("GRPC_ENDPOINT") diff --git a/examples/pumpfun_with_metrics.rs b/examples/pumpfun_with_metrics.rs index 6a3fc31..34572ad 100644 --- a/examples/pumpfun_with_metrics.rs +++ b/examples/pumpfun_with_metrics.rs @@ -15,8 +15,7 @@ async fn main() -> Result<(), Box> { println!("PumpFun with metrics (solana-streamer)\n"); - let mut config = ClientConfig::default(); - config.enable_metrics = true; + let config = ClientConfig { enable_metrics: true, ..Default::default() }; let grpc = YellowstoneGrpc::new_with_config( std::env::var("GRPC_ENDPOINT") diff --git a/examples/pumpswap_pool_account_listen_example.rs b/examples/pumpswap_pool_account_listen_example.rs index 2a3a0f3..bda3064 100644 --- a/examples/pumpswap_pool_account_listen_example.rs +++ b/examples/pumpswap_pool_account_listen_example.rs @@ -26,9 +26,11 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration. - let mut config: ClientConfig = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( "https://solana-yellowstone-grpc.publicnode.com:443".to_string(), None, @@ -105,10 +107,9 @@ async fn test_grpc() -> Result<(), Box> { } fn create_event_callback() -> impl Fn(DexEvent) { - |event: DexEvent| match event { - DexEvent::TokenAccountEvent(e) => { + |event: DexEvent| { + if let DexEvent::TokenAccountEvent(e) = event { println!("TokenAccount: {:?} amount: {:?}", e.pubkey, e.amount); } - _ => {} } } diff --git a/examples/pumpswap_with_metrics.rs b/examples/pumpswap_with_metrics.rs index 5920205..5f8c7cf 100644 --- a/examples/pumpswap_with_metrics.rs +++ b/examples/pumpswap_with_metrics.rs @@ -15,8 +15,7 @@ async fn main() -> Result<(), Box> { println!("PumpSwap with metrics (solana-streamer)\n"); - let mut config = ClientConfig::default(); - config.enable_metrics = true; + let config = ClientConfig { enable_metrics: true, ..Default::default() }; let grpc = YellowstoneGrpc::new_with_config( std::env::var("GRPC_ENDPOINT") diff --git a/examples/shred_example.rs b/examples/shred_example.rs index a1d4961..463219b 100644 --- a/examples/shred_example.rs +++ b/examples/shred_example.rs @@ -16,9 +16,11 @@ async fn test_shreds() -> Result<(), Box> { println!("Subscribing to ShredStream events..."); // Create low-latency configuration. - let mut config = StreamClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = StreamClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let shred_stream = ShredStreamGrpc::new_with_config("http://127.0.0.1:10800".to_string(), config).await?; @@ -57,11 +59,8 @@ fn create_event_callback() -> impl Fn(DexEvent) { event.metadata().event_type, event.metadata().tx_index ); - match event { - DexEvent::BlockMetaEvent(e) => { - println!("BlockMetaEvent: {:?}", e.metadata.handle_us); - } - _ => {} + if let DexEvent::BlockMetaEvent(e) = event { + println!("BlockMetaEvent: {:?}", e.metadata.handle_us); } } } diff --git a/examples/token_balance_listen_example.rs b/examples/token_balance_listen_example.rs index 764d3f1..896da27 100644 --- a/examples/token_balance_listen_example.rs +++ b/examples/token_balance_listen_example.rs @@ -18,9 +18,11 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration. - let mut config: ClientConfig = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( "https://solana-yellowstone-grpc.publicnode.com:443".to_string(), None, diff --git a/examples/token_decimals_listen_example.rs b/examples/token_decimals_listen_example.rs index f306013..0221200 100644 --- a/examples/token_decimals_listen_example.rs +++ b/examples/token_decimals_listen_example.rs @@ -18,9 +18,11 @@ async fn main() -> Result<(), Box> { async fn test_grpc() -> Result<(), Box> { println!("Subscribing to Yellowstone gRPC events..."); // Create low-latency configuration. - let mut config: ClientConfig = ClientConfig::default(); // Metrics add overhead; enable explicitly with STREAMER_ENABLE_METRICS=1. - config.enable_metrics = std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"); + let config = ClientConfig { + enable_metrics: std::env::var("STREAMER_ENABLE_METRICS").as_deref() == Ok("1"), + ..Default::default() + }; let grpc = YellowstoneGrpc::new_with_config( "https://solana-yellowstone-grpc.publicnode.com:443".to_string(), None, @@ -80,10 +82,9 @@ async fn test_grpc() -> Result<(), Box> { } fn create_event_callback() -> impl Fn(DexEvent) { - |event: DexEvent| match event { - DexEvent::TokenInfoEvent(e) => { + |event: DexEvent| { + if let DexEvent::TokenInfoEvent(e) = event { println!("TokenInfo pubkey={} decimals={} supply={}", e.pubkey, e.decimals, e.supply); } - _ => {} } } diff --git a/src/streaming/common/event_processor.rs b/src/streaming/common/event_processor.rs index 132a4d2..95d8226 100644 --- a/src/streaming/common/event_processor.rs +++ b/src/streaming/common/event_processor.rs @@ -69,8 +69,7 @@ pub fn parse_grpc_transaction_events( let recv_us = transaction_pretty.recv_us; let grpc_tx = transaction_pretty.grpc_tx; let block_time_us = block_time.map(|t| t.seconds * 1_000_000 + t.nanos as i64 / 1_000); - let update = - SubscribeUpdateTransaction { slot, transaction: Some(grpc_tx), ..Default::default() }; + let update = SubscribeUpdateTransaction { slot, transaction: Some(grpc_tx) }; let sdk_parse_filter = build_sdk_parse_event_filter(event_type_filter); let sdk_events = parse_subscribe_update_transaction_low_latency( &update, @@ -116,7 +115,7 @@ pub async fn process_grpc_transaction( AccountParseResult::Event(mut event) => { event.metadata_mut().handle_us = elapsed_micros_since(account_pretty.recv_us); let processing_time_us = event.metadata().handle_us as f64; - callback(event); + callback(*event); update_metrics(MetricsEventType::Account, 1, processing_time_us); return Ok(()); } diff --git a/src/streaming/common/metrics.rs b/src/streaming/common/metrics.rs index 86e9666..ffda0cb 100644 --- a/src/streaming/common/metrics.rs +++ b/src/streaming/common/metrics.rs @@ -194,6 +194,12 @@ impl PerformanceMetrics { } } +impl Default for PerformanceMetrics { + fn default() -> Self { + Self::new() + } +} + /// High-performance metrics system #[derive(Debug)] pub struct HighPerformanceMetrics { @@ -525,7 +531,7 @@ impl MetricsManager { let new_count = GLOBAL_METRICS.dropped_events_count.fetch_add(1, Ordering::Relaxed) + 1; // 每丢弃1000个事件记录一次警告日志 - if new_count % 1000 == 0 { + if new_count.is_multiple_of(1000) { log::debug!("Dropped events count reached: {}", new_count); } } @@ -547,7 +553,7 @@ impl MetricsManager { } // 每丢弃1000个事件记录一次警告日志 - if new_count % 1000 == 0 || (new_count / 1000) != ((new_count - count) / 1000) { + if new_count.is_multiple_of(1000) || (new_count / 1000) != ((new_count - count) / 1000) { log::debug!("Dropped events count reached: {}", new_count); } } diff --git a/src/streaming/event_parser/common/filter.rs b/src/streaming/event_parser/common/filter.rs index aae9768..8fa7fcf 100644 --- a/src/streaming/event_parser/common/filter.rs +++ b/src/streaming/event_parser/common/filter.rs @@ -136,17 +136,18 @@ pub(crate) fn build_sdk_shred_parse_event_filter( protocols: &[Protocol], filter: Option<&EventTypeFilter>, ) -> Option { - if protocols.is_empty() { - return build_sdk_parse_event_filter(filter); - } - if let Some(f) = filter.filter(|f| !f.include.is_empty()) { - if let Some(exact) = build_sdk_parse_event_filter(Some(f)) { - return Some(exact); - } if !f.include_transaction_event() { return Some(SdkGrpcEventTypeFilter::include_only(Vec::new())); } + if protocols.is_empty() { + return build_sdk_parse_event_filter(Some(f)); + } + if let Some(exact) = build_sdk_parse_event_filter(Some(f)) { + return Some(exact); + } + } else if protocols.is_empty() { + return build_sdk_parse_event_filter(filter); } let mut raw = Vec::with_capacity(protocols.len() * 8); @@ -229,12 +230,12 @@ fn push_streamer_event_sdk_grpc_types( St::PumpSwapDeposit => out.push(Sdk::PumpSwapLiquidityAdded), St::PumpSwapWithdraw => out.push(Sdk::PumpSwapLiquidityRemoved), St::BonkBuyExactIn | St::BonkBuyExactOut | St::BonkSellExactIn | St::BonkSellExactOut => { - out.push(Sdk::BonkTrade) + out.push(Sdk::RaydiumLaunchlabTrade) } St::BonkInitialize | St::BonkInitializeV2 | St::BonkInitializeWithToken2022 => { - out.push(Sdk::BonkPoolCreate) + out.push(Sdk::RaydiumLaunchlabPoolCreate) } - St::BonkMigrateToAmm => out.push(Sdk::BonkMigrateAmm), + St::BonkMigrateToAmm => out.push(Sdk::RaydiumLaunchlabMigrateAmm), St::RaydiumCpmmSwapBaseInput | St::RaydiumCpmmSwapBaseOutput => { out.push(Sdk::RaydiumCpmmSwap) } @@ -278,8 +279,12 @@ fn push_streamer_event_sdk_grpc_types( St::MeteoraDammV2Swap | St::MeteoraDammV2Swap2 => out.push(Sdk::MeteoraDammV2Swap), St::MeteoraDammV2AddLiquidity => out.push(Sdk::MeteoraDammV2AddLiquidity), St::MeteoraDammV2RemoveLiquidity => out.push(Sdk::MeteoraDammV2RemoveLiquidity), + St::MeteoraDammV2InitializePool => out.push(Sdk::MeteoraDammV2InitializePool), St::MeteoraDammV2CreatePosition => out.push(Sdk::MeteoraDammV2CreatePosition), St::MeteoraDammV2ClosePosition => out.push(Sdk::MeteoraDammV2ClosePosition), + St::MeteoraDbcSwap => out.push(Sdk::MeteoraDbcSwap), + St::MeteoraDbcInitializePool => out.push(Sdk::MeteoraDbcInitializePool), + St::MeteoraDbcCurveComplete => out.push(Sdk::MeteoraDbcCurveComplete), St::MeteoraDlmmSwap => out.push(Sdk::MeteoraDlmmSwap), St::MeteoraDlmmAddLiquidity => out.push(Sdk::MeteoraDlmmAddLiquidity), St::MeteoraDlmmRemoveLiquidity => out.push(Sdk::MeteoraDlmmRemoveLiquidity), @@ -302,6 +307,16 @@ fn push_streamer_event_sdk_grpc_types( } St::AccountPumpSwapGlobalConfig => out.push(Sdk::AccountPumpSwapGlobalConfig), St::AccountPumpSwapPool => out.push(Sdk::AccountPumpSwapPool), + St::AccountRaydiumClmmAmmConfig => out.push(Sdk::AccountRaydiumClmmAmmConfig), + St::AccountRaydiumClmmPoolState => out.push(Sdk::AccountRaydiumClmmPoolState), + St::AccountRaydiumClmmTickArrayState => out.push(Sdk::AccountRaydiumClmmTickArrayState), + St::AccountRaydiumCpmmAmmConfig => out.push(Sdk::AccountRaydiumCpmmAmmConfig), + St::AccountRaydiumCpmmPoolState => out.push(Sdk::AccountRaydiumCpmmPoolState), + St::AccountOrcaWhirlpool => out.push(Sdk::AccountOrcaWhirlpool), + St::AccountOrcaPosition => out.push(Sdk::AccountOrcaPosition), + St::AccountOrcaTickArray => out.push(Sdk::AccountOrcaTickArray), + St::AccountOrcaFeeTier => out.push(Sdk::AccountOrcaFeeTier), + St::AccountOrcaWhirlpoolsConfig => out.push(Sdk::AccountOrcaWhirlpoolsConfig), _ => return false, } true @@ -351,9 +366,11 @@ fn push_protocol_sdk_grpc_event_types(protocol: &Protocol, out: &mut Vec { - out.extend_from_slice(&[Sdk::BonkTrade, Sdk::BonkPoolCreate, Sdk::BonkMigrateAmm]) - } + StProtocol::Bonk | StProtocol::RaydiumLaunchpad => out.extend_from_slice(&[ + Sdk::RaydiumLaunchlabTrade, + Sdk::RaydiumLaunchlabPoolCreate, + Sdk::RaydiumLaunchlabMigrateAmm, + ]), StProtocol::RaydiumCpmm => out.extend_from_slice(&[ Sdk::RaydiumCpmmSwap, Sdk::RaydiumCpmmDeposit, @@ -390,9 +407,15 @@ fn push_protocol_sdk_grpc_event_types(protocol: &Protocol, out: &mut Vec out.extend_from_slice(&[ + Sdk::MeteoraDbcSwap, + Sdk::MeteoraDbcInitializePool, + Sdk::MeteoraDbcCurveComplete, + ]), StProtocol::OrcaWhirlpool => out.extend_from_slice(&[ Sdk::OrcaWhirlpoolSwap, Sdk::OrcaWhirlpoolLiquidityIncreased, @@ -499,11 +522,7 @@ mod tests { #[test] fn exclude_blocks_even_when_include_empty() { - let f = EventTypeFilter { - include: vec![], - exclude: vec![EventType::PumpFunSell], - ..Default::default() - }; + let f = EventTypeFilter { include: vec![], exclude: vec![EventType::PumpFunSell] }; let ev = DexEvent::ParserSdkErrorEvent(ParserSdkErrorEvent { metadata: mk_meta(EventType::PumpFunSell), message: "x".into(), @@ -528,7 +547,6 @@ mod tests { let f = EventTypeFilter { include: vec![EventType::PumpFunBuy, EventType::PumpFunSell], exclude: vec![EventType::PumpFunSell], - ..Default::default() }; let buy = DexEvent::ParserSdkErrorEvent(ParserSdkErrorEvent { metadata: mk_meta(EventType::PumpFunBuy), @@ -544,11 +562,7 @@ mod tests { #[test] fn build_sdk_filter_exclude_only_pumpfun_sell() { - let f = EventTypeFilter { - include: vec![], - exclude: vec![EventType::PumpFunSell], - ..Default::default() - }; + let f = EventTypeFilter { include: vec![], exclude: vec![EventType::PumpFunSell] }; let sdk_f = build_sdk_parse_event_filter(Some(&f)).expect("mapped"); assert!(sdk_f.should_include(SdkGrpcEventType::PumpFunBuy)); assert!(!sdk_f.should_include(SdkGrpcEventType::PumpFunSell)); @@ -725,8 +739,12 @@ mod tests { EventType::MeteoraDammV2Swap2, EventType::MeteoraDammV2AddLiquidity, EventType::MeteoraDammV2RemoveLiquidity, + EventType::MeteoraDammV2InitializePool, EventType::MeteoraDammV2CreatePosition, EventType::MeteoraDammV2ClosePosition, + EventType::MeteoraDbcSwap, + EventType::MeteoraDbcInitializePool, + EventType::MeteoraDbcCurveComplete, EventType::MeteoraDlmmSwap, EventType::MeteoraDlmmAddLiquidity, EventType::MeteoraDlmmRemoveLiquidity, @@ -746,6 +764,16 @@ mod tests { EventType::AccountPumpFunUserVolumeAccumulator, EventType::AccountPumpSwapGlobalConfig, EventType::AccountPumpSwapPool, + EventType::AccountRaydiumClmmAmmConfig, + EventType::AccountRaydiumClmmPoolState, + EventType::AccountRaydiumClmmTickArrayState, + EventType::AccountRaydiumCpmmAmmConfig, + EventType::AccountRaydiumCpmmPoolState, + EventType::AccountOrcaWhirlpool, + EventType::AccountOrcaPosition, + EventType::AccountOrcaTickArray, + EventType::AccountOrcaFeeTier, + EventType::AccountOrcaWhirlpoolsConfig, ]; for event_type in sdk_filter_backed { @@ -760,7 +788,10 @@ mod tests { #[test] fn build_sdk_filter_none_when_public_sdk_filter_enum_cannot_express_requested_type() { let f = EventTypeFilter { - include: vec![EventType::PumpFunBuy, EventType::MeteoraDammV2InitializePool], + include: vec![ + EventType::PumpFunBuy, + EventType::MeteoraDammV2InitializeCustomizablePool, + ], ..Default::default() }; assert!(build_sdk_parse_event_filter(Some(&f)).is_none()); @@ -769,7 +800,7 @@ mod tests { #[test] fn build_sdk_shred_filter_falls_back_to_protocol_group_for_sdk_enum_gap() { let f = EventTypeFilter { - include: vec![EventType::MeteoraDammV2InitializePool], + include: vec![EventType::MeteoraDammV2InitializeCustomizablePool], ..Default::default() }; let sdk_f = @@ -792,12 +823,20 @@ mod tests { } #[test] - fn build_sdk_filter_exclude_only_orca_maps_upstream() { + fn build_sdk_shred_filter_skips_transaction_parse_for_account_only_without_protocols() { let f = EventTypeFilter { - include: vec![], - exclude: vec![EventType::OrcaWhirlpoolSwap], + include: vec![EventType::AccountRaydiumClmmPoolState], ..Default::default() }; + let sdk_f = build_sdk_shred_parse_event_filter(&[], Some(&f)).unwrap(); + + assert!(!sdk_f.should_include(SdkGrpcEventType::RaydiumClmmSwap)); + assert!(!sdk_f.should_include(SdkGrpcEventType::PumpFunBuy)); + } + + #[test] + fn build_sdk_filter_exclude_only_orca_maps_upstream() { + let f = EventTypeFilter { include: vec![], exclude: vec![EventType::OrcaWhirlpoolSwap] }; let sdk_f = build_sdk_parse_event_filter(Some(&f)).expect("mapped"); assert!(!sdk_f.should_include(SdkGrpcEventType::OrcaWhirlpoolSwap)); assert!(sdk_f.should_include(SdkGrpcEventType::PumpFunBuy)); @@ -807,19 +846,14 @@ mod tests { fn build_sdk_filter_exclude_only_none_when_only_sdk_filter_enum_gap() { let f = EventTypeFilter { include: vec![], - exclude: vec![EventType::MeteoraDammV2InitializePool], - ..Default::default() + exclude: vec![EventType::MeteoraDammV2InitializeCustomizablePool], }; assert!(build_sdk_parse_event_filter(Some(&f)).is_none()); } #[test] fn build_sdk_filter_exclude_only_none_when_only_unmapped_types() { - let f = EventTypeFilter { - include: vec![], - exclude: vec![EventType::SetComputeUnitLimit], - ..Default::default() - }; + let f = EventTypeFilter { include: vec![], exclude: vec![EventType::SetComputeUnitLimit] }; assert!(build_sdk_parse_event_filter(Some(&f)).is_none()); } } diff --git a/src/streaming/event_parser/common/types.rs b/src/streaming/event_parser/common/types.rs index 89795f0..d6cc79e 100755 --- a/src/streaming/event_parser/common/types.rs +++ b/src/streaming/event_parser/common/types.rs @@ -49,6 +49,7 @@ pub enum ProtocolType { RaydiumClmm, RaydiumAmmV4, MeteoraDammV2, + MeteoraDbc, OrcaWhirlpool, MeteoraPools, MeteoraDlmm, @@ -153,6 +154,11 @@ pub enum EventType { MeteoraDammV2AddLiquidity, MeteoraDammV2RemoveLiquidity, + // Meteora DBC + MeteoraDbcSwap, + MeteoraDbcInitializePool, + MeteoraDbcCurveComplete, + // Orca Whirlpool OrcaWhirlpoolSwap, OrcaWhirlpoolLiquidityIncreased, @@ -196,6 +202,11 @@ pub enum EventType { AccountRaydiumClmmTickArrayState, AccountRaydiumCpmmAmmConfig, AccountRaydiumCpmmPoolState, + AccountOrcaWhirlpool, + AccountOrcaPosition, + AccountOrcaTickArray, + AccountOrcaFeeTier, + AccountOrcaWhirlpoolsConfig, NonceAccount, TokenAccount, @@ -228,6 +239,11 @@ pub const ACCOUNT_EVENT_TYPES: &[EventType] = &[ EventType::AccountRaydiumClmmTickArrayState, EventType::AccountRaydiumCpmmAmmConfig, EventType::AccountRaydiumCpmmPoolState, + EventType::AccountOrcaWhirlpool, + EventType::AccountOrcaPosition, + EventType::AccountOrcaTickArray, + EventType::AccountOrcaFeeTier, + EventType::AccountOrcaWhirlpoolsConfig, EventType::TokenAccount, EventType::TokenInfo, EventType::NonceAccount, diff --git a/src/streaming/event_parser/core/dispatcher.rs b/src/streaming/event_parser/core/dispatcher.rs index 295080f..459037a 100644 --- a/src/streaming/event_parser/core/dispatcher.rs +++ b/src/streaming/event_parser/core/dispatcher.rs @@ -70,7 +70,7 @@ impl EventDispatcher { } Protocol::PumpFees => all_inner::pump_fees::parse(&disc, inner_instruction_data, pm), Protocol::Bonk | Protocol::RaydiumLaunchpad => { - all_inner::bonk::parse(&disc, inner_instruction_data, pm) + all_inner::raydium_launchlab::parse(&disc, inner_instruction_data, pm) } Protocol::RaydiumCpmm => { all_inner::raydium_cpmm::parse(&disc, inner_instruction_data, pm) @@ -86,6 +86,8 @@ impl EventDispatcher { Protocol::MeteoraDammV2 => { all_inner::meteora_damm::parse(&disc, inner_instruction_data, pm) } + // Meteora DBC is currently log-side in sol-parser-sdk; direct inner dispatch is absent. + Protocol::MeteoraDbc => None, Protocol::OrcaWhirlpool => all_inner::orca::parse(&disc, inner_instruction_data, pm), Protocol::MeteoraPools => { all_inner::meteora_amm::parse(&disc, inner_instruction_data, pm) @@ -108,7 +110,7 @@ impl EventDispatcher { Some(Protocol::PumpFees) } else if program_id == &program_ids::PUMPSWAP_PROGRAM_ID { Some(Protocol::PumpSwap) - } else if program_id == &program_ids::BONK_PROGRAM_ID { + } else if program_id == &program_ids::RAYDIUM_LAUNCHLAB_PROGRAM_ID { Some(Protocol::Bonk) } else if program_id == &program_ids::RAYDIUM_CPMM_PROGRAM_ID { Some(Protocol::RaydiumCpmm) @@ -118,6 +120,8 @@ impl EventDispatcher { Some(Protocol::RaydiumAmmV4) } else if program_id == &program_ids::METEORA_DAMM_V2_PROGRAM_ID { Some(Protocol::MeteoraDammV2) + } else if program_id == &program_ids::METEORA_DBC_PROGRAM_ID { + Some(Protocol::MeteoraDbc) } else if program_id == &program_ids::ORCA_WHIRLPOOL_PROGRAM_ID { Some(Protocol::OrcaWhirlpool) } else if program_id == &program_ids::METEORA_POOLS_PROGRAM_ID { @@ -148,11 +152,14 @@ impl EventDispatcher { Protocol::PumpFun => program_ids::PUMPFUN_PROGRAM_ID, Protocol::PumpFees => program_ids::PUMP_FEES_PROGRAM_ID, Protocol::PumpSwap => program_ids::PUMPSWAP_PROGRAM_ID, - Protocol::Bonk | Protocol::RaydiumLaunchpad => program_ids::BONK_PROGRAM_ID, + Protocol::Bonk | Protocol::RaydiumLaunchpad => { + program_ids::RAYDIUM_LAUNCHLAB_PROGRAM_ID + } Protocol::RaydiumCpmm => program_ids::RAYDIUM_CPMM_PROGRAM_ID, Protocol::RaydiumClmm => program_ids::RAYDIUM_CLMM_PROGRAM_ID, Protocol::RaydiumAmmV4 => program_ids::RAYDIUM_AMM_V4_PROGRAM_ID, Protocol::MeteoraDammV2 => program_ids::METEORA_DAMM_V2_PROGRAM_ID, + Protocol::MeteoraDbc => program_ids::METEORA_DBC_PROGRAM_ID, Protocol::OrcaWhirlpool => program_ids::ORCA_WHIRLPOOL_PROGRAM_ID, Protocol::MeteoraPools => program_ids::METEORA_POOLS_PROGRAM_ID, Protocol::MeteoraDlmm => program_ids::METEORA_DLMM_PROGRAM_ID, diff --git a/src/streaming/event_parser/core/event_parser/mod.rs b/src/streaming/event_parser/core/event_parser/mod.rs index c00f8e9..022132e 100644 --- a/src/streaming/event_parser/core/event_parser/mod.rs +++ b/src/streaming/event_parser/core/event_parser/mod.rs @@ -9,6 +9,7 @@ pub(crate) mod helpers; pub struct EventParser; impl EventParser { + #[allow(clippy::too_many_arguments)] pub async fn parse_grpc_transaction( protocols: &[crate::streaming::event_parser::Protocol], event_type_filter: Option<&crate::streaming::event_parser::common::filter::EventTypeFilter>, @@ -32,7 +33,6 @@ impl EventParser { let update = yellowstone_grpc_proto::geyser::SubscribeUpdateTransaction { slot: slot.unwrap_or(0), transaction: Some(grpc_tx), - ..Default::default() }; let sdk_parse_filter = crate::streaming::event_parser::common::filter::build_sdk_parse_event_filter( diff --git a/src/streaming/event_parser/core/merger_event.rs b/src/streaming/event_parser/core/merger_event.rs index 54447e3..c7b5644 100644 --- a/src/streaming/event_parser/core/merger_event.rs +++ b/src/streaming/event_parser/core/merger_event.rs @@ -1,3 +1,5 @@ +#![allow(clippy::single_match)] + use crate::streaming::event_parser::DexEvent; use solana_sdk::{pubkey, pubkey::Pubkey}; diff --git a/src/streaming/event_parser/core/traits.rs b/src/streaming/event_parser/core/traits.rs index c5c8107..f0749e4 100755 --- a/src/streaming/event_parser/core/traits.rs +++ b/src/streaming/event_parser/core/traits.rs @@ -14,14 +14,16 @@ 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 crate::streaming::event_parser::protocols::sol_parser_forward::events::{ + MeteoraDbcCurveCompleteEvent, MeteoraDbcInitializePoolEvent, MeteoraDbcSwapEvent, MeteoraDlmmAddLiquidityEvent, MeteoraDlmmClaimFeeEvent, MeteoraDlmmClosePositionEvent, MeteoraDlmmCreatePositionEvent, MeteoraDlmmInitializeBinArrayEvent, MeteoraDlmmInitializePoolEvent, MeteoraDlmmRemoveLiquidityEvent, MeteoraDlmmSwapEvent, MeteoraPoolsAddLiquidityEvent, MeteoraPoolsBootstrapLiquidityEvent, MeteoraPoolsPoolCreatedEvent, MeteoraPoolsRemoveLiquidityEvent, MeteoraPoolsSetPoolFeesEvent, - MeteoraPoolsSwapEvent, OrcaWhirlpoolLiquidityDecreasedEvent, + MeteoraPoolsSwapEvent, OrcaFeeTierAccountEvent, OrcaPositionAccountEvent, + OrcaTickArrayAccountEvent, OrcaWhirlpoolAccountEvent, OrcaWhirlpoolLiquidityDecreasedEvent, OrcaWhirlpoolLiquidityIncreasedEvent, OrcaWhirlpoolPoolInitializedEvent, - OrcaWhirlpoolSwapEvent, ParserSdkErrorEvent, + OrcaWhirlpoolSwapEvent, OrcaWhirlpoolsConfigAccountEvent, ParserSdkErrorEvent, }; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -96,17 +98,17 @@ pub enum DexEvent { RaydiumClmmCreatePoolEvent(RaydiumClmmCreatePoolEvent), RaydiumClmmOpenPositionWithToken22NftEvent(RaydiumClmmOpenPositionWithToken22NftEvent), RaydiumClmmOpenPositionV2Event(RaydiumClmmOpenPositionV2Event), - RaydiumClmmAmmConfigAccountEvent(RaydiumClmmAmmConfigAccountEvent), - RaydiumClmmPoolStateAccountEvent(RaydiumClmmPoolStateAccountEvent), - RaydiumClmmTickArrayStateAccountEvent(RaydiumClmmTickArrayStateAccountEvent), + RaydiumClmmAmmConfigAccountEvent(Box), + RaydiumClmmPoolStateAccountEvent(Box), + RaydiumClmmTickArrayStateAccountEvent(Box), // Raydium CPMM events RaydiumCpmmSwapEvent(RaydiumCpmmSwapEvent), RaydiumCpmmDepositEvent(RaydiumCpmmDepositEvent), RaydiumCpmmWithdrawEvent(RaydiumCpmmWithdrawEvent), RaydiumCpmmInitializeEvent(RaydiumCpmmInitializeEvent), - RaydiumCpmmAmmConfigAccountEvent(RaydiumCpmmAmmConfigAccountEvent), - RaydiumCpmmPoolStateAccountEvent(RaydiumCpmmPoolStateAccountEvent), + RaydiumCpmmAmmConfigAccountEvent(Box), + RaydiumCpmmPoolStateAccountEvent(Box), // Meteora DAMM v2 events MeteoraDammV2SwapEvent(MeteoraDammV2SwapEvent), @@ -122,10 +124,19 @@ pub enum DexEvent { MeteoraDammV2CreatePositionEvent(MeteoraDammV2CreatePositionEvent), MeteoraDammV2ClosePositionEvent(MeteoraDammV2ClosePositionEvent), + MeteoraDbcSwapEvent(MeteoraDbcSwapEvent), + MeteoraDbcInitializePoolEvent(MeteoraDbcInitializePoolEvent), + MeteoraDbcCurveCompleteEvent(MeteoraDbcCurveCompleteEvent), + OrcaWhirlpoolSwapEvent(OrcaWhirlpoolSwapEvent), OrcaWhirlpoolLiquidityIncreasedEvent(OrcaWhirlpoolLiquidityIncreasedEvent), OrcaWhirlpoolLiquidityDecreasedEvent(OrcaWhirlpoolLiquidityDecreasedEvent), OrcaWhirlpoolPoolInitializedEvent(OrcaWhirlpoolPoolInitializedEvent), + OrcaWhirlpoolAccountEvent(Box), + OrcaPositionAccountEvent(Box), + OrcaTickArrayAccountEvent(Box), + OrcaFeeTierAccountEvent(Box), + OrcaWhirlpoolsConfigAccountEvent(Box), MeteoraPoolsSwapEvent(MeteoraPoolsSwapEvent), MeteoraPoolsAddLiquidityEvent(MeteoraPoolsAddLiquidityEvent), @@ -256,10 +267,18 @@ impl_dex_event_metadata!( MeteoraDammV2RemoveLiquidityEvent, MeteoraDammV2CreatePositionEvent, MeteoraDammV2ClosePositionEvent, + MeteoraDbcSwapEvent, + MeteoraDbcInitializePoolEvent, + MeteoraDbcCurveCompleteEvent, OrcaWhirlpoolSwapEvent, OrcaWhirlpoolLiquidityIncreasedEvent, OrcaWhirlpoolLiquidityDecreasedEvent, OrcaWhirlpoolPoolInitializedEvent, + OrcaWhirlpoolAccountEvent, + OrcaPositionAccountEvent, + OrcaTickArrayAccountEvent, + OrcaFeeTierAccountEvent, + OrcaWhirlpoolsConfigAccountEvent, MeteoraPoolsSwapEvent, MeteoraPoolsAddLiquidityEvent, MeteoraPoolsRemoveLiquidityEvent, diff --git a/src/streaming/event_parser/protocols/bonk/parser.rs b/src/streaming/event_parser/protocols/bonk/parser.rs index f98a6cd..9e9fd0c 100644 --- a/src/streaming/event_parser/protocols/bonk/parser.rs +++ b/src/streaming/event_parser/protocols/bonk/parser.rs @@ -3,7 +3,7 @@ use crate::streaming::event_parser::{ }; use solana_sdk::pubkey::Pubkey; -pub use sol_parser_sdk::instr::program_ids::BONK_PROGRAM_ID; +pub use sol_parser_sdk::instr::program_ids::RAYDIUM_LAUNCHLAB_PROGRAM_ID as BONK_PROGRAM_ID; pub fn parse_bonk_instruction_data( discriminator: &[u8], diff --git a/src/streaming/event_parser/protocols/bonk/types.rs b/src/streaming/event_parser/protocols/bonk/types.rs index 5b5b4b4..9f9beb4 100755 --- a/src/streaming/event_parser/protocols/bonk/types.rs +++ b/src/streaming/event_parser/protocols/bonk/types.rs @@ -32,32 +32,22 @@ pub struct VestingParams { pub unlock_period: u64, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] pub enum AmmFeeOn { + #[default] QuoteToken, BothToken, } -impl Default for AmmFeeOn { - fn default() -> Self { - Self::QuoteToken - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] #[borsh(use_discriminant = true)] #[repr(u8)] pub enum AmmCreatorFeeOn { + #[default] QuoteToken = 0, BothToken = 1, } -impl Default for AmmCreatorFeeOn { - fn default() -> Self { - Self::QuoteToken - } -} - #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] pub struct ConstantCurve { pub supply: u64, @@ -170,7 +160,7 @@ impl Default for PoolState { } } -pub const POOL_STATE_SIZE: usize = 8 + 1 * 5 + 8 * 10 + 32 * 7 + 8 * 8 + 8 * 5 + 1 + 1 + 8 + 54; +pub const POOL_STATE_SIZE: usize = 8 + 5 + 8 * 10 + 32 * 7 + 8 * 8 + 8 * 5 + 1 + 1 + 8 + 54; #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] pub struct GlobalConfig { pub epoch: u64, diff --git a/src/streaming/event_parser/protocols/raydium_amm_v4/events.rs b/src/streaming/event_parser/protocols/raydium_amm_v4/events.rs index fac8f40..f715fdf 100755 --- a/src/streaming/event_parser/protocols/raydium_amm_v4/events.rs +++ b/src/streaming/event_parser/protocols/raydium_amm_v4/events.rs @@ -168,10 +168,10 @@ pub mod discriminators { // 指令鉴别器 pub const SWAP_BASE_IN: &[u8] = &[9]; pub const SWAP_BASE_OUT: &[u8] = &[11]; - pub const DEPOSIT: &[u8] = &[03]; - pub const INITIALIZE2: &[u8] = &[01]; - pub const WITHDRAW: &[u8] = &[04]; - pub const WITHDRAW_PNL: &[u8] = &[07]; + pub const DEPOSIT: &[u8] = &[3]; + pub const INITIALIZE2: &[u8] = &[1]; + pub const WITHDRAW: &[u8] = &[4]; + pub const WITHDRAW_PNL: &[u8] = &[7]; /// 池信息鉴别器 pub const AMM_INFO: &[u8] = &[6]; diff --git a/src/streaming/event_parser/protocols/raydium_clmm/types.rs b/src/streaming/event_parser/protocols/raydium_clmm/types.rs index cde893f..000f48d 100644 --- a/src/streaming/event_parser/protocols/raydium_clmm/types.rs +++ b/src/streaming/event_parser/protocols/raydium_clmm/types.rs @@ -105,7 +105,7 @@ pub struct PoolState { pub const POOL_STATE_SIZE: usize = 1536; -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] pub struct TickState { pub tick: i32, pub liquidity_net: i128, @@ -120,24 +120,6 @@ pub struct TickState { pub padding: [u32; 3], } -impl Default for TickState { - fn default() -> Self { - Self { - tick: 0, - liquidity_net: 0, - liquidity_gross: 0, - fee_growth_outside0_x64: 0, - fee_growth_outside1_x64: 0, - reward_growths_outside_x64: [0; 3], - order_phase: 0, - orders_amount: 0, - part_filled_orders_remaining: 0, - unfilled_ratio_x64: 0, - padding: [0; 3], - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)] pub struct TickArrayState { pub pool_id: Pubkey, diff --git a/src/streaming/event_parser/protocols/sol_parser_forward/events.rs b/src/streaming/event_parser/protocols/sol_parser_forward/events.rs index 0d09171..6817e25 100644 --- a/src/streaming/event_parser/protocols/sol_parser_forward/events.rs +++ b/src/streaming/event_parser/protocols/sol_parser_forward/events.rs @@ -69,6 +69,185 @@ pub struct OrcaWhirlpoolPoolInitializedEvent { pub initial_sqrt_price: u128, } +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaWhirlpoolAccountEvent { + pub metadata: EventMetadata, + pub pubkey: Pubkey, + pub executable: bool, + pub lamports: u64, + pub owner: Pubkey, + pub rent_epoch: u64, + pub whirlpool: OrcaWhirlpoolAccount, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaWhirlpoolAccount { + pub whirlpools_config: Pubkey, + pub whirlpool_bump: u8, + pub tick_spacing: u16, + pub tick_spacing_seed: [u8; 2], + pub fee_rate: u16, + pub protocol_fee_rate: u16, + pub liquidity: u128, + pub sqrt_price: u128, + pub tick_current_index: i32, + pub protocol_fee_owed_a: u64, + pub protocol_fee_owed_b: u64, + pub token_mint_a: Pubkey, + pub token_vault_a: Pubkey, + pub fee_growth_global_a: u128, + pub token_mint_b: Pubkey, + pub token_vault_b: Pubkey, + pub fee_growth_global_b: u128, + pub reward_last_updated_timestamp: u64, + pub reward_infos: [OrcaWhirlpoolRewardInfo; 3], +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaWhirlpoolRewardInfo { + pub mint: Pubkey, + pub vault: Pubkey, + pub authority: Pubkey, + pub emissions_per_second_x64: u128, + pub growth_global_x64: u128, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaPositionAccountEvent { + pub metadata: EventMetadata, + pub pubkey: Pubkey, + pub executable: bool, + pub lamports: u64, + pub owner: Pubkey, + pub rent_epoch: u64, + pub position: OrcaPositionAccount, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaPositionAccount { + pub whirlpool: Pubkey, + pub position_mint: Pubkey, + pub liquidity: u128, + pub tick_lower_index: i32, + pub tick_upper_index: i32, + pub fee_growth_checkpoint_a: u128, + pub fee_owed_a: u64, + pub fee_growth_checkpoint_b: u128, + pub fee_owed_b: u64, + pub reward_infos: [OrcaPositionRewardInfo; 3], +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaPositionRewardInfo { + pub growth_inside_checkpoint: u128, + pub amount_owed: u64, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaTickArrayAccountEvent { + pub metadata: EventMetadata, + pub pubkey: Pubkey, + pub executable: bool, + pub lamports: u64, + pub owner: Pubkey, + pub rent_epoch: u64, + pub tick_array: OrcaTickArrayAccount, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaTickArrayAccount { + pub start_tick_index: i32, + pub ticks: Vec, + pub whirlpool: Pubkey, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaTick { + pub initialized: bool, + pub liquidity_net: i128, + pub liquidity_gross: u128, + pub fee_growth_outside_a: u128, + pub fee_growth_outside_b: u128, + pub reward_growths_outside: [u128; 3], +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaFeeTierAccountEvent { + pub metadata: EventMetadata, + pub pubkey: Pubkey, + pub executable: bool, + pub lamports: u64, + pub owner: Pubkey, + pub rent_epoch: u64, + pub fee_tier: OrcaFeeTierAccount, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaFeeTierAccount { + pub whirlpools_config: Pubkey, + pub tick_spacing: u16, + pub default_fee_rate: u16, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaWhirlpoolsConfigAccountEvent { + pub metadata: EventMetadata, + pub pubkey: Pubkey, + pub executable: bool, + pub lamports: u64, + pub owner: Pubkey, + pub rent_epoch: u64, + pub config: OrcaWhirlpoolsConfigAccount, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrcaWhirlpoolsConfigAccount { + pub fee_authority: Pubkey, + pub collect_protocol_fees_authority: Pubkey, + pub reward_emissions_super_authority: Pubkey, + pub default_protocol_fee_rate: u16, +} + +// --- Meteora DBC --- + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeteoraDbcSwapEvent { + pub metadata: EventMetadata, + pub pool: Pubkey, + pub config: Pubkey, + pub trade_direction: u8, + pub has_referral: bool, + pub amount_in: u64, + pub minimum_amount_out: u64, + pub actual_input_amount: u64, + pub output_amount: u64, + pub next_sqrt_price: u128, + pub trading_fee: u64, + pub protocol_fee: u64, + pub referral_fee: u64, + pub current_timestamp: u64, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeteoraDbcInitializePoolEvent { + pub metadata: EventMetadata, + pub pool: Pubkey, + pub config: Pubkey, + pub creator: Pubkey, + pub base_mint: Pubkey, + pub pool_type: u8, + pub activation_point: u64, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeteoraDbcCurveCompleteEvent { + pub metadata: EventMetadata, + pub pool: Pubkey, + pub config: Pubkey, + pub base_reserve: u64, + pub quote_reserve: u64, +} + // --- Meteora Pools --- #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/streaming/event_parser/protocols/types.rs b/src/streaming/event_parser/protocols/types.rs index 406d0f9..b919dc5 100755 --- a/src/streaming/event_parser/protocols/types.rs +++ b/src/streaming/event_parser/protocols/types.rs @@ -1,8 +1,9 @@ use anyhow::{anyhow, Result}; use sol_parser_sdk::instr::program_ids::{ - BONK_PROGRAM_ID, METEORA_DAMM_V2_PROGRAM_ID, METEORA_DLMM_PROGRAM_ID, METEORA_POOLS_PROGRAM_ID, - ORCA_WHIRLPOOL_PROGRAM_ID, PUMPFUN_PROGRAM_ID, PUMPSWAP_PROGRAM_ID, PUMP_FEES_PROGRAM_ID, - RAYDIUM_AMM_V4_PROGRAM_ID, RAYDIUM_CLMM_PROGRAM_ID, RAYDIUM_CPMM_PROGRAM_ID, + METEORA_DAMM_V2_PROGRAM_ID, METEORA_DBC_PROGRAM_ID, METEORA_DLMM_PROGRAM_ID, + METEORA_POOLS_PROGRAM_ID, ORCA_WHIRLPOOL_PROGRAM_ID, PUMPFUN_PROGRAM_ID, PUMPSWAP_PROGRAM_ID, + PUMP_FEES_PROGRAM_ID, RAYDIUM_AMM_V4_PROGRAM_ID, RAYDIUM_CLMM_PROGRAM_ID, + RAYDIUM_CPMM_PROGRAM_ID, RAYDIUM_LAUNCHLAB_PROGRAM_ID as BONK_PROGRAM_ID, }; use solana_sdk::pubkey::Pubkey; @@ -19,6 +20,7 @@ pub enum Protocol { RaydiumClmm, RaydiumAmmV4, MeteoraDammV2, + MeteoraDbc, OrcaWhirlpool, MeteoraPools, MeteoraDlmm, @@ -36,6 +38,7 @@ impl Protocol { Protocol::RaydiumClmm => vec![RAYDIUM_CLMM_PROGRAM_ID], Protocol::RaydiumAmmV4 => vec![RAYDIUM_AMM_V4_PROGRAM_ID], Protocol::MeteoraDammV2 => vec![METEORA_DAMM_V2_PROGRAM_ID], + Protocol::MeteoraDbc => vec![METEORA_DBC_PROGRAM_ID], Protocol::OrcaWhirlpool => vec![ORCA_WHIRLPOOL_PROGRAM_ID], Protocol::MeteoraPools => vec![METEORA_POOLS_PROGRAM_ID], Protocol::MeteoraDlmm => vec![METEORA_DLMM_PROGRAM_ID], @@ -55,6 +58,7 @@ impl std::fmt::Display for Protocol { Protocol::RaydiumClmm => write!(f, "RaydiumClmm"), Protocol::RaydiumAmmV4 => write!(f, "RaydiumAmmV4"), Protocol::MeteoraDammV2 => write!(f, "MeteoraDammV2"), + Protocol::MeteoraDbc => write!(f, "MeteoraDbc"), Protocol::OrcaWhirlpool => write!(f, "OrcaWhirlpool"), Protocol::MeteoraPools => write!(f, "MeteoraPools"), Protocol::MeteoraDlmm => write!(f, "MeteoraDlmm"), @@ -77,6 +81,7 @@ impl std::str::FromStr for Protocol { "raydiumclmm" | "raydium_clmm" => Ok(Protocol::RaydiumClmm), "raydiumammv4" | "raydium_amm_v4" => Ok(Protocol::RaydiumAmmV4), "meteoradammv2" | "meteoradamm_v2" | "meteora_damm_v2" => Ok(Protocol::MeteoraDammV2), + "meteoradbc" | "meteora_dbc" => Ok(Protocol::MeteoraDbc), "orcawhirlpool" | "orca_whirlpool" | "orca" => Ok(Protocol::OrcaWhirlpool), "meteorapools" | "meteora_pools" => Ok(Protocol::MeteoraPools), "meteoradlmm" | "meteora_dlmm" => Ok(Protocol::MeteoraDlmm), @@ -99,6 +104,7 @@ mod tests { Protocol::RaydiumClmm, Protocol::RaydiumAmmV4, Protocol::MeteoraDammV2, + Protocol::MeteoraDbc, Protocol::OrcaWhirlpool, Protocol::MeteoraPools, Protocol::MeteoraDlmm, @@ -116,6 +122,7 @@ mod tests { assert_eq!(Protocol::from_str("raydium_clmm").unwrap(), Protocol::RaydiumClmm); assert_eq!(Protocol::from_str("raydium_amm_v4").unwrap(), Protocol::RaydiumAmmV4); assert_eq!(Protocol::from_str("meteora_damm_v2").unwrap(), Protocol::MeteoraDammV2); + assert_eq!(Protocol::from_str("meteora_dbc").unwrap(), Protocol::MeteoraDbc); assert_eq!(Protocol::from_str("orca_whirlpool").unwrap(), Protocol::OrcaWhirlpool); assert_eq!(Protocol::from_str("meteora_pools").unwrap(), Protocol::MeteoraPools); assert_eq!(Protocol::from_str("meteora_dlmm").unwrap(), Protocol::MeteoraDlmm); diff --git a/src/streaming/grpc/subscription.rs b/src/streaming/grpc/subscription.rs index 7a63d5d..840a56c 100644 --- a/src/streaming/grpc/subscription.rs +++ b/src/streaming/grpc/subscription.rs @@ -54,7 +54,7 @@ impl SubscriptionManager { )> { // When no filter is set, subscribe to block meta like before; if a filter exists, // only keep block meta when the filter includes block-related event types. - let blocks_meta = if event_type_filter.map_or(true, |f| f.include_block_event()) { + let blocks_meta = if event_type_filter.is_none_or(|f| f.include_block_event()) { HashMap::from([("".to_owned(), SubscribeRequestFilterBlocksMeta {})]) } else { HashMap::new() diff --git a/src/streaming/grpc/types.rs b/src/streaming/grpc/types.rs index 2d5f9db..80e5862 100644 --- a/src/streaming/grpc/types.rs +++ b/src/streaming/grpc/types.rs @@ -11,6 +11,7 @@ use yellowstone_grpc_proto::{ pub type TransactionsFilterMap = HashMap; pub type AccountsFilterMap = HashMap; +#[allow(clippy::large_enum_variant)] #[derive(Clone, Debug)] pub enum EventPretty { BlockMeta(BlockMetaPretty), @@ -65,7 +66,7 @@ impl fmt::Debug for BlockMetaPretty { } } -#[derive(Clone)] +#[derive(Clone, Default)] pub struct TransactionPretty { pub slot: u64, pub tx_index: Option, // 新增:交易在slot中的索引 @@ -88,18 +89,3 @@ impl fmt::Debug for TransactionPretty { .finish() } } - -impl Default for TransactionPretty { - fn default() -> Self { - Self { - slot: 0, - tx_index: None, - block_hash: String::new(), - block_time: None, - signature: Signature::default(), - is_vote: false, - grpc_tx: SubscribeUpdateTransactionInfo::default(), - recv_us: 0, - } - } -} diff --git a/src/streaming/parser_sdk_bridge/accounts.rs b/src/streaming/parser_sdk_bridge/accounts.rs index f525f11..b05d965 100644 --- a/src/streaming/parser_sdk_bridge/accounts.rs +++ b/src/streaming/parser_sdk_bridge/accounts.rs @@ -11,7 +11,7 @@ use super::convert_parser_event; use super::filter::event_matches_protocol; pub(crate) enum AccountParseResult { - Event(DexEvent), + Event(Box), Filtered, Unsupported, } @@ -22,7 +22,7 @@ pub(crate) fn parse_account_event( event_type_filter: Option<&EventTypeFilter>, ) -> Option { match parse_account_event_for_streamer(account, protocols, event_type_filter) { - AccountParseResult::Event(event) => Some(event), + AccountParseResult::Event(event) => Some(*event), AccountParseResult::Filtered | AccountParseResult::Unsupported => None, } } @@ -68,7 +68,7 @@ pub(crate) fn parse_account_event_for_streamer( return AccountParseResult::Filtered; } normalize_account_event(&mut event, account); - AccountParseResult::Event(event) + AccountParseResult::Event(Box::new(event)) } fn build_sdk_account_event_filter(filter: Option<&EventTypeFilter>) -> SdkGrpcEventTypeFilter { @@ -124,6 +124,19 @@ fn streamer_account_event_to_sdk_types(t: &EventType) -> Vec { EventType::AccountRaydiumClmmTickArrayState => { vec![SdkGrpcEventType::AccountRaydiumClmmTickArrayState] } + EventType::AccountRaydiumCpmmAmmConfig => { + vec![SdkGrpcEventType::AccountRaydiumCpmmAmmConfig] + } + EventType::AccountRaydiumCpmmPoolState => { + vec![SdkGrpcEventType::AccountRaydiumCpmmPoolState] + } + EventType::AccountOrcaWhirlpool => vec![SdkGrpcEventType::AccountOrcaWhirlpool], + EventType::AccountOrcaPosition => vec![SdkGrpcEventType::AccountOrcaPosition], + EventType::AccountOrcaTickArray => vec![SdkGrpcEventType::AccountOrcaTickArray], + EventType::AccountOrcaFeeTier => vec![SdkGrpcEventType::AccountOrcaFeeTier], + EventType::AccountOrcaWhirlpoolsConfig => { + vec![SdkGrpcEventType::AccountOrcaWhirlpoolsConfig] + } _ => Vec::new(), } } @@ -195,6 +208,48 @@ fn normalize_account_event(event: &mut DexEvent, account: &AccountPretty) { e.owner = account.owner; e.rent_epoch = account.rent_epoch; } + DexEvent::RaydiumCpmmAmmConfigAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } + DexEvent::RaydiumCpmmPoolStateAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } + DexEvent::OrcaWhirlpoolAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } + DexEvent::OrcaPositionAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } + DexEvent::OrcaTickArrayAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } + DexEvent::OrcaFeeTierAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } + DexEvent::OrcaWhirlpoolsConfigAccountEvent(e) => { + e.executable = account.executable; + e.lamports = account.lamports; + e.owner = account.owner; + e.rent_epoch = account.rent_epoch; + } _ => {} } } diff --git a/src/streaming/parser_sdk_bridge/bonk_accounts.rs b/src/streaming/parser_sdk_bridge/bonk_accounts.rs index 53b69c5..491eb5a 100644 --- a/src/streaming/parser_sdk_bridge/bonk_accounts.rs +++ b/src/streaming/parser_sdk_bridge/bonk_accounts.rs @@ -14,7 +14,7 @@ use crate::streaming::event_parser::protocols::pumpswap::events::{ }; use crate::streaming::event_parser::protocols::pumpswap::types::{GlobalConfig, Pool}; use sol_parser_sdk::core::events::{ - BonkTradeEvent as PbBonkTrade, TradeDirection as PbBonkTradeDirection, + RaydiumLaunchlabTradeEvent as PbBonkTrade, TradeDirection as PbBonkTradeDirection, }; use solana_sdk::pubkey::Pubkey; @@ -43,7 +43,7 @@ pub(crate) fn sdk_bonk_trade_event_type( /// SDK Bonk trade events do not expose reserves or fee rates; keep those fields at streamer /// defaults. pub(crate) fn bonk_trade_from_parser( - b: sol_parser_sdk::core::events::BonkTradeEvent, + b: sol_parser_sdk::core::events::RaydiumLaunchlabTradeEvent, meta: EventMetadata, ) -> BonkTradeEvent { BonkTradeEvent { @@ -71,7 +71,7 @@ pub(crate) fn bonk_trade_from_parser( } pub(crate) fn bonk_pool_create_from_parser( - p: sol_parser_sdk::core::events::BonkPoolCreateEvent, + p: sol_parser_sdk::core::events::RaydiumLaunchlabPoolCreateEvent, meta: EventMetadata, ) -> BonkPoolCreateEvent { BonkPoolCreateEvent { @@ -93,7 +93,7 @@ pub(crate) fn bonk_pool_create_from_parser( } pub(crate) fn bonk_migrate_to_amm_from_parser( - m: sol_parser_sdk::core::events::BonkMigrateAmmEvent, + m: sol_parser_sdk::core::events::RaydiumLaunchlabMigrateAmmEvent, meta: EventMetadata, ) -> BonkMigrateToAmmEvent { BonkMigrateToAmmEvent { diff --git a/src/streaming/parser_sdk_bridge/convert.rs b/src/streaming/parser_sdk_bridge/convert.rs index caf76e4..cc4a736 100644 --- a/src/streaming/parser_sdk_bridge/convert.rs +++ b/src/streaming/parser_sdk_bridge/convert.rs @@ -338,7 +338,7 @@ pub(crate) fn convert_parser_event( Some(DexEvent::PumpSwapWithdrawEvent(pumpswap_liquidity_removed_to_withdraw(r, meta))) } - PbDexEvent::BonkTrade(b) => { + PbDexEvent::RaydiumLaunchlabTrade(b) => { let et = sdk_bonk_trade_event_type(&b); let meta = adapt_pm( b.metadata.clone(), @@ -350,7 +350,7 @@ pub(crate) fn convert_parser_event( ); Some(DexEvent::BonkTradeEvent(bonk_trade_from_parser(b, meta))) } - PbDexEvent::BonkPoolCreate(p) => { + PbDexEvent::RaydiumLaunchlabPoolCreate(p) => { let meta = adapt_pm( p.metadata.clone(), bt, @@ -361,7 +361,7 @@ pub(crate) fn convert_parser_event( ); Some(DexEvent::BonkPoolCreateEvent(bonk_pool_create_from_parser(p, meta))) } - PbDexEvent::BonkMigrateAmm(m) => { + PbDexEvent::RaydiumLaunchlabMigrateAmm(m) => { let meta = adapt_pm( m.metadata.clone(), bt, @@ -422,6 +422,32 @@ pub(crate) fn convert_parser_event( ); Some(DexEvent::RaydiumCpmmInitializeEvent(raydium_cpmm_initialize_from_parser(e, meta))) } + PbDexEvent::RaydiumCpmmAmmConfigAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::RaydiumCpmm, + EventType::AccountRaydiumCpmmAmmConfig, + raydium_cpmm_program(), + ); + Some(DexEvent::RaydiumCpmmAmmConfigAccountEvent(Box::new( + raydium_cpmm_amm_config_account_from_parser(*e, meta), + ))) + } + PbDexEvent::RaydiumCpmmPoolStateAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::RaydiumCpmm, + EventType::AccountRaydiumCpmmPoolState, + raydium_cpmm_program(), + ); + Some(DexEvent::RaydiumCpmmPoolStateAccountEvent(Box::new( + raydium_cpmm_pool_state_account_from_parser(*e, meta), + ))) + } PbDexEvent::RaydiumClmmSwap(e) => { let meta = adapt_pm( @@ -651,9 +677,9 @@ pub(crate) fn convert_parser_event( EventType::AccountRaydiumClmmAmmConfig, raydium_clmm_program(), ); - Some(DexEvent::RaydiumClmmAmmConfigAccountEvent( - raydium_clmm_amm_config_account_from_parser(e, meta), - )) + Some(DexEvent::RaydiumClmmAmmConfigAccountEvent(Box::new( + raydium_clmm_amm_config_account_from_parser(*e, meta), + ))) } PbDexEvent::RaydiumClmmPoolStateAccount(e) => { let meta = adapt_pm( @@ -664,9 +690,9 @@ pub(crate) fn convert_parser_event( EventType::AccountRaydiumClmmPoolState, raydium_clmm_program(), ); - Some(DexEvent::RaydiumClmmPoolStateAccountEvent( - raydium_clmm_pool_state_account_from_parser(e, meta), - )) + Some(DexEvent::RaydiumClmmPoolStateAccountEvent(Box::new( + raydium_clmm_pool_state_account_from_parser(*e, meta), + ))) } PbDexEvent::RaydiumClmmTickArrayStateAccount(e) => { let meta = adapt_pm( @@ -677,9 +703,9 @@ pub(crate) fn convert_parser_event( EventType::AccountRaydiumClmmTickArrayState, raydium_clmm_program(), ); - Some(DexEvent::RaydiumClmmTickArrayStateAccountEvent( - raydium_clmm_tick_array_state_account_from_parser(e, meta), - )) + Some(DexEvent::RaydiumClmmTickArrayStateAccountEvent(Box::new( + raydium_clmm_tick_array_state_account_from_parser(*e, meta), + ))) } PbDexEvent::RaydiumAmmV4Swap(e) => { @@ -758,6 +784,19 @@ pub(crate) fn convert_parser_event( ); Some(DexEvent::MeteoraDammV2SwapEvent(meteora_damm_v2_swap_from_parser(e, meta))) } + PbDexEvent::MeteoraDammV2InitializePool(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::MeteoraDammV2, + EventType::MeteoraDammV2InitializePool, + meteora_damm_program(), + ); + Some(DexEvent::MeteoraDammV2InitializePoolEvent( + meteora_damm_v2_initialize_pool_from_parser(e, meta), + )) + } PbDexEvent::MeteoraDammV2AddLiquidity(e) => { let meta = adapt_pm( e.metadata.clone(), @@ -811,6 +850,44 @@ pub(crate) fn convert_parser_event( ))) } + PbDexEvent::MeteoraDbcSwap(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::MeteoraDbc, + EventType::MeteoraDbcSwap, + meteora_dbc_program(), + ); + Some(DexEvent::MeteoraDbcSwapEvent(meteora_dbc_swap_from_pb(e, meta))) + } + PbDexEvent::MeteoraDbcInitializePool(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::MeteoraDbc, + EventType::MeteoraDbcInitializePool, + meteora_dbc_program(), + ); + Some(DexEvent::MeteoraDbcInitializePoolEvent(meteora_dbc_initialize_pool_from_pb( + e, meta, + ))) + } + PbDexEvent::MeteoraDbcCurveComplete(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::MeteoraDbc, + EventType::MeteoraDbcCurveComplete, + meteora_dbc_program(), + ); + Some(DexEvent::MeteoraDbcCurveCompleteEvent(meteora_dbc_curve_complete_from_pb( + e, meta, + ))) + } + PbDexEvent::TokenAccount(e) => { let meta = adapt_pm( e.metadata.clone(), @@ -943,6 +1020,71 @@ pub(crate) fn convert_parser_event( e, meta, ))) } + PbDexEvent::OrcaWhirlpoolAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::OrcaWhirlpool, + EventType::AccountOrcaWhirlpool, + orca_whirlpool_program(), + ); + Some(DexEvent::OrcaWhirlpoolAccountEvent(Box::new(orca_whirlpool_account_from_pb( + *e, meta, + )))) + } + PbDexEvent::OrcaPositionAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::OrcaWhirlpool, + EventType::AccountOrcaPosition, + orca_whirlpool_program(), + ); + Some(DexEvent::OrcaPositionAccountEvent(Box::new(orca_position_account_from_pb( + *e, meta, + )))) + } + PbDexEvent::OrcaTickArrayAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::OrcaWhirlpool, + EventType::AccountOrcaTickArray, + orca_whirlpool_program(), + ); + Some(DexEvent::OrcaTickArrayAccountEvent(Box::new(orca_tick_array_account_from_pb( + *e, meta, + )))) + } + PbDexEvent::OrcaFeeTierAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::OrcaWhirlpool, + EventType::AccountOrcaFeeTier, + orca_whirlpool_program(), + ); + Some(DexEvent::OrcaFeeTierAccountEvent(Box::new(orca_fee_tier_account_from_pb( + *e, meta, + )))) + } + PbDexEvent::OrcaWhirlpoolsConfigAccount(e) => { + let meta = adapt_pm( + e.metadata.clone(), + bt, + recv_wall_us, + ProtocolType::OrcaWhirlpool, + EventType::AccountOrcaWhirlpoolsConfig, + orca_whirlpool_program(), + ); + Some(DexEvent::OrcaWhirlpoolsConfigAccountEvent(Box::new( + orca_whirlpools_config_account_from_pb(*e, meta), + ))) + } PbDexEvent::MeteoraPoolsSwap(e) => { let meta = adapt_pm( e.metadata.clone(), diff --git a/src/streaming/parser_sdk_bridge/filter.rs b/src/streaming/parser_sdk_bridge/filter.rs index ab5dff9..e69c020 100644 --- a/src/streaming/parser_sdk_bridge/filter.rs +++ b/src/streaming/parser_sdk_bridge/filter.rs @@ -25,6 +25,7 @@ fn is_protocol_independent_event(ev: &DexEvent) -> bool { ) } +#[allow(clippy::match_like_matches_macro)] fn protocol_matches_event(p: &Protocol, ev: &DexEvent) -> bool { match (p, ev) { (Protocol::PumpFun, DexEvent::PumpFunCreateTokenEvent(_)) @@ -122,10 +123,18 @@ fn protocol_matches_event(p: &Protocol, ev: &DexEvent) -> bool { | (Protocol::MeteoraDammV2, DexEvent::MeteoraDammV2RemoveLiquidityEvent(_)) | (Protocol::MeteoraDammV2, DexEvent::MeteoraDammV2CreatePositionEvent(_)) | (Protocol::MeteoraDammV2, DexEvent::MeteoraDammV2ClosePositionEvent(_)) => true, + (Protocol::MeteoraDbc, DexEvent::MeteoraDbcSwapEvent(_)) + | (Protocol::MeteoraDbc, DexEvent::MeteoraDbcInitializePoolEvent(_)) + | (Protocol::MeteoraDbc, DexEvent::MeteoraDbcCurveCompleteEvent(_)) => true, (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolSwapEvent(_)) | (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolLiquidityIncreasedEvent(_)) | (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolLiquidityDecreasedEvent(_)) - | (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolPoolInitializedEvent(_)) => true, + | (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolPoolInitializedEvent(_)) + | (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolAccountEvent(_)) + | (Protocol::OrcaWhirlpool, DexEvent::OrcaPositionAccountEvent(_)) + | (Protocol::OrcaWhirlpool, DexEvent::OrcaTickArrayAccountEvent(_)) + | (Protocol::OrcaWhirlpool, DexEvent::OrcaFeeTierAccountEvent(_)) + | (Protocol::OrcaWhirlpool, DexEvent::OrcaWhirlpoolsConfigAccountEvent(_)) => true, (Protocol::MeteoraPools, DexEvent::MeteoraPoolsSwapEvent(_)) | (Protocol::MeteoraPools, DexEvent::MeteoraPoolsAddLiquidityEvent(_)) | (Protocol::MeteoraPools, DexEvent::MeteoraPoolsRemoveLiquidityEvent(_)) diff --git a/src/streaming/parser_sdk_bridge/forward_pb.rs b/src/streaming/parser_sdk_bridge/forward_pb.rs index 0006388..b070fd3 100644 --- a/src/streaming/parser_sdk_bridge/forward_pb.rs +++ b/src/streaming/parser_sdk_bridge/forward_pb.rs @@ -1,14 +1,18 @@ //! Orca Whirlpool and Meteora Pools / DLMM events with SDK-shaped payloads. use crate::streaming::event_parser::common::EventMetadata; use crate::streaming::event_parser::protocols::sol_parser_forward::events::{ + MeteoraDbcCurveCompleteEvent, MeteoraDbcInitializePoolEvent, MeteoraDbcSwapEvent, MeteoraDlmmAddLiquidityEvent, MeteoraDlmmClaimFeeEvent, MeteoraDlmmClosePositionEvent, MeteoraDlmmCreatePositionEvent, MeteoraDlmmInitializeBinArrayEvent, MeteoraDlmmInitializePoolEvent, MeteoraDlmmRemoveLiquidityEvent, MeteoraDlmmSwapEvent, MeteoraPoolsAddLiquidityEvent, MeteoraPoolsBootstrapLiquidityEvent, MeteoraPoolsPoolCreatedEvent, MeteoraPoolsRemoveLiquidityEvent, MeteoraPoolsSetPoolFeesEvent, - MeteoraPoolsSwapEvent, OrcaWhirlpoolLiquidityDecreasedEvent, - OrcaWhirlpoolLiquidityIncreasedEvent, OrcaWhirlpoolPoolInitializedEvent, - OrcaWhirlpoolSwapEvent, + MeteoraPoolsSwapEvent, OrcaFeeTierAccount, OrcaFeeTierAccountEvent, OrcaPositionAccount, + OrcaPositionAccountEvent, OrcaPositionRewardInfo, OrcaTick, OrcaTickArrayAccount, + OrcaTickArrayAccountEvent, OrcaWhirlpoolAccount, OrcaWhirlpoolAccountEvent, + OrcaWhirlpoolLiquidityDecreasedEvent, OrcaWhirlpoolLiquidityIncreasedEvent, + OrcaWhirlpoolPoolInitializedEvent, OrcaWhirlpoolRewardInfo, OrcaWhirlpoolSwapEvent, + OrcaWhirlpoolsConfigAccount, OrcaWhirlpoolsConfigAccountEvent, }; pub(crate) fn orca_swap_from_pb( @@ -85,6 +89,192 @@ pub(crate) fn orca_pool_initialized_from_pb( } } +fn orca_whirlpool_reward_from_pb( + r: sol_parser_sdk::core::events::OrcaWhirlpoolRewardInfo, +) -> OrcaWhirlpoolRewardInfo { + OrcaWhirlpoolRewardInfo { + mint: r.mint, + vault: r.vault, + authority: r.authority, + emissions_per_second_x64: r.emissions_per_second_x64, + growth_global_x64: r.growth_global_x64, + } +} + +fn orca_position_reward_from_pb( + r: sol_parser_sdk::core::events::OrcaPositionRewardInfo, +) -> OrcaPositionRewardInfo { + OrcaPositionRewardInfo { + growth_inside_checkpoint: r.growth_inside_checkpoint, + amount_owed: r.amount_owed, + } +} + +fn orca_tick_from_pb(t: sol_parser_sdk::core::events::OrcaTick) -> OrcaTick { + OrcaTick { + initialized: t.initialized, + liquidity_net: t.liquidity_net, + liquidity_gross: t.liquidity_gross, + fee_growth_outside_a: t.fee_growth_outside_a, + fee_growth_outside_b: t.fee_growth_outside_b, + reward_growths_outside: t.reward_growths_outside, + } +} + +pub(crate) fn orca_whirlpool_account_from_pb( + e: sol_parser_sdk::core::events::OrcaWhirlpoolAccountEvent, + meta: EventMetadata, +) -> OrcaWhirlpoolAccountEvent { + OrcaWhirlpoolAccountEvent { + metadata: meta, + pubkey: e.pubkey, + whirlpool: OrcaWhirlpoolAccount { + whirlpools_config: e.whirlpool.whirlpools_config, + whirlpool_bump: e.whirlpool.whirlpool_bump, + tick_spacing: e.whirlpool.tick_spacing, + tick_spacing_seed: e.whirlpool.tick_spacing_seed, + fee_rate: e.whirlpool.fee_rate, + protocol_fee_rate: e.whirlpool.protocol_fee_rate, + liquidity: e.whirlpool.liquidity, + sqrt_price: e.whirlpool.sqrt_price, + tick_current_index: e.whirlpool.tick_current_index, + protocol_fee_owed_a: e.whirlpool.protocol_fee_owed_a, + protocol_fee_owed_b: e.whirlpool.protocol_fee_owed_b, + token_mint_a: e.whirlpool.token_mint_a, + token_vault_a: e.whirlpool.token_vault_a, + fee_growth_global_a: e.whirlpool.fee_growth_global_a, + token_mint_b: e.whirlpool.token_mint_b, + token_vault_b: e.whirlpool.token_vault_b, + fee_growth_global_b: e.whirlpool.fee_growth_global_b, + reward_last_updated_timestamp: e.whirlpool.reward_last_updated_timestamp, + reward_infos: e.whirlpool.reward_infos.map(orca_whirlpool_reward_from_pb), + }, + ..Default::default() + } +} + +pub(crate) fn orca_position_account_from_pb( + e: sol_parser_sdk::core::events::OrcaPositionAccountEvent, + meta: EventMetadata, +) -> OrcaPositionAccountEvent { + OrcaPositionAccountEvent { + metadata: meta, + pubkey: e.pubkey, + position: OrcaPositionAccount { + whirlpool: e.position.whirlpool, + position_mint: e.position.position_mint, + liquidity: e.position.liquidity, + tick_lower_index: e.position.tick_lower_index, + tick_upper_index: e.position.tick_upper_index, + fee_growth_checkpoint_a: e.position.fee_growth_checkpoint_a, + fee_owed_a: e.position.fee_owed_a, + fee_growth_checkpoint_b: e.position.fee_growth_checkpoint_b, + fee_owed_b: e.position.fee_owed_b, + reward_infos: e.position.reward_infos.map(orca_position_reward_from_pb), + }, + ..Default::default() + } +} + +pub(crate) fn orca_tick_array_account_from_pb( + e: sol_parser_sdk::core::events::OrcaTickArrayAccountEvent, + meta: EventMetadata, +) -> OrcaTickArrayAccountEvent { + OrcaTickArrayAccountEvent { + metadata: meta, + pubkey: e.pubkey, + tick_array: OrcaTickArrayAccount { + start_tick_index: e.tick_array.start_tick_index, + ticks: e.tick_array.ticks.into_iter().map(orca_tick_from_pb).collect(), + whirlpool: e.tick_array.whirlpool, + }, + ..Default::default() + } +} + +pub(crate) fn orca_fee_tier_account_from_pb( + e: sol_parser_sdk::core::events::OrcaFeeTierAccountEvent, + meta: EventMetadata, +) -> OrcaFeeTierAccountEvent { + OrcaFeeTierAccountEvent { + metadata: meta, + pubkey: e.pubkey, + fee_tier: OrcaFeeTierAccount { + whirlpools_config: e.fee_tier.whirlpools_config, + tick_spacing: e.fee_tier.tick_spacing, + default_fee_rate: e.fee_tier.default_fee_rate, + }, + ..Default::default() + } +} + +pub(crate) fn orca_whirlpools_config_account_from_pb( + e: sol_parser_sdk::core::events::OrcaWhirlpoolsConfigAccountEvent, + meta: EventMetadata, +) -> OrcaWhirlpoolsConfigAccountEvent { + OrcaWhirlpoolsConfigAccountEvent { + metadata: meta, + pubkey: e.pubkey, + config: OrcaWhirlpoolsConfigAccount { + fee_authority: e.config.fee_authority, + collect_protocol_fees_authority: e.config.collect_protocol_fees_authority, + reward_emissions_super_authority: e.config.reward_emissions_super_authority, + default_protocol_fee_rate: e.config.default_protocol_fee_rate, + }, + ..Default::default() + } +} + +pub(crate) fn meteora_dbc_swap_from_pb( + e: sol_parser_sdk::core::events::MeteoraDbcSwapEvent, + meta: EventMetadata, +) -> MeteoraDbcSwapEvent { + MeteoraDbcSwapEvent { + metadata: meta, + pool: e.pool, + config: e.config, + trade_direction: e.trade_direction, + has_referral: e.has_referral, + amount_in: e.amount_in, + minimum_amount_out: e.minimum_amount_out, + actual_input_amount: e.actual_input_amount, + output_amount: e.output_amount, + next_sqrt_price: e.next_sqrt_price, + trading_fee: e.trading_fee, + protocol_fee: e.protocol_fee, + referral_fee: e.referral_fee, + current_timestamp: e.current_timestamp, + } +} + +pub(crate) fn meteora_dbc_initialize_pool_from_pb( + e: sol_parser_sdk::core::events::MeteoraDbcInitializePoolEvent, + meta: EventMetadata, +) -> MeteoraDbcInitializePoolEvent { + MeteoraDbcInitializePoolEvent { + metadata: meta, + pool: e.pool, + config: e.config, + creator: e.creator, + base_mint: e.base_mint, + pool_type: e.pool_type, + activation_point: e.activation_point, + } +} + +pub(crate) fn meteora_dbc_curve_complete_from_pb( + e: sol_parser_sdk::core::events::MeteoraDbcCurveCompleteEvent, + meta: EventMetadata, +) -> MeteoraDbcCurveCompleteEvent { + MeteoraDbcCurveCompleteEvent { + metadata: meta, + pool: e.pool, + config: e.config, + base_reserve: e.base_reserve, + quote_reserve: e.quote_reserve, + } +} + pub(crate) fn meteora_pools_swap_from_pb( e: sol_parser_sdk::core::events::MeteoraPoolsSwapEvent, meta: EventMetadata, diff --git a/src/streaming/parser_sdk_bridge/mod.rs b/src/streaming/parser_sdk_bridge/mod.rs index 996776f..770a1b0 100644 --- a/src/streaming/parser_sdk_bridge/mod.rs +++ b/src/streaming/parser_sdk_bridge/mod.rs @@ -32,6 +32,7 @@ pub(crate) use adapt::{block_timestamp_from_stream_meta, fuse_streamer_ix_ctx}; pub(crate) use convert::{adapt_parser_event, adapt_parser_events_list, convert_parser_event}; #[cfg(test)] +#[allow(clippy::field_reassign_with_default)] mod tests { use super::filter::event_matches_protocol; use super::{adapt_parser_event, convert_parser_event}; @@ -40,9 +41,9 @@ mod tests { use crate::streaming::event_parser::core::account_event_parser::TokenInfoEvent; use crate::streaming::event_parser::{DexEvent, Protocol}; use sol_parser_sdk::core::events::{ - BonkTradeEvent as PbBonkTrade, EventMetadata, MeteoraDlmmSwapEvent as PbDlmmSwap, - OrcaWhirlpoolSwapEvent as PbOrcaSwap, PumpFunCreateV2TokenEvent as PbPumpCreateV2, - PumpFunTradeEvent as PbPumpTrade, TokenInfoEvent as PbTokenInfo, + EventMetadata, MeteoraDlmmSwapEvent as PbDlmmSwap, OrcaWhirlpoolSwapEvent as PbOrcaSwap, + PumpFunCreateV2TokenEvent as PbPumpCreateV2, PumpFunTradeEvent as PbPumpTrade, + RaydiumLaunchlabTradeEvent as PbBonkTrade, TokenInfoEvent as PbTokenInfo, TradeDirection as PbBonkDir, }; use sol_parser_sdk::DexEvent as PbDexEvent; @@ -370,7 +371,8 @@ mod tests { trade_direction: PbBonkDir::Buy, exact_in: true, }; - let dex = convert_parser_event(PbDexEvent::BonkTrade(b), None, 0).expect("convert"); + let dex = + convert_parser_event(PbDexEvent::RaydiumLaunchlabTrade(b), None, 0).expect("convert"); match dex { DexEvent::BonkTradeEvent(e) => { assert_eq!(e.metadata.event_type, EventType::BonkBuyExactIn) @@ -391,7 +393,8 @@ mod tests { trade_direction: PbBonkDir::Sell, exact_in: false, }; - let dex = convert_parser_event(PbDexEvent::BonkTrade(b), None, 0).expect("convert"); + let dex = + convert_parser_event(PbDexEvent::RaydiumLaunchlabTrade(b), None, 0).expect("convert"); match dex { DexEvent::BonkTradeEvent(e) => { assert_eq!(e.metadata.event_type, EventType::BonkSellExactOut) diff --git a/src/streaming/parser_sdk_bridge/program_ids.rs b/src/streaming/parser_sdk_bridge/program_ids.rs index 988676e..abf7334 100644 --- a/src/streaming/parser_sdk_bridge/program_ids.rs +++ b/src/streaming/parser_sdk_bridge/program_ids.rs @@ -12,7 +12,7 @@ pub(crate) fn pump_fees_program() -> Pubkey { program_ids::PUMP_FEES_PROGRAM_ID } pub(crate) fn bonk_program() -> Pubkey { - program_ids::BONK_PROGRAM_ID + program_ids::RAYDIUM_LAUNCHLAB_PROGRAM_ID } pub(crate) fn raydium_cpmm_program() -> Pubkey { program_ids::RAYDIUM_CPMM_PROGRAM_ID @@ -27,6 +27,10 @@ pub(crate) fn meteora_damm_program() -> Pubkey { program_ids::METEORA_DAMM_V2_PROGRAM_ID } +pub(crate) fn meteora_dbc_program() -> Pubkey { + program_ids::METEORA_DBC_PROGRAM_ID +} + pub(crate) fn orca_whirlpool_program() -> Pubkey { program_ids::ORCA_WHIRLPOOL_PROGRAM_ID } diff --git a/src/streaming/parser_sdk_bridge/raydium_and_damm.rs b/src/streaming/parser_sdk_bridge/raydium_and_damm.rs index bebd20a..9577d1d 100644 --- a/src/streaming/parser_sdk_bridge/raydium_and_damm.rs +++ b/src/streaming/parser_sdk_bridge/raydium_and_damm.rs @@ -2,7 +2,8 @@ use crate::streaming::event_parser::common::EventMetadata; use crate::streaming::event_parser::protocols::meteora_damm_v2::events::{ MeteoraDammV2AddLiquidityEvent, MeteoraDammV2ClosePositionEvent, - MeteoraDammV2CreatePositionEvent, MeteoraDammV2RemoveLiquidityEvent, MeteoraDammV2SwapEvent, + MeteoraDammV2CreatePositionEvent, MeteoraDammV2InitializePoolEvent, + MeteoraDammV2RemoveLiquidityEvent, MeteoraDammV2SwapEvent, }; use crate::streaming::event_parser::protocols::raydium_amm_v4::events::{ RaydiumAmmV4DepositEvent, RaydiumAmmV4Initialize2Event, RaydiumAmmV4SwapEvent, @@ -24,8 +25,11 @@ use crate::streaming::event_parser::protocols::raydium_clmm::types::{ RewardInfo as ClmmRewardInfo, TickArrayState as ClmmTickArrayState, TickState as ClmmTickState, }; use crate::streaming::event_parser::protocols::raydium_cpmm::events::{ - RaydiumCpmmDepositEvent, RaydiumCpmmInitializeEvent, RaydiumCpmmSwapEvent, - RaydiumCpmmWithdrawEvent, + RaydiumCpmmAmmConfigAccountEvent, RaydiumCpmmDepositEvent, RaydiumCpmmInitializeEvent, + RaydiumCpmmPoolStateAccountEvent, RaydiumCpmmSwapEvent, RaydiumCpmmWithdrawEvent, +}; +use crate::streaming::event_parser::protocols::raydium_cpmm::types::{ + AmmConfig as CpmmAmmConfig, PoolState as CpmmPoolState, }; use solana_sdk::pubkey::Pubkey; pub(crate) fn meteora_damm_v2_swap_from_parser( @@ -72,6 +76,38 @@ pub(crate) fn meteora_damm_v2_swap_from_parser( } } +pub(crate) fn meteora_damm_v2_initialize_pool_from_parser( + e: sol_parser_sdk::core::events::MeteoraDammV2InitializePoolEvent, + meta: EventMetadata, +) -> MeteoraDammV2InitializePoolEvent { + MeteoraDammV2InitializePoolEvent { + metadata: meta, + pool: e.pool, + token_a_mint: e.token_a_mint, + token_b_mint: e.token_b_mint, + creator: e.creator, + payer: e.payer, + alpha_vault: e.alpha_vault, + sqrt_min_price: e.sqrt_min_price, + sqrt_max_price: e.sqrt_max_price, + activation_type: e.activation_type, + collect_fee_mode: e.collect_fee_mode, + liquidity: e.liquidity, + sqrt_price: e.sqrt_price, + activation_point: e.activation_point.unwrap_or(0), + token_a_flag: e.token_a_flag, + token_b_flag: e.token_b_flag, + token_a_amount: e.token_a_amount, + token_b_amount: e.token_b_amount, + total_amount_a: e.total_amount_a, + total_amount_b: e.total_amount_b, + pool_type: e.pool_type, + position: e.position, + position_nft_mint: e.position_nft_mint, + ..Default::default() + } +} + pub(crate) fn raydium_cpmm_swap_from_parser( e: sol_parser_sdk::core::events::RaydiumCpmmSwapEvent, meta: EventMetadata, @@ -164,6 +200,85 @@ pub(crate) fn raydium_cpmm_initialize_from_parser( } } +fn raydium_cpmm_amm_config_from_parser( + c: sol_parser_sdk::core::events::RaydiumCpmmAmmConfig, +) -> CpmmAmmConfig { + CpmmAmmConfig { + bump: c.bump, + disable_create_pool: c.disable_create_pool, + index: c.index, + trade_fee_rate: c.trade_fee_rate, + protocol_fee_rate: c.protocol_fee_rate, + fund_fee_rate: c.fund_fee_rate, + create_pool_fee: c.create_pool_fee, + protocol_owner: c.protocol_owner, + fund_owner: c.fund_owner, + creator_fee_rate: c.creator_fee_rate, + padding: c.padding, + } +} + +fn raydium_cpmm_pool_state_from_parser( + p: sol_parser_sdk::core::events::RaydiumCpmmPoolState, +) -> CpmmPoolState { + CpmmPoolState { + amm_config: p.amm_config, + pool_creator: p.pool_creator, + token_0_vault: p.token_0_vault, + token_1_vault: p.token_1_vault, + lp_mint: p.lp_mint, + token_0_mint: p.token_0_mint, + token_1_mint: p.token_1_mint, + token_0_program: p.token_0_program, + token_1_program: p.token_1_program, + observation_key: p.observation_key, + auth_bump: p.auth_bump, + status: p.status, + lp_mint_decimals: p.lp_mint_decimals, + mint_0_decimals: p.mint_0_decimals, + mint_1_decimals: p.mint_1_decimals, + lp_supply: p.lp_supply, + protocol_fees_token_0: p.protocol_fees_token_0, + protocol_fees_token_1: p.protocol_fees_token_1, + fund_fees_token_0: p.fund_fees_token_0, + fund_fees_token_1: p.fund_fees_token_1, + open_time: p.open_time, + recent_epoch: p.recent_epoch, + creator_fee_on: p.creator_fee_on, + enable_creator_fee: p.enable_creator_fee, + padding1: p.padding1, + creator_fees_token_0: p.creator_fees_token_0, + creator_fees_token_1: p.creator_fees_token_1, + padding: p.padding, + } +} + +pub(crate) fn raydium_cpmm_amm_config_account_from_parser( + e: sol_parser_sdk::core::events::RaydiumCpmmAmmConfigAccountEvent, + meta: EventMetadata, +) -> RaydiumCpmmAmmConfigAccountEvent { + RaydiumCpmmAmmConfigAccountEvent { + metadata: meta, + pubkey: e.pubkey, + owner: super::program_ids::raydium_cpmm_program(), + amm_config: raydium_cpmm_amm_config_from_parser(e.amm_config), + ..Default::default() + } +} + +pub(crate) fn raydium_cpmm_pool_state_account_from_parser( + e: sol_parser_sdk::core::events::RaydiumCpmmPoolStateAccountEvent, + meta: EventMetadata, +) -> RaydiumCpmmPoolStateAccountEvent { + RaydiumCpmmPoolStateAccountEvent { + metadata: meta, + pubkey: e.pubkey, + owner: super::program_ids::raydium_cpmm_program(), + pool_state: raydium_cpmm_pool_state_from_parser(e.pool_state), + ..Default::default() + } +} + pub(crate) fn raydium_amm_v4_swap_from_parser( e: sol_parser_sdk::core::events::RaydiumAmmV4SwapEvent, meta: EventMetadata, diff --git a/src/streaming/shred/connection.rs b/src/streaming/shred/connection.rs index f90c8a0..7ae2a72 100644 --- a/src/streaming/shred/connection.rs +++ b/src/streaming/shred/connection.rs @@ -25,6 +25,7 @@ impl ShredStreamGrpc { /// 创建客户端,使用自定义配置 pub async fn new_with_config(endpoint: String, config: StreamClientConfig) -> AnyResult { + sol_parser_sdk::warmup_parser(); let shredstream_client = ShredstreamProxyClient::connect(endpoint.clone()) .await? .max_decoding_message_size(config.connection.max_decoding_message_size); diff --git a/src/streaming/shred/pool.rs b/src/streaming/shred/pool.rs index 81ad6a2..76a9409 100644 --- a/src/streaming/shred/pool.rs +++ b/src/streaming/shred/pool.rs @@ -63,7 +63,7 @@ impl PooledTransactionWithSlot { /// 使用优化的工厂方法创建 TransactionWithSlot(移动数据而不是克隆) pub fn into_transaction_with_slot(mut self) -> TransactionWithSlot { // 移动数据而不是克隆,避免多余的内存分配 - std::mem::replace(self.deref_mut(), TransactionWithSlot::default()) + std::mem::take(self.deref_mut()) } } diff --git a/src/streaming/yellowstone_grpc.rs b/src/streaming/yellowstone_grpc.rs index 3fdc1b7..d776571 100644 --- a/src/streaming/yellowstone_grpc.rs +++ b/src/streaming/yellowstone_grpc.rs @@ -66,6 +66,7 @@ impl YellowstoneGrpc { x_token: Option, config: StreamClientConfig, ) -> AnyResult { + sol_parser_sdk::warmup_parser(); let _ = rustls::crypto::ring::default_provider().install_default().ok(); let subscription_manager = SubscriptionManager::new(endpoint.clone(), x_token.clone(), config.clone()); @@ -133,6 +134,7 @@ impl YellowstoneGrpc { /// /// # Returns /// Returns `AnyResult<()>`, `Ok(())` on success, error information on failure + #[allow(clippy::too_many_arguments)] pub async fn subscribe_events_immediate( &self, protocols: Vec, diff --git a/src/streaming/yellowstone_sub_system.rs b/src/streaming/yellowstone_sub_system.rs index 26625ac..ab10bf7 100755 --- a/src/streaming/yellowstone_sub_system.rs +++ b/src/streaming/yellowstone_sub_system.rs @@ -16,6 +16,7 @@ use yellowstone_grpc_proto::geyser::{ const SYSTEM_PROGRAM_ID: Pubkey = pubkey!("11111111111111111111111111111111"); +#[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum SystemEvent { NewTransfer(TransferInfo), @@ -101,15 +102,12 @@ impl YellowstoneGrpc { where F: Fn(SystemEvent) + Send + Sync, { - match event_pretty { - EventPretty::Transaction(transaction_pretty) => { - callback(SystemEvent::NewTransfer(TransferInfo { - slot: transaction_pretty.slot, - signature: transaction_pretty.signature.to_string(), - tx: Some(transaction_pretty.grpc_tx), - })); - } - _ => {} + if let EventPretty::Transaction(transaction_pretty) = event_pretty { + callback(SystemEvent::NewTransfer(TransferInfo { + slot: transaction_pretty.slot, + signature: transaction_pretty.signature.to_string(), + tx: Some(transaction_pretty.grpc_tx), + })); } Ok(()) }