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:
ysq
2025-08-03 21:59:08 +08:00
parent 4c90931e28
commit 109c50cf06
8 changed files with 356 additions and 100 deletions
+1 -1
View File
@@ -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"
+8 -2
View File
@@ -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
View File
@@ -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);
},
+6
View File
@@ -0,0 +1,6 @@
max_width = 100
hard_tabs = false
tab_spaces = 4
edition = "2021"
use_small_heuristics = "Max"
newline_style = "Unix"
+15 -10
View File
@@ -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:?}");
},
+26 -22
View File
@@ -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()
}))
}
}