mirror of
https://github.com/0xfnzero/solana-streamer.git
synced 2026-07-27 17:37:45 +00:00
feat: add Bonk migration events and bump to v0.1.9
- Add BonkMigrateToAmmEvent and BonkMigrateToCpswapEvent - Update parsers and event handlers - Add rustfmt.toml configuration - Update documentation and examples
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-streamer-sdk"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
edition = "2021"
|
||||
authors = ["William <byteblock6@gmail.com>", "sgxiang <sgxiang@gmail.com>", "wei <1415121722@qq.com>"]
|
||||
repository = "https://github.com/0xfnzero/solana-streamer"
|
||||
|
||||
@@ -36,14 +36,14 @@ Add the dependency to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
# Add to your Cargo.toml
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "0.1.8" }
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "0.1.9" }
|
||||
```
|
||||
|
||||
### Use crates.io
|
||||
|
||||
```toml
|
||||
# Add to your Cargo.toml
|
||||
solana-streamer-sdk = "0.1.8"
|
||||
solana-streamer-sdk = "0.1.9"
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
@@ -177,6 +177,12 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
|
||||
BonkTradeEvent => |e: BonkTradeEvent| {
|
||||
println!("BonkTradeEvent: {:?}", e);
|
||||
},
|
||||
BonkMigrateToAmmEvent => |e: BonkMigrateToAmmEvent| {
|
||||
println!("BonkMigrateToAmmEvent: {e:?}");
|
||||
},
|
||||
BonkMigrateToCpswapEvent => |e: BonkMigrateToCpswapEvent| {
|
||||
println!("BonkMigrateToCpswapEvent: {e:?}");
|
||||
},
|
||||
PumpFunTradeEvent => |e: PumpFunTradeEvent| {
|
||||
println!("PumpFunTradeEvent: {:?}", e);
|
||||
},
|
||||
|
||||
+8
-2
@@ -36,14 +36,14 @@ git clone https://github.com/0xfnzero/solana-streamer
|
||||
|
||||
```toml
|
||||
# 添加到您的 Cargo.toml
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "0.1.8" }
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "0.1.9" }
|
||||
```
|
||||
|
||||
### 使用 crates.io
|
||||
|
||||
```toml
|
||||
# 添加到您的 Cargo.toml
|
||||
solana-streamer-sdk = "0.1.8"
|
||||
solana-streamer-sdk = "0.1.9"
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
@@ -162,6 +162,12 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
|
||||
BonkTradeEvent => |e: BonkTradeEvent| {
|
||||
println!("BonkTradeEvent: {:?}", e);
|
||||
},
|
||||
BonkMigrateToAmmEvent => |e: BonkMigrateToAmmEvent| {
|
||||
println!("BonkMigrateToAmmEvent: {e:?}");
|
||||
},
|
||||
BonkMigrateToCpswapEvent => |e: BonkMigrateToCpswapEvent| {
|
||||
println!("BonkMigrateToCpswapEvent: {e:?}");
|
||||
},
|
||||
PumpFunTradeEvent => |e: PumpFunTradeEvent| {
|
||||
println!("PumpFunTradeEvent: {:?}", e);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
max_width = 100
|
||||
hard_tabs = false
|
||||
tab_spaces = 4
|
||||
edition = "2021"
|
||||
use_small_heuristics = "Max"
|
||||
newline_style = "Unix"
|
||||
+15
-10
@@ -3,7 +3,10 @@ use solana_streamer_sdk::{
|
||||
streaming::{
|
||||
event_parser::{
|
||||
protocols::{
|
||||
bonk::{parser::BONK_PROGRAM_ID, BonkPoolCreateEvent, BonkTradeEvent},
|
||||
bonk::{
|
||||
parser::BONK_PROGRAM_ID, BonkMigrateToAmmEvent, BonkMigrateToCpswapEvent,
|
||||
BonkPoolCreateEvent, BonkTradeEvent,
|
||||
},
|
||||
pumpfun::{parser::PUMPFUN_PROGRAM_ID, PumpFunCreateTokenEvent, PumpFunTradeEvent},
|
||||
pumpswap::{
|
||||
parser::PUMPSWAP_PROGRAM_ID, PumpSwapBuyEvent, PumpSwapCreatePoolEvent,
|
||||
@@ -66,9 +69,9 @@ async fn test_grpc() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
println!("Starting to listen for events, press Ctrl+C to stop...");
|
||||
println!("Monitoring programs: {:?}", account_include);
|
||||
|
||||
|
||||
println!("Starting subscription...");
|
||||
|
||||
|
||||
grpc.subscribe_events_v2(
|
||||
protocols,
|
||||
None,
|
||||
@@ -87,10 +90,8 @@ async fn test_shreds() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Subscribing to ShredStream events...");
|
||||
|
||||
// enable_metrics 为 true 时,会打印性能指标
|
||||
let shred_stream = ShredStreamGrpc::new_with_config(
|
||||
"http://127.0.0.1:10800".to_string(),
|
||||
true,
|
||||
).await?;
|
||||
let shred_stream =
|
||||
ShredStreamGrpc::new_with_config("http://127.0.0.1:10800".to_string(), true).await?;
|
||||
|
||||
let callback = create_event_callback();
|
||||
let protocols = vec![
|
||||
@@ -102,9 +103,7 @@ async fn test_shreds() -> Result<(), Box<dyn std::error::Error>> {
|
||||
];
|
||||
|
||||
println!("Listening for events, press Ctrl+C to stop...");
|
||||
shred_stream
|
||||
.shredstream_subscribe(protocols, None, callback)
|
||||
.await?;
|
||||
shred_stream.shredstream_subscribe(protocols, None, callback).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -121,6 +120,12 @@ fn create_event_callback() -> impl Fn(Box<dyn UnifiedEvent>) {
|
||||
BonkTradeEvent => |e: BonkTradeEvent| {
|
||||
println!("BonkTradeEvent: {e:?}");
|
||||
},
|
||||
BonkMigrateToAmmEvent => |e: BonkMigrateToAmmEvent| {
|
||||
println!("BonkMigrateToAmmEvent: {e:?}");
|
||||
},
|
||||
BonkMigrateToCpswapEvent => |e: BonkMigrateToCpswapEvent| {
|
||||
println!("BonkMigrateToCpswapEvent: {e:?}");
|
||||
},
|
||||
PumpFunTradeEvent => |e: PumpFunTradeEvent| {
|
||||
println!("PumpFunTradeEvent: {e:?}");
|
||||
},
|
||||
|
||||
@@ -5,11 +5,11 @@ use solana_transaction_status::UiInstruction;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
// 对象池大小配置
|
||||
// Object pool size configuration
|
||||
const EVENT_METADATA_POOL_SIZE: usize = 1000;
|
||||
const TRANSFER_DATA_POOL_SIZE: usize = 2000;
|
||||
|
||||
/// 事件元数据对象池
|
||||
/// Event metadata object pool
|
||||
pub struct EventMetadataPool {
|
||||
pool: Arc<Mutex<Vec<EventMetadata>>>,
|
||||
}
|
||||
@@ -40,7 +40,7 @@ impl EventMetadataPool {
|
||||
}
|
||||
}
|
||||
|
||||
/// 传输数据对象池
|
||||
/// Transfer data object pool
|
||||
pub struct TransferDataPool {
|
||||
pool: Arc<Mutex<Vec<TransferData>>>,
|
||||
}
|
||||
@@ -71,7 +71,7 @@ impl TransferDataPool {
|
||||
}
|
||||
}
|
||||
|
||||
// 全局对象池实例
|
||||
// Global object pool instances
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref EVENT_METADATA_POOL: EventMetadataPool = EventMetadataPool::new();
|
||||
pub static ref TRANSFER_DATA_POOL: TransferDataPool = TransferDataPool::new();
|
||||
@@ -90,12 +90,12 @@ pub enum ProtocolType {
|
||||
SDKSystem,
|
||||
}
|
||||
|
||||
/// 事件类型枚举
|
||||
/// Event type enumeration
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||
)]
|
||||
pub enum EventType {
|
||||
// PumpSwap 事件
|
||||
// PumpSwap events
|
||||
#[default]
|
||||
PumpSwapBuy,
|
||||
PumpSwapSell,
|
||||
@@ -103,27 +103,29 @@ pub enum EventType {
|
||||
PumpSwapDeposit,
|
||||
PumpSwapWithdraw,
|
||||
|
||||
// PumpFun 事件
|
||||
// PumpFun events
|
||||
PumpFunCreateToken,
|
||||
PumpFunBuy,
|
||||
PumpFunSell,
|
||||
|
||||
// Bonk 事件
|
||||
// Bonk events
|
||||
BonkBuyExactIn,
|
||||
BonkBuyExactOut,
|
||||
BonkSellExactIn,
|
||||
BonkSellExactOut,
|
||||
BonkInitialize,
|
||||
BonkMigrateToAmm,
|
||||
BonkMigrateToCpswap,
|
||||
|
||||
// Raydium CPMM 事件
|
||||
// Raydium CPMM events
|
||||
RaydiumCpmmSwapBaseInput,
|
||||
RaydiumCpmmSwapBaseOutput,
|
||||
|
||||
// Raydium CLMM 事件
|
||||
// Raydium CLMM events
|
||||
RaydiumClmmSwap,
|
||||
RaydiumClmmSwapV2,
|
||||
|
||||
// 通用事件
|
||||
// Common events
|
||||
SDKSystem,
|
||||
Unknown,
|
||||
}
|
||||
@@ -145,6 +147,8 @@ impl EventType {
|
||||
EventType::BonkSellExactIn => "BonkSellExactIn".to_string(),
|
||||
EventType::BonkSellExactOut => "BonkSellExactOut".to_string(),
|
||||
EventType::BonkInitialize => "BonkInitialize".to_string(),
|
||||
EventType::BonkMigrateToAmm => "BonkMigrateToAmm".to_string(),
|
||||
EventType::BonkMigrateToCpswap => "BonkMigrateToCpswap".to_string(),
|
||||
EventType::RaydiumCpmmSwapBaseInput => "RaydiumCpmmSwapBaseInput".to_string(),
|
||||
EventType::RaydiumCpmmSwapBaseOutput => "RaydiumCpmmSwapBaseOutput".to_string(),
|
||||
EventType::RaydiumClmmSwap => "RaydiumClmmSwap".to_string(),
|
||||
@@ -155,7 +159,7 @@ impl EventType {
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析结果
|
||||
/// Parse result
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParseResult<T> {
|
||||
pub success: bool,
|
||||
@@ -189,7 +193,7 @@ impl<T> ParseResult<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 协议信息
|
||||
/// Protocol information
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ProtocolInfo {
|
||||
pub name: String,
|
||||
@@ -206,7 +210,7 @@ impl ProtocolInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// 交易数据
|
||||
/// Transfer data
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||
)]
|
||||
@@ -220,7 +224,7 @@ pub struct TransferData {
|
||||
pub mint: Option<Pubkey>,
|
||||
}
|
||||
|
||||
/// 事件元数据
|
||||
/// Event metadata
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||
)]
|
||||
@@ -264,12 +268,12 @@ impl EventMetadata {
|
||||
protocol,
|
||||
event_type,
|
||||
program_id,
|
||||
transfer_datas: Vec::with_capacity(4), // 预分配容量
|
||||
transfer_datas: Vec::with_capacity(4), // Pre-allocate capacity
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用对象池创建EventMetadata
|
||||
/// Create EventMetadata using object pool
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn new_with_pool(
|
||||
id: String,
|
||||
@@ -283,7 +287,7 @@ impl EventMetadata {
|
||||
index: String,
|
||||
program_received_time_ms: i64,
|
||||
) -> Self {
|
||||
// 尝试从对象池获取
|
||||
// Try to get from object pool
|
||||
if let Some(mut metadata) = EVENT_METADATA_POOL.acquire().await {
|
||||
metadata.id = id;
|
||||
metadata.signature = signature;
|
||||
@@ -300,7 +304,7 @@ impl EventMetadata {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// 如果对象池为空,创建新的
|
||||
// If object pool is empty, create new one
|
||||
Self::new(
|
||||
id,
|
||||
signature,
|
||||
@@ -323,13 +327,13 @@ impl EventMetadata {
|
||||
self.transfer_datas = transfer_datas;
|
||||
}
|
||||
|
||||
/// 回收EventMetadata到对象池
|
||||
/// Recycle EventMetadata to object pool
|
||||
pub async fn recycle(self) {
|
||||
EVENT_METADATA_POOL.release(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析接下来指令中的token转账数据
|
||||
/// Parse token transfer data from next instructions
|
||||
pub fn parse_transfer_datas_from_next_instructions(
|
||||
inner_instruction: &solana_transaction_status::UiInnerInstructions,
|
||||
current_index: i8,
|
||||
@@ -355,7 +359,7 @@ pub fn parse_transfer_datas_from_next_instructions(
|
||||
return vec![];
|
||||
}
|
||||
let mut transfer_datas = vec![];
|
||||
// 获取当前指令之后的两个指令
|
||||
// Get the next two instructions after the current instruction
|
||||
let next_instructions: Vec<&UiInstruction> = inner_instruction
|
||||
.instructions
|
||||
.iter()
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use crate::impl_unified_event;
|
||||
use crate::streaming::event_parser::common::EventMetadata;
|
||||
use crate::streaming::event_parser::protocols::bonk::types::{
|
||||
CurveParams, MintParams, PoolStatus, TradeDirection, VestingParams,
|
||||
};
|
||||
use crate::streaming::event_parser::common::EventMetadata;
|
||||
use crate::impl_unified_event;
|
||||
use borsh::BorshDeserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
/// 买入事件
|
||||
/// Trade event
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct BonkTradeEvent {
|
||||
#[borsh(skip)]
|
||||
@@ -53,7 +53,7 @@ pub struct BonkTradeEvent {
|
||||
pub is_bot: bool,
|
||||
}
|
||||
|
||||
// 使用宏生成UnifiedEvent实现,指定需要合并的字段
|
||||
// Macro to generate UnifiedEvent implementation, specifying the fields to be merged
|
||||
impl_unified_event!(
|
||||
BonkTradeEvent,
|
||||
pool_state,
|
||||
@@ -73,7 +73,7 @@ impl_unified_event!(
|
||||
pool_status
|
||||
);
|
||||
|
||||
/// 创建池事件
|
||||
/// Create pool event
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct BonkPoolCreateEvent {
|
||||
#[borsh(skip)]
|
||||
@@ -100,7 +100,7 @@ pub struct BonkPoolCreateEvent {
|
||||
pub platform_config: Pubkey,
|
||||
}
|
||||
|
||||
// 使用宏生成UnifiedEvent实现,指定需要合并的字段
|
||||
// Macro to generate UnifiedEvent implementation, specifying the fields to be merged
|
||||
impl_unified_event!(
|
||||
BonkPoolCreateEvent,
|
||||
pool_state,
|
||||
@@ -111,16 +111,138 @@ impl_unified_event!(
|
||||
vesting_param
|
||||
);
|
||||
|
||||
/// 事件鉴别器常量
|
||||
/// Create pool event
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct BonkMigrateToAmmEvent {
|
||||
#[borsh(skip)]
|
||||
pub metadata: EventMetadata,
|
||||
pub base_lot_size: u64,
|
||||
pub quote_lot_size: u64,
|
||||
pub market_vault_signer_nonce: u8,
|
||||
#[borsh(skip)]
|
||||
pub payer: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub base_mint: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub quote_mint: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub openbook_program: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub market: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub request_queue: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub event_queue: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub bids: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub asks: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub market_vault_signer: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub market_base_vault: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub market_quote_vault: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_program: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_pool: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_authority: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_open_orders: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_lp_mint: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_base_vault: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_quote_vault: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_target_orders: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_config: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub amm_create_fee_destination: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub authority: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub pool_state: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub global_config: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub base_vault: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub quote_vault: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub pool_lp_token: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub spl_token_program: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub associated_token_program: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub system_program: Pubkey,
|
||||
#[borsh(skip)]
|
||||
pub rent_program: Pubkey,
|
||||
}
|
||||
|
||||
// Macro to generate UnifiedEvent implementation, specifying the fields to be merged
|
||||
impl_unified_event!(
|
||||
BonkMigrateToAmmEvent,
|
||||
base_lot_size,
|
||||
quote_lot_size,
|
||||
market_vault_signer_nonce
|
||||
);
|
||||
|
||||
// Migrate to CP Swap event
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct BonkMigrateToCpswapEvent {
|
||||
pub metadata: EventMetadata,
|
||||
pub payer: Pubkey,
|
||||
pub base_mint: Pubkey,
|
||||
pub quote_mint: Pubkey,
|
||||
pub platform_config: Pubkey,
|
||||
pub cpswap_program: Pubkey,
|
||||
pub cpswap_pool: Pubkey,
|
||||
pub cpswap_authority: Pubkey,
|
||||
pub cpswap_lp_mint: Pubkey,
|
||||
pub cpswap_base_vault: Pubkey,
|
||||
pub cpswap_quote_vault: Pubkey,
|
||||
pub cpswap_config: Pubkey,
|
||||
pub cpswap_create_pool_fee: Pubkey,
|
||||
pub cpswap_observation: Pubkey,
|
||||
pub lock_program: Pubkey,
|
||||
pub lock_authority: Pubkey,
|
||||
pub lock_lp_vault: Pubkey,
|
||||
pub authority: Pubkey,
|
||||
pub pool_state: Pubkey,
|
||||
pub global_config: Pubkey,
|
||||
pub base_vault: Pubkey,
|
||||
pub quote_vault: Pubkey,
|
||||
pub pool_lp_token: Pubkey,
|
||||
pub base_token_program: Pubkey,
|
||||
pub quote_token_program: Pubkey,
|
||||
pub associated_token_program: Pubkey,
|
||||
pub system_program: Pubkey,
|
||||
pub rent_program: Pubkey,
|
||||
pub metadata_program: Pubkey,
|
||||
pub remaining_accounts: Vec<Pubkey>,
|
||||
}
|
||||
|
||||
// Macro to generate UnifiedEvent implementation, specifying the fields to be merged
|
||||
impl_unified_event!(BonkMigrateToCpswapEvent,);
|
||||
|
||||
/// Event discriminator constants
|
||||
pub mod discriminators {
|
||||
// 事件鉴别器
|
||||
// Event discriminators
|
||||
pub const TRADE_EVENT: &str = "0xe445a52e51cb9a1dbddb7fd34ee661ee";
|
||||
pub const POOL_CREATE_EVENT: &str = "0xe445a52e51cb9a1d97d7e20976a173ae";
|
||||
|
||||
// 指令鉴别器
|
||||
// Instruction discriminators
|
||||
pub const BUY_EXACT_IN: &[u8] = &[250, 234, 13, 123, 213, 156, 19, 236];
|
||||
pub const BUY_EXACT_OUT: &[u8] = &[24, 211, 116, 40, 105, 3, 153, 56];
|
||||
pub const SELL_EXACT_IN: &[u8] = &[149, 39, 222, 155, 211, 124, 152, 26];
|
||||
pub const SELL_EXACT_OUT: &[u8] = &[95, 200, 71, 34, 8, 9, 11, 166];
|
||||
pub const INITIALIZE: &[u8] = &[175, 175, 109, 31, 13, 152, 155, 237];
|
||||
pub const MIGRATE_TO_AMM: &[u8] = &[207, 82, 192, 145, 254, 207, 145, 223];
|
||||
pub const MIGRATE_TO_CP_SWAP: &[u8] = &[136, 92, 200, 103, 28, 218, 144, 140];
|
||||
}
|
||||
|
||||
@@ -6,16 +6,17 @@ use crate::streaming::event_parser::{
|
||||
common::{utils::*, EventMetadata, EventType, ProtocolType},
|
||||
core::traits::{EventParser, GenericEventParseConfig, GenericEventParser, UnifiedEvent},
|
||||
protocols::bonk::{
|
||||
discriminators, BonkPoolCreateEvent, BonkTradeEvent, ConstantCurve, CurveParams,
|
||||
FixedCurve, LinearCurve, MintParams, TradeDirection, VestingParams,
|
||||
discriminators, BonkMigrateToAmmEvent, BonkMigrateToCpswapEvent, BonkPoolCreateEvent,
|
||||
BonkTradeEvent, ConstantCurve, CurveParams, FixedCurve, LinearCurve, MintParams,
|
||||
TradeDirection, VestingParams,
|
||||
},
|
||||
};
|
||||
|
||||
/// Bonk程序ID
|
||||
/// Bonk Program ID
|
||||
pub const BONK_PROGRAM_ID: Pubkey =
|
||||
solana_sdk::pubkey!("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj");
|
||||
|
||||
/// Bonk事件解析器
|
||||
/// Bonk Event Parser
|
||||
pub struct BonkEventParser {
|
||||
inner: GenericEventParser,
|
||||
}
|
||||
@@ -28,7 +29,7 @@ impl Default for BonkEventParser {
|
||||
|
||||
impl BonkEventParser {
|
||||
pub fn new() -> Self {
|
||||
// 配置所有事件类型
|
||||
// Configure all event types
|
||||
let configs = vec![
|
||||
GenericEventParseConfig {
|
||||
inner_instruction_discriminator: discriminators::TRADE_EVENT,
|
||||
@@ -65,6 +66,20 @@ impl BonkEventParser {
|
||||
inner_instruction_parser: Self::parse_pool_create_inner_instruction,
|
||||
instruction_parser: Self::parse_initialize_instruction,
|
||||
},
|
||||
GenericEventParseConfig {
|
||||
inner_instruction_discriminator: "",
|
||||
instruction_discriminator: discriminators::MIGRATE_TO_AMM,
|
||||
event_type: EventType::BonkMigrateToAmm,
|
||||
inner_instruction_parser: Self::parse_migrate_to_amm_inner_instruction,
|
||||
instruction_parser: Self::parse_migrate_to_amm_instruction,
|
||||
},
|
||||
GenericEventParseConfig {
|
||||
inner_instruction_discriminator: "",
|
||||
instruction_discriminator: discriminators::MIGRATE_TO_CP_SWAP,
|
||||
event_type: EventType::BonkMigrateToCpswap,
|
||||
inner_instruction_parser: Self::parse_migrate_to_cpswap_inner_instruction,
|
||||
instruction_parser: Self::parse_migrate_to_cpswap_instruction,
|
||||
},
|
||||
];
|
||||
|
||||
let inner = GenericEventParser::new(BONK_PROGRAM_ID, ProtocolType::Bonk, configs);
|
||||
@@ -72,7 +87,7 @@ impl BonkEventParser {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// 解析创建池事件
|
||||
/// Parse pool creation event
|
||||
fn parse_pool_create_inner_instruction(
|
||||
data: &[u8],
|
||||
metadata: EventMetadata,
|
||||
@@ -80,27 +95,36 @@ impl BonkEventParser {
|
||||
if let Ok(event) = borsh::from_slice::<BonkPoolCreateEvent>(data) {
|
||||
let mut metadata = metadata;
|
||||
metadata.set_id(metadata.signature.to_string());
|
||||
Some(Box::new(BonkPoolCreateEvent {
|
||||
metadata,
|
||||
..event
|
||||
}))
|
||||
Some(Box::new(BonkPoolCreateEvent { metadata, ..event }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析交易事件
|
||||
/// Parse migrate to AMM event
|
||||
fn parse_migrate_to_amm_inner_instruction(
|
||||
_data: &[u8],
|
||||
_metadata: EventMetadata,
|
||||
) -> Option<Box<dyn UnifiedEvent>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Parse migrate to CP Swap event
|
||||
fn parse_migrate_to_cpswap_inner_instruction(
|
||||
_data: &[u8],
|
||||
_metadata: EventMetadata,
|
||||
) -> Option<Box<dyn UnifiedEvent>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Parse trade event
|
||||
fn parse_trade_inner_instruction(
|
||||
data: &[u8],
|
||||
metadata: EventMetadata,
|
||||
) -> Option<Box<dyn UnifiedEvent>> {
|
||||
if let Ok(event) = borsh::from_slice::<BonkTradeEvent>(data) {
|
||||
let mut metadata = metadata;
|
||||
metadata.set_id(format!(
|
||||
"{}-{}",
|
||||
metadata.signature,
|
||||
event.pool_state
|
||||
));
|
||||
metadata.set_id(format!("{}-{}", metadata.signature, event.pool_state));
|
||||
if metadata.event_type == EventType::BonkBuyExactIn
|
||||
|| metadata.event_type == EventType::BonkBuyExactOut
|
||||
{
|
||||
@@ -109,19 +133,17 @@ impl BonkEventParser {
|
||||
}
|
||||
} else if (metadata.event_type == EventType::BonkSellExactIn
|
||||
|| metadata.event_type == EventType::BonkSellExactOut)
|
||||
&& event.trade_direction != TradeDirection::Sell {
|
||||
return None;
|
||||
}
|
||||
Some(Box::new(BonkTradeEvent {
|
||||
metadata,
|
||||
..event
|
||||
}))
|
||||
&& event.trade_direction != TradeDirection::Sell
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(Box::new(BonkTradeEvent { metadata, ..event }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析买入指令事件
|
||||
/// Parse buy instruction event
|
||||
fn parse_buy_exact_in_instruction(
|
||||
data: &[u8],
|
||||
accounts: &[Pubkey],
|
||||
@@ -258,7 +280,7 @@ impl BonkEventParser {
|
||||
}))
|
||||
}
|
||||
|
||||
/// 解析初始化事件
|
||||
/// Parse initialize event
|
||||
fn parse_initialize_instruction(
|
||||
data: &[u8],
|
||||
accounts: &[Pubkey],
|
||||
@@ -294,13 +316,13 @@ impl BonkEventParser {
|
||||
}))
|
||||
}
|
||||
|
||||
/// 解析 MintParams 结构
|
||||
/// Parse MintParams structure
|
||||
fn parse_mint_params(data: &[u8], offset: &mut usize) -> Option<MintParams> {
|
||||
// 读取decimals (1字节)
|
||||
// Read decimals (1 byte)
|
||||
let decimals = read_u8(data, *offset)?;
|
||||
*offset += 1;
|
||||
|
||||
// 读取name字符串长度和内容
|
||||
// Read name string length and content
|
||||
let name_len = read_u32_le(data, *offset)? as usize;
|
||||
*offset += 4;
|
||||
if data.len() < *offset + name_len {
|
||||
@@ -309,7 +331,7 @@ impl BonkEventParser {
|
||||
let name = String::from_utf8(data[*offset..*offset + name_len].to_vec()).ok()?;
|
||||
*offset += name_len;
|
||||
|
||||
// 读取symbol字符串长度和内容
|
||||
// Read symbol string length and content
|
||||
let symbol_len = read_u32_le(data, *offset)? as usize;
|
||||
*offset += 4;
|
||||
if data.len() < *offset + symbol_len {
|
||||
@@ -318,7 +340,7 @@ impl BonkEventParser {
|
||||
let symbol = String::from_utf8(data[*offset..*offset + symbol_len].to_vec()).ok()?;
|
||||
*offset += symbol_len;
|
||||
|
||||
// 读取uri字符串长度和内容
|
||||
// Read uri string length and content
|
||||
let uri_len = read_u32_le(data, *offset)? as usize;
|
||||
*offset += 4;
|
||||
if data.len() < *offset + uri_len {
|
||||
@@ -327,17 +349,12 @@ impl BonkEventParser {
|
||||
let uri = String::from_utf8(data[*offset..*offset + uri_len].to_vec()).ok()?;
|
||||
*offset += uri_len;
|
||||
|
||||
Some(MintParams {
|
||||
decimals,
|
||||
name,
|
||||
symbol,
|
||||
uri,
|
||||
})
|
||||
Some(MintParams { decimals, name, symbol, uri })
|
||||
}
|
||||
|
||||
/// 解析 CurveParams 结构
|
||||
/// Parse CurveParams structure
|
||||
fn parse_curve_params(data: &[u8], offset: &mut usize) -> Option<CurveParams> {
|
||||
// 读取curve类型标识符 (1字节)
|
||||
// Read curve type identifier (1 byte)
|
||||
let curve_type = read_u8(data, *offset)?;
|
||||
*offset += 1;
|
||||
|
||||
@@ -372,11 +389,7 @@ impl BonkEventParser {
|
||||
*offset += 1;
|
||||
|
||||
Some(CurveParams::Fixed {
|
||||
data: FixedCurve {
|
||||
supply,
|
||||
total_quote_fund_raising,
|
||||
migrate_type,
|
||||
},
|
||||
data: FixedCurve { supply, total_quote_fund_raising, migrate_type },
|
||||
})
|
||||
}
|
||||
2 => {
|
||||
@@ -389,18 +402,14 @@ impl BonkEventParser {
|
||||
*offset += 1;
|
||||
|
||||
Some(CurveParams::Linear {
|
||||
data: LinearCurve {
|
||||
supply,
|
||||
total_quote_fund_raising,
|
||||
migrate_type,
|
||||
},
|
||||
data: LinearCurve { supply, total_quote_fund_raising, migrate_type },
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析 VestingParams 结构
|
||||
/// Parse VestingParams structure
|
||||
fn parse_vesting_params(data: &[u8], offset: &mut usize) -> Option<VestingParams> {
|
||||
let total_locked_amount = read_u64_le(data, *offset)?;
|
||||
*offset += 8;
|
||||
@@ -409,11 +418,109 @@ impl BonkEventParser {
|
||||
let unlock_period = read_u64_le(data, *offset)?;
|
||||
*offset += 8;
|
||||
|
||||
Some(VestingParams {
|
||||
total_locked_amount,
|
||||
cliff_period,
|
||||
unlock_period,
|
||||
})
|
||||
Some(VestingParams { total_locked_amount, cliff_period, unlock_period })
|
||||
}
|
||||
|
||||
/// Parse migrate to AMM event
|
||||
fn parse_migrate_to_amm_instruction(
|
||||
data: &[u8],
|
||||
accounts: &[Pubkey],
|
||||
metadata: EventMetadata,
|
||||
) -> Option<Box<dyn UnifiedEvent>> {
|
||||
if data.len() < 16 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let base_lot_size = u64::from_le_bytes(data[0..8].try_into().unwrap());
|
||||
let quote_lot_size = u64::from_le_bytes(data[8..16].try_into().unwrap());
|
||||
let market_vault_signer_nonce = data[16];
|
||||
|
||||
let mut metadata = metadata;
|
||||
metadata.set_id(metadata.signature.to_string());
|
||||
|
||||
Some(Box::new(BonkMigrateToAmmEvent {
|
||||
metadata,
|
||||
base_lot_size,
|
||||
quote_lot_size,
|
||||
market_vault_signer_nonce,
|
||||
payer: accounts[0],
|
||||
base_mint: accounts[1],
|
||||
quote_mint: accounts[2],
|
||||
openbook_program: accounts[3],
|
||||
market: accounts[4],
|
||||
request_queue: accounts[5],
|
||||
event_queue: accounts[6],
|
||||
bids: accounts[7],
|
||||
asks: accounts[8],
|
||||
market_vault_signer: accounts[9],
|
||||
market_base_vault: accounts[10],
|
||||
market_quote_vault: accounts[11],
|
||||
amm_program: accounts[12],
|
||||
amm_pool: accounts[13],
|
||||
amm_authority: accounts[14],
|
||||
amm_open_orders: accounts[15],
|
||||
amm_lp_mint: accounts[16],
|
||||
amm_base_vault: accounts[17],
|
||||
amm_quote_vault: accounts[18],
|
||||
amm_target_orders: accounts[19],
|
||||
amm_config: accounts[20],
|
||||
amm_create_fee_destination: accounts[21],
|
||||
authority: accounts[22],
|
||||
pool_state: accounts[23],
|
||||
global_config: accounts[24],
|
||||
base_vault: accounts[25],
|
||||
quote_vault: accounts[26],
|
||||
pool_lp_token: accounts[27],
|
||||
spl_token_program: accounts[28],
|
||||
associated_token_program: accounts[29],
|
||||
system_program: accounts[30],
|
||||
rent_program: accounts[31],
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parse migrate to CP Swap event
|
||||
fn parse_migrate_to_cpswap_instruction(
|
||||
_data: &[u8],
|
||||
accounts: &[Pubkey],
|
||||
metadata: EventMetadata,
|
||||
) -> Option<Box<dyn UnifiedEvent>> {
|
||||
let mut metadata = metadata;
|
||||
metadata.set_id(metadata.signature.to_string());
|
||||
|
||||
Some(Box::new(BonkMigrateToCpswapEvent {
|
||||
metadata,
|
||||
payer: accounts[0],
|
||||
base_mint: accounts[1],
|
||||
quote_mint: accounts[2],
|
||||
platform_config: accounts[3],
|
||||
cpswap_program: accounts[4],
|
||||
cpswap_pool: accounts[5],
|
||||
cpswap_authority: accounts[6],
|
||||
cpswap_lp_mint: accounts[7],
|
||||
cpswap_base_vault: accounts[8],
|
||||
cpswap_quote_vault: accounts[9],
|
||||
cpswap_config: accounts[10],
|
||||
cpswap_create_pool_fee: accounts[11],
|
||||
cpswap_observation: accounts[12],
|
||||
lock_program: accounts[13],
|
||||
lock_authority: accounts[14],
|
||||
lock_lp_vault: accounts[15],
|
||||
authority: accounts[16],
|
||||
pool_state: accounts[17],
|
||||
global_config: accounts[18],
|
||||
base_vault: accounts[19],
|
||||
quote_vault: accounts[20],
|
||||
pool_lp_token: accounts[21],
|
||||
base_token_program: accounts[22],
|
||||
quote_token_program: accounts[23],
|
||||
associated_token_program: accounts[24],
|
||||
system_program: accounts[25],
|
||||
rent_program: accounts[26],
|
||||
metadata_program: accounts[27],
|
||||
remaining_accounts: accounts[28..].to_vec(),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user