mirror of
https://github.com/0xfnzero/solana-streamer.git
synced 2026-07-27 17:37:45 +00:00
fix: add PumpFun quote case parser example
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-streamer-sdk"
|
||||
version = "1.5.14"
|
||||
version = "1.5.15"
|
||||
edition = "2021"
|
||||
authors = ["William <byteblock6@gmail.com>", "sgxiang <sgxiang@gmail.com>", "wei <1415121722@qq.com>"]
|
||||
repository = "https://github.com/0xfnzero/solana-streamer"
|
||||
@@ -21,7 +21,7 @@ sdk-perf-stats = ["sol-parser-sdk/perf-stats"]
|
||||
sdk-ultra-perf = ["sol-parser-sdk/ultra-perf"]
|
||||
|
||||
[dependencies]
|
||||
sol-parser-sdk = { version = "0.5.14", default-features = false }
|
||||
sol-parser-sdk = { git = "https://github.com/0xfnzero/sol-parser-sdk", rev = "4464880", version = "0.5.15", default-features = false }
|
||||
solana-sdk = "3.0.0"
|
||||
solana-client = "3.1.12"
|
||||
solana-transaction-status = "3.1.12"
|
||||
|
||||
@@ -124,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.14" }
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.15" }
|
||||
```
|
||||
|
||||
### Use crates.io
|
||||
|
||||
```toml
|
||||
# Add to your Cargo.toml
|
||||
solana-streamer-sdk = "1.5.14"
|
||||
solana-streamer-sdk = "1.5.15"
|
||||
```
|
||||
|
||||
Parser backend features:
|
||||
|
||||
```toml
|
||||
# Default: sol-parser-sdk parse-borsh backend
|
||||
solana-streamer-sdk = "1.5.14"
|
||||
solana-streamer-sdk = "1.5.15"
|
||||
|
||||
# Zero-copy parser backend for latency-sensitive bots
|
||||
solana-streamer-sdk = { version = "1.5.14", default-features = false, features = ["sdk-parse-zero-copy"] }
|
||||
solana-streamer-sdk = { version = "1.5.15", 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.14+` uses the zero-copy backend.
|
||||
If both `sdk-parse-borsh` and `sdk-parse-zero-copy` are enabled, `sol-parser-sdk 0.5.15+` uses the zero-copy backend.
|
||||
|
||||
## 🔄 Migration Guide
|
||||
|
||||
### Upgrading to v1.5.15
|
||||
|
||||
Version 1.5.15 tracks `sol-parser-sdk 0.5.15` at GitHub rev `4464880`. Pump.fun `create_v2` now distinguishes 16-account SOL-sentinel creates from 19-account quote-pool creates, and account filling selects the actual create/create_v2 instruction before reading quote fields.
|
||||
|
||||
### Upgrading to v1.5.14
|
||||
|
||||
Version 1.5.14 uses `sol-parser-sdk 0.5.14` from crates.io. Pump.fun canonical create events now expose `quote_mint`, `quote_vault`, and `quote_token_program` for `create_v2` quote pools, including USDC pools, across gRPC/RPC parser bridge and ShredStream-backed SDK output.
|
||||
@@ -350,6 +354,7 @@ grpc.subscribe_events_immediate(
|
||||
| Monitor transaction events using ShredStream | `cargo run --example shred_example` | [examples/shred_example.rs](examples/shred_example.rs) |
|
||||
| Parse Solana mainnet transaction data | `cargo run --example parse_tx_events` | [examples/parse_tx_events.rs](examples/parse_tx_events.rs) |
|
||||
| Parse PumpFun transaction from RPC (signature: `TX_SIGNATURE` or CLI arg) | `cargo run --example parse_pump_tx --release` | [examples/parse_pump_tx.rs](examples/parse_pump_tx.rs) |
|
||||
| Parse PumpFun quote-mint cases from RPC | `TX_SIGNATURES=<sig1,sig2> cargo run --example parse_pumpfun_quote_cases --release` | [examples/parse_pumpfun_quote_cases.rs](examples/parse_pumpfun_quote_cases.rs) |
|
||||
| Parse PumpSwap transaction from RPC | `cargo run --example parse_pumpswap_tx --release` | [examples/parse_pumpswap_tx.rs](examples/parse_pumpswap_tx.rs) |
|
||||
| Parse Meteora DAMM v2 transaction from RPC | `TX_SIGNATURE=<sig> cargo run --example parse_meteora_damm_tx --release` | [examples/parse_meteora_damm_tx.rs](examples/parse_meteora_damm_tx.rs) |
|
||||
| Debug PumpFun transaction (fetch, print meta/logs, parse) | `TX_SIGNATURE=<sig> cargo run --example debug_pump_tx --release` | [examples/debug_pump_tx.rs](examples/debug_pump_tx.rs) |
|
||||
|
||||
+10
-5
@@ -123,30 +123,34 @@ git clone https://github.com/0xfnzero/solana-streamer
|
||||
|
||||
```toml
|
||||
# 添加到您的 Cargo.toml
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.14" }
|
||||
solana-streamer-sdk = { path = "./solana-streamer", version = "1.5.15" }
|
||||
```
|
||||
|
||||
### 使用 crates.io
|
||||
|
||||
```toml
|
||||
# 添加到您的 Cargo.toml
|
||||
solana-streamer-sdk = "1.5.14"
|
||||
solana-streamer-sdk = "1.5.15"
|
||||
```
|
||||
|
||||
解析后端 feature:
|
||||
|
||||
```toml
|
||||
# 默认:sol-parser-sdk parse-borsh 后端
|
||||
solana-streamer-sdk = "1.5.14"
|
||||
solana-streamer-sdk = "1.5.15"
|
||||
|
||||
# 面向低延迟 Bot 的 zero-copy 解析后端
|
||||
solana-streamer-sdk = { version = "1.5.14", default-features = false, features = ["sdk-parse-zero-copy"] }
|
||||
solana-streamer-sdk = { version = "1.5.15", default-features = false, features = ["sdk-parse-zero-copy"] }
|
||||
```
|
||||
|
||||
如果同时启用 `sdk-parse-borsh` 和 `sdk-parse-zero-copy`,`sol-parser-sdk 0.5.14+` 会优先使用 zero-copy 后端。
|
||||
如果同时启用 `sdk-parse-borsh` 和 `sdk-parse-zero-copy`,`sol-parser-sdk 0.5.15+` 会优先使用 zero-copy 后端。
|
||||
|
||||
## 🔄 迁移指南
|
||||
|
||||
### 升级到 v1.5.15
|
||||
|
||||
v1.5.15 跟随 GitHub rev `4464880` 上的 `sol-parser-sdk 0.5.15`。Pump.fun `create_v2` 现在会区分 16 账户 SOL sentinel 创建和 19 账户 quote-pool 创建;填充账户时会先选择实际的 create/create_v2 指令,再读取 quote 字段。
|
||||
|
||||
### 升级到 v1.5.14
|
||||
|
||||
v1.5.14 使用 crates.io 上的 `sol-parser-sdk 0.5.14`。Pump.fun canonical create 事件现在会为 `create_v2` quote 池暴露 `quote_mint`、`quote_vault`、`quote_token_program`,包括 USDC 池;gRPC/RPC parser bridge 和 ShredStream-backed SDK 输出都会保留这些字段。
|
||||
@@ -349,6 +353,7 @@ grpc.subscribe_events_immediate(
|
||||
| 使用 ShredStream 监控交易事件 | `cargo run --example shred_example` | [examples/shred_example.rs](examples/shred_example.rs) |
|
||||
| 解析 Solana 主网交易数据 | `cargo run --example parse_tx_events` | [examples/parse_tx_events.rs](examples/parse_tx_events.rs) |
|
||||
| 从 RPC 解析 PumpFun 交易(签名:环境变量 `TX_SIGNATURE` 或 CLI 参数) | `cargo run --example parse_pump_tx --release` | [examples/parse_pump_tx.rs](examples/parse_pump_tx.rs) |
|
||||
| 从 RPC 解析 PumpFun quote_mint 边界案例 | `TX_SIGNATURES=<sig1,sig2> cargo run --example parse_pumpfun_quote_cases --release` | [examples/parse_pumpfun_quote_cases.rs](examples/parse_pumpfun_quote_cases.rs) |
|
||||
| 从 RPC 解析 PumpSwap 交易 | `cargo run --example parse_pumpswap_tx --release` | [examples/parse_pumpswap_tx.rs](examples/parse_pumpswap_tx.rs) |
|
||||
| 从 RPC 解析 Meteora DAMM v2 交易 | `TX_SIGNATURE=<sig> cargo run --example parse_meteora_damm_tx --release` | [examples/parse_meteora_damm_tx.rs](examples/parse_meteora_damm_tx.rs) |
|
||||
| 调试 PumpFun 交易(拉取、打印 meta/logs、解析) | `TX_SIGNATURE=<sig> cargo run --example debug_pump_tx --release` | [examples/debug_pump_tx.rs](examples/debug_pump_tx.rs) |
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
//! Parse Pump.fun quote-mint edge cases through solana-streamer's parser SDK re-export.
|
||||
//!
|
||||
//! Defaults cover:
|
||||
//! - 19-account `create_v2` with explicit WSOL quote mint.
|
||||
//! - 16-account `create_v2` with no quote mint account.
|
||||
//!
|
||||
//! Usage:
|
||||
//! ```bash
|
||||
//! cargo run --example parse_pumpfun_quote_cases --release
|
||||
//! SOLANA_RPC_URL=https://api.mainnet-beta.solana.com cargo run --example parse_pumpfun_quote_cases --release
|
||||
//! TX_SIGNATURES=sig1,sig2 cargo run --example parse_pumpfun_quote_cases --release
|
||||
//! ```
|
||||
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::Signature;
|
||||
use solana_streamer_sdk::parser_sdk::core::events::{
|
||||
DexEvent, PUMPFUN_SOLSCAN_SOL_QUOTE_MINT, PUMPFUN_WSOL_QUOTE_MINT,
|
||||
};
|
||||
use solana_streamer_sdk::parser_sdk::parse_transaction_from_rpc;
|
||||
use std::str::FromStr;
|
||||
|
||||
struct Case {
|
||||
name: &'static str,
|
||||
signature: &'static str,
|
||||
expected_create_v2_quote: Option<Pubkey>,
|
||||
}
|
||||
|
||||
fn default_cases() -> Vec<Case> {
|
||||
vec![
|
||||
Case {
|
||||
name: "19-account create_v2 explicit WSOL quote",
|
||||
signature: "4GCVgY2FnT1s4q5zemnPL4mzSbuhUTgQo9mc9jewhLZzsCXKe8ehz6xD4QDJE853CLrF6doJbf4JNwJVeEYLA4De",
|
||||
expected_create_v2_quote: Some(PUMPFUN_WSOL_QUOTE_MINT),
|
||||
},
|
||||
Case {
|
||||
name: "16-account create_v2 no quote account",
|
||||
signature: "H6azwLqtRtrnVNC5iwcjYM9idU3e9SRyLZXTwjfJGJxA4X7dZL7vyhFAJNvQy7bb6bmQNmFHUt1KkkPPmhdge3G",
|
||||
expected_create_v2_quote: Some(PUMPFUN_SOLSCAN_SOL_QUOTE_MINT),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn cases_from_env() -> Option<Vec<Case>> {
|
||||
let raw = std::env::var("TX_SIGNATURES").ok()?;
|
||||
let cases: Vec<Case> = raw
|
||||
.split(',')
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|signature| Case {
|
||||
name: "custom signature",
|
||||
signature: Box::leak(signature.to_string().into_boxed_str()),
|
||||
expected_create_v2_quote: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
if cases.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(cases)
|
||||
}
|
||||
}
|
||||
|
||||
fn print_event_summary(index: usize, event: &DexEvent) -> Option<Pubkey> {
|
||||
match event {
|
||||
DexEvent::PumpFunCreate(e) => {
|
||||
println!(
|
||||
" #{index} PumpFunCreate ix={} mint={} quote_mint={} token_program={} user={}",
|
||||
e.ix_name, e.mint, e.quote_mint, e.token_program, e.user
|
||||
);
|
||||
if e.ix_name == "create_v2" {
|
||||
Some(e.quote_mint)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
DexEvent::PumpFunCreateV2(e) => {
|
||||
println!(
|
||||
" #{index} PumpFunCreateV2 ix={} mint={} quote_mint={} token_program={} user={}",
|
||||
e.ix_name, e.mint, e.quote_mint, e.token_program, e.user
|
||||
);
|
||||
Some(e.quote_mint)
|
||||
}
|
||||
DexEvent::PumpFunBuy(e)
|
||||
| DexEvent::PumpFunBuyExactSolIn(e)
|
||||
| DexEvent::PumpFunSell(e)
|
||||
| DexEvent::PumpFunTrade(e) => {
|
||||
println!(
|
||||
" #{index} PumpFunTrade ix={} mint={} quote_mint={} quote_amount={} sol_amount={} token_amount={}",
|
||||
e.ix_name, e.mint, e.quote_mint, e.quote_amount, e.sol_amount, e.token_amount
|
||||
);
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rpc_url = std::env::var("SOLANA_RPC_URL")
|
||||
.unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string());
|
||||
let client = RpcClient::new(rpc_url.clone());
|
||||
let cases = cases_from_env().unwrap_or_else(default_cases);
|
||||
let mut failed = false;
|
||||
|
||||
println!("RPC: {rpc_url}");
|
||||
println!("Cases: {}\n", cases.len());
|
||||
|
||||
for case in cases {
|
||||
println!("=== {} ===", case.name);
|
||||
println!("signature={}", case.signature);
|
||||
|
||||
let signature = Signature::from_str(case.signature).expect("invalid signature");
|
||||
let events = match parse_transaction_from_rpc(&client, &signature, None) {
|
||||
Ok(events) => events,
|
||||
Err(err) => {
|
||||
eprintln!(" ERROR: {err}");
|
||||
failed = true;
|
||||
println!();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
println!(" events={}", events.len());
|
||||
let mut create_v2_quotes = Vec::new();
|
||||
for (i, event) in events.iter().enumerate() {
|
||||
if let Some(quote) = print_event_summary(i + 1, event) {
|
||||
create_v2_quotes.push(quote);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(expected) = case.expected_create_v2_quote {
|
||||
let ok = create_v2_quotes.contains(&expected);
|
||||
println!(
|
||||
" expected_create_v2_quote={} result={}",
|
||||
expected,
|
||||
if ok { "ok" } else { "FAIL" }
|
||||
);
|
||||
failed |= !ok;
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
if failed {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user