閱讀時間 19 分鐘
概覽
本指南將使用 Rust 建置一個即時 Jupiter 限價單監控工具,方法是 Solana gRPC (Yellowstone GeysergRPC) 以及 Vixen,這是一個基於 Rust 的Solana 解析工具包。該應用程式streams 限價單交易,並以人可讀的代幣金額和代號,記錄下單、成交及取消的紀錄。在此過程中,本指南將示範 Vixen v0.6.1 的三項功能:透過程序宏(proc-macro)基於 IDL 進行解析器程式碼生成,以及 失敗 欄位在 TransactionPrefilter 用於篩除失敗的交易,以及用於可觀察性的結構化追蹤。
- 使用Solana gRPC Vixen,以 Rust 語言建置一個即時 Jupiter 限價單 v2 監控工具
- 利用 Vixen 的 功能,直接從 Jupiter 限價單 IDL 產生類型安全的解析器
include_vixen_parser!程序宏 - 僅串流使用 Vixen v0.6.1 的已確認(未失敗)交易
TransactionPrefilter - 使用易於人讀取的代碼符號和金額,記錄訂單下單、成交及取消的紀錄
- 在Quicknode Solana gRPC Solana mainnet)上運行
您將負責的工作內容
- 建立一個包含 Vixen v0.6.1 依賴項的 Rust 專案
- 擷取並將 Jupiter 限價單 v2 IDL 轉換為 Codama 格式
- 使用 Vixen 的 proc-macro 產生一個類型安全的指令解析器
- 實作一個處理程式,用以記錄限價單事件,並以人類可讀的格式輸出
- 建置並執行一個連接到Quicknode Solana gRPC endpointVixen 執行環境
您需要準備的物品
- 您的系統上已安裝Rust 和 Cargo
- 適用於 Codama CLI 工具鏈的Node.js(v18+)
- 一個具備Solana gRPC Quicknode (Scale 和 Business 方案已包含此功能,或可透過 Build 和 Accelerate 方案的Solana gRPC 取得)
- 用於擷取鏈上 IDL 的Anchor CLI
- 對 Rust 和Solana 具備基礎了解
- 熟悉Solana gRPC:《使用Solana gRPC Rust) 監控Solana 》一文,為了解Solana gRPC 運作原理奠定了紮實的基礎
- 了解 Codama:《如何使用 Codama 建立 Anchor 程式客戶端》一文涵蓋了格式與命令列介面(CLI)
本指南亦使用以下套件:
| 依賴關係 | 版本 |
|---|---|
| rustc | 1.85.0 |
| yellowstone | 0.6.1 |
| yellowstone | 0.6.1 |
| yellowstone | 0.6.1 |
| yellowstone | 0.6.1 |
| grpc | 0.6.1 |
| 羅宋湯 | 1 |
| bs58 | 0.5 |
| chrono | 0.4 |
| reqwest | 0.12 |
| serde | 1 |
| 鼓掌 | 4 |
| rustls | 0.23 |
| toml | 0.8 |
| 追蹤 | 0.1 |
| 追蹤訂閱者 | 0.3 |
什麼是Solana gRPC?
Solana gRPC 基於 Geyser 外掛系統Solana 、專為Solana 的高效能資料串流解決方案。與其透過輪詢 RPCendpoint 或管理 WebSocket 的重新連線Solana gRPC 帳戶更新、交易及時槽通知以連續串流的形式gRPC 至您的應用程式。相較於傳統方法,此方案能提供更低的延遲與更高的吞吐量。
Quicknode 託管的Solana gRPC endpoint。此功能已包含在「Scale」和「Business」方案中;在「Build」和「Accelerate」方案中,則可透過Solana gRPC 使用。您可以在Quicknode 任何Solana endpoint 啟用此功能,系統將為您的應用程式提供專用的gRPC endpoint 證endpoint 。
主要篩選功能包括:
- 依計畫地址篩選,僅接收涉及特定計畫的交易
- 過濾掉失敗的交易,僅處理已確認的鏈上事件
- 過濾掉投票交易以減少雜訊
什麼是 Vixen?
Vixen是一個基於Solana gRPC 打造的開源 Rust 框架,用於建構Solana 管線。它會自動處理gRPC 、交易篩選及反序列化,因此應用程式程式碼接收的是具型別的 Rust 結構體,而非原始位元組。
Vixen 採用「解析器 + 處理器」架構,將資料擷取與業務邏輯分開:
- 解析器:將原始交易資料反序列化為帶有資料型的 Rust 結構體
- 處理器:接收已解析的資料,並實作您的應用程式邏輯
- 處理管線:將解析器與一個或多個處理器連接起來
- 執行時:管理gRPC 、串流訂閱及管線執行
根據Vixen v0.6.1 的發行說明,此版本引入了三項以生產環境為導向的改進,本指南將針對這些改進進行說明:
- 透過程序宏進行基於 IDL 的程式碼生成: 直接從程式的 IDL 產生類型安全的解析器,方法是使用
include_vixen_parser!, 省去手動反序列化的程式碼 失敗欄位在TransactionPrefilter: 將失敗的交易從資料流中排除,確保只有已確認的鏈上事件才會傳送到您的處理程序- 可觀察性中的追蹤區間: 透過
追蹤使用「crate」而非「plain」日誌/env_logger
Vixen 對決 Carbon
Vixen和Carbon都是用於解析Solana 資料的 Rust 框架。它們採用相同的核心方法:透過Solana gRPC 串流交易、將指令資料解碼為具型別的結構體,並在處理器中處理事件;但兩者在解析器的生成方式以及支援的資料來源方面有所不同:
| 特色 | Vixen | 碳 |
|---|---|---|
| 解析器生成 | 透過 IDL 產生程式碼 include_vixen_parser! 編譯時的 proc-macro | 預先建置的解碼器 Crates + 來自 IDL 的命令列介面程式碼產生器 |
| 資料來源 | Solana gRPC | Solana gRPC、JITO Shredstream、JSON RPC |
| 內建程式支援 | 無 — 由任何 Anchor IDL 產生 | 60 多個適用於熱門節目的預設解碼器 |
| 受支援程式的設定 | 取得 IDL → 轉換為 Codama → 呼叫巨集 | 新增一個 Cargo 套件依賴項 |
| 可觀察性 | 追蹤 具有結構化跨度的木箱 | Prometheus 指標 + 記錄 |
| 管道模型 | 執行階段 → 處理流程 → 解析器 → 處理器 | 處理管線 → 資料來源 → 解碼器 → 處理器 |
有關 Carbon 的指南,請參閱《Solana gRPC Carbon:解析Solana 資料的即時資料》。
範例應用程式:木星限價單監控器
「Jupiter 限價單」是一個鏈上訂單簿,讓交易者能下單,當市場價格達到指定價位時,訂單便會自動執行。與即時兌換不同,限價單會保留在鏈上,直到有「持單者」(稱為 接手者 (在該計畫的帳戶中)會以等於或高於指定價格的價格為其成交。做市商亦可隨時取消未成交的訂單,以取回其代幣。
本指南選用「木星限價單」,原因有三:
- 所有活動皆透過單一的 Anchor 程式進行(
j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X),這與 Vixen 的單管道模型完全吻合。 - 該程式會發布一個鏈上 IDL,這讓我們能夠端到端地展示 Vixen 的 IDL 程式碼生成功能。
- 該程式會發出三種互不重疊且語義上各不相同的指令類型(每個生命週期事件對應一種),這使得處理程序的邏輯既易於閱讀,也便於擴充。
本指南所監控的三項指令分別為:
InitializeOrder: 做市商建立一筆新的限價單,並指定輸入/輸出代幣及其數量FillOrder: 持倉交易者會以等同於或優於委託價的價格執行現有訂單取消訂單: 造市者取消其未成交的訂單,並取回其代幣
針對每個事件,處理程序會從 Jupiter 的代幣 API 中解析出易於人類閱讀的代幣符號,並根據交易中代幣餘額元資料所指定的小數精確度,對原始代幣數量進行格式化。
設定專案
建立專案目錄以及一個 idls 用來儲存 Jupiter 限價單 IDL 的資料夾:
cargo 新款 Jupiter-Lo-Vixen
cd jupiter-lo-vixen
mkdir idls
將以下內容替換為 Cargo.toml 如下所示。所有 Vixen 套件均固定為 v0.6.1 版本:
[package]
name = "jupiter-lo-vixen"
version = "0.1.0"
edition = "2021"
[dependencies]
yellowstone-vixen = "0.6.1"
yellowstone-vixen-core = "0.6.1"
yellowstone-vixen-parser = "0.6.1"
yellowstone-vixen-proc-macro = "0.6.1"
yellowstone-vixen-yellowstone-grpc-source = "0.6.1"
borsh = { version = "1", features = ["derive"] }
bs58 = "0.5"
chrono = { version = "0.4", features = ["clock"] }
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
serde = { version = "1", features = ["derive"] }
clap = { version = "4", features = ["derive"] }
rustls = { version = "0.23", features = ["ring"] }
toml = "0.8"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
請注意, yellowstone 一定是個 直接 依賴關係(不僅僅是透過 yellowstone) 因為該程序巨集所產生的程式碼是透過 crate 名稱來引用它的。
以下是這些關鍵依賴項的功能:
yellowstone/yellowstone: Vixen 執行環境與核心特徵(解析器、處理器、處理管線)yellowstone: 該include_vixen_parser!基於 IDL 的程式碼生成巨集grpc: 將 Vixen 執行環境連接到Solana gRPC endpoint羅宋湯:Solana 所使用的序列化格式(由生成的解析器所要求)bs58: 交易簽名的 Base58 編碼chrono: 日誌輸出的時間戳記格式reqwest: 用於從 Jupiter API 擷取代碼符號的 HTTP 客戶端鼓掌: 針對該的命令列參數解析--config旗幟rustls:gRPC 所需的 TLS 提供者追蹤/追蹤訂閱者: 基於環境的篩選功能之結構化記錄
建立 Vixen.toml 位於專案根目錄下。這是應用程式所需的唯一設定檔:
[source]
endpoint = "YOUR_QN_ENDPOINT:10000"
x-token = "YOUR_X_TOKEN"
timeout = 120
commitment-level = "confirmed"
accept-compression = "zstd"
您可以在 Quicknode 位於您的Solana mainnet endpoint Solana gRPC 。儀表板會以以下格式顯示endpoint : https://your-endpoint-name.solana-mainnet.quiknode.pro/abc123. 追加 :10000 至該主機名稱的 endpoint 欄位,並使用尾隨標記 (abc123) 作為您的 x-token. 如需更多詳細資訊,請參閱 Solana gRPC.
根據限價單 IDL 產生解析器
您無需為每條指令手動編寫反序列化程式碼,只需提供以 Codama 格式撰寫的程式 IDL 以及 include_vixen_parser! 此巨集會在編譯時產生一個完整的類型安全解析器。本節將逐步說明整個flow 您能將其應用於任何 Anchor 程式。
取得 Jupiter 限價單 v2 IDL:
Vixen 儲存庫中已包含一個可直接使用的 Codama IDL,適用於 Jupiter Limit Order v2,位置在 tests/idls/lo_v2.json. 您可以直接將其複製到您的 idls/ 資料夾,並直接跳至 呼叫 Proc-Macro. 以下步驟將引導您完成整個「擷取與轉換」flow 將此流程套用至任何尚未具備 Codama IDL 的 Anchor 程式。
使用 Anchor CLI 擷取 Jupiter Limit Order v2 程式的鏈上 IDL。請將 YOUR_QN_RPC_URL 搭配您的Quicknode Solana mainnet endpoint:
anchor idl fetch j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X \
--provider.cluster YOUR_QN_RPC_URL \
-o idls/lo_v2_raw.json
IDL 包含完整的程式介面定義:指令名稱、帳戶結構、參數類型以及程式位址。這正是 Vixen 用來產生具型別的 Rust 程式碼的依據。
當您使用 錨點 idl 指令,其中存在一個微小的不一致之處,導致 Codama 的轉換器無法正常運作。在 initialize_order 根據說明,PDA 種子會引用一個名為 unique_id,但在這個 IDL 中, unique_id 實際上是嵌套在一個 參數 這是結構體,而非頂層參數。Codama 會在頂層搜尋它,但找不到,因此報錯。
當您將 Codama 與其他程式的 IDL 搭配使用時,可能會遇到這種情況:該 IDL 雖然在技術上屬於有效的 Anchor 輸出,但路徑參照卻與實際的參數結構不符。在使用 Vixen 時,若所用的 IDL 尚未具備 Codama 格式的 IDL,您可能需要手動排除此類問題。
要解決此問題,請開啟 idls/lo_v2_raw.json 並在 initialize_order 指令的帳戶初始值中找到這一行(約第 621 行):
{
"kind": "arg",
"path": "unique_id"
}
請改為:
{
"kind": "arg",
"path": "params.unique_id"
}
轉換為 Codama 格式:
將根專案資料夾初始化為 Node.js 專案,以便我們能夠執行 Codama 指令:
npm init -y
npm install -g @codama/cli
npm install @codama/nodes-from-anchor
@codama/來自錨點的節點 在轉換過程中,必須理解 Anchor 的 IDL 格式。
將原始的 Anchor IDL 轉換為 Codama 格式:
codama 轉換 idls/lo_v2_raw.json 為 idls/lo_v2.json
正是這個一次性轉換步驟,才能為任何 Anchor 程式啟用 Vixen 的編譯時程式碼生成功能。
呼叫 Proc-Macro
建立 src/parser.rs 內容如下:
use yellowstone_vixen_proc_macro::include_vixen_parser;
include_vixen_parser!("idls/lo_v2.json");
這個單一的巨集呼叫會在編譯時產生:
- A
限價單2包含所有生成類型的模組 - 打字稿
說明包含 IDL 中每條指令對應變體的枚舉 (InitializeOrder,FillOrder,取消訂單, 及其他) - 每條指令的類型化指令結構與參數結構
- 一個
指令解析器該類別實作了 Vixen 的解析器特質 - A
TransactionPrefilter配置了三個篩選條件:程式位址(僅限 Jupiter LO v2),失敗:部分(false)(v0.6.1 新增功能) 以排除失敗的交易,並投票:部分(false)以排除投票交易
實作 Monitor
Vixen v0.6.1 使用的是 追蹤 用於產生結構化且可篩選的日誌輸出的套件,用以取代舊版的 log/env_logger Vixen 先前版本中使用的模式。
該追蹤用戶遵守 RUST_LOG 環境變數,因此您可以在執行時控制輸出詳盡程度,而無需重新編譯:
RUST_LOG=info: 顯示處理程式的輸出內容及 Vixen 的生命週期事件RUST_LOG=debug: 新增gRPC 詳細資訊及串流訂閱活動RUST_LOG=warn: 僅顯示警告和錯誤
初始化是在 main() 在任何其他程式碼執行之前,確保所有 Vixen 內部組件以及您的處理程式碼都能從結構化記錄中受益。
實作限價單處理程式
建立 src/handlers.rs. 處理程式會從生成的解析器接收已解析的指令,並記錄三種訂單事件:下單、成交及取消。
此處理程式包含一些輔助函式,用於從 Jupiter 的代幣 API 擷取易於人類閱讀的代幣符號,並將其快取以避免重複查詢。它還會從交易的代幣餘額元資料中提取小數精確度,以便以易於人類閱讀的形式顯示金額(例如, 1.5 USDC 而非 1500000).
use std::{collections::HashMap, sync::Mutex};
use yellowstone_vixen::vixen_core::instruction::InstructionUpdate;
use crate::parser::limit_order2;
fn fmt_amount(raw: u64, decimals: u32) -> String {
if decimals == 0 {
return raw.to_string();
}
let s = format!("{:.prec$}", raw as f64 / 10f64.powi(decimals as i32), prec = decimals as usize);
s.trim_end_matches('0').trim_end_matches('.').to_string()
}
fn fmt_token(amount: &str, symbol: &str, mint: &str) -> String {
if symbol == mint {
format!("{amount} {mint}")
} else {
format!("{amount} {symbol} ({mint})")
}
}
async fn fetch_symbol(mint: &str) -> String {
#[derive(serde::Deserialize)]
struct Token {
id: String,
symbol: String,
}
let url = format!("https://api.jup.ag/tokens/v2/search?query={mint}");
let fallback = mint.to_string();
let Ok(resp) = reqwest::get(&url).await else {
return fallback;
};
let Ok(tokens) = resp.json::<Vec<Token>>().await else {
return fallback;
};
代幣
.into_iter()
.find(|t| t.id == mint)
.map(|t| t.symbol)
.unwrap_or(fallback)
}
#[derive(Debug, Default)]
pub struct LimitOrderHandler {
symbol_cache: Mutex<HashMap<String, String>>,
}
impl LimitOrderHandler {
async fn get_symbol(&self, mint: &str) -> String {
{
let cache = self.symbol_cache.lock().unwrap();
if let Some(sym) = cache.get(mint) {
return sym.clone();
}
}
let symbol = fetch_symbol(mint).await;
self.symbol_cache
.lock()
.unwrap()
.insert(mint.to_string(), symbol.clone());
符號
}
}
impl yellowstone_vixen::Handler<limit_order2::Instructions, InstructionUpdate>
for LimitOrderHandler
{
async fn handle(
&self,
value: &limit_order2::Instructions,
raw: &InstructionUpdate,
) -> yellowstone_vixen::HandlerResult<()> {
use limit_order2::instruction::Instruction;
let sig = bs58::encode(&raw.shared.signature).into_string();
let ts = chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.6fZ");
let pre = &raw.shared.pre_token_balances;
let post = &raw.shared.post_token_balances;
let find_decimals = |mint: &str| {
pre.iter()
.chain(post.iter())
.find(|b| b.mint == mint)
.and_then(|b| b.ui_token_amount.as_ref())
.map(|u| u.decimals)
};
match &value.instruction {
Instruction::InitializeOrder { accounts, args } => {
let input_mint_str = accounts.input_mint.to_string();
let output_mint_str = accounts.output_mint.to_string();
let input_symbol = self.get_symbol(&input_mint_str).await;
let output_symbol = self.get_symbol(&output_mint_str).await;
let making_amount = find_decimals(&input_mint_str)
.map(|d| fmt_amount(args.making_amount, d))
.unwrap_or_else(|| args.making_amount.to_string());
let taking_amount = find_decimals(&output_mint_str)
.map(|d| fmt_amount(args.taking_amount, d))
.unwrap_or_else(|| args.taking_amount.to_string());
let expired_at = args.expired_at
.and_then(|t| chrono::DateTime::from_timestamp(t, 0))
.map(|dt| dt.format("%Y-%m-%dT%H:%M:%SZ").to_string())
.unwrap_or_else(|| "None".to_string());
let making = fmt_token(&making_amount, &input_symbol, &input_mint_str);
let taking = fmt_token(&taking_amount, &output_symbol, &output_mint_str);
tracing::info!(
tx = %sig,
maker = %accounts.maker,
making_amount = %making,
taking_amount = %taking,
expired_at = %expired_at,
"New limit order placed - {ts}",
);
},
Instruction::FillOrder { accounts, args } => {
let input_mint_str = accounts.input_mint.to_string();
let output_mint_str = accounts.output_mint.to_string();
let input_symbol = self.get_symbol(&input_mint_str).await;
let input_amount = find_decimals(&input_mint_str)
.map(|d| fmt_amount(args.input_amount, d))
.unwrap_or_else(|| args.input_amount.to_string());
let input = fmt_token(&input_amount, &input_symbol, &input_mint_str);
tracing::info!(
tx = %sig,
taker = %accounts.taker,
output_mint = %output_mint_str,
input_amount = %input,
"Limit order filled - {ts}",
);
},
Instruction::CancelOrder { accounts, .. } => {
tracing::info!(
tx = %sig,
maker = %accounts.maker,
order = %accounts.order,
"Limit order cancelled - {ts}",
);
},
_ => {},
}
Ok(())
}
}
該處理程序實作了 Vixen 的 處理器 生成的特徵 limit_order2::操作說明 類型。它針對三種指令變體進行模式比對:
InitializeOrder: 記錄創建者的地址、以人可讀形式顯示金額的輸入/輸出代幣,以及訂單的到期時間戳記FillOrder: 記錄接單者的地址、輸出鑄幣以及正在成交的輸入金額取消訂單: 記錄製造商的地址以及即將被取消的訂單帳號_(通配符): 會靜默地忽略所有其他指令(手續費更新、管理操作等)
該處理程式還包含一些方便使用者操作的功能,例如將代幣金額轉換為小數,以及透過 Jupiter 的代幣 API 查詢代幣代號。對於超高效能的應用程式而言,這些外接 API 呼叫可能會影響效能。
編譯 Vixen 執行環境
請將生成的 src/main.rs 透過以下程式碼。這將所有元件整合在一起:追蹤初始化、TLS 加密提供者、設定載入,以及具備指令管線的 Vixen 執行環境。
use std::path::PathBuf;
use clap::Parser as _;
use yellowstone_vixen::Pipeline;
use yellowstone_vixen_yellowstone_grpc_source::YellowstoneGrpcSource;
mod handlers;
mod parser;
use handlers::LimitOrderHandler;
use parser::limit_order2;
#[derive(clap::Parser)]
#[command(version, author, about = "Monitor Jupiter Limit Order v2 events via Yellowstone Vixen")]
struct Opts {
#[arg(long, short)]
config: PathBuf,
}
fn main() {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
)
.init();
rustls::crypto::ring::default_provider()
.install_default()
.expect("Failed to install rustls crypto provider");
let Opts { config } = Opts::parse();
let config = std::fs::read_to_string(config).expect("Error reading config file");
let config = toml::from_str(&config).expect("Error parsing config");
yellowstone_vixen::Runtime::<YellowstoneGrpcSource>::builder()
.instruction(Pipeline::new(limit_order2::InstructionParser, [LimitOrderHandler::default()]))
.build(config)
.run();
}
執行階段設定會執行四個步驟:
- 追溯: 初始化
追蹤訂閱者與EnvFilter所以,這個RUST_LOG環境變數可在執行時控制日誌的詳盡程度,無需重新編譯 - TLS: 安裝
rustls加密服務提供者,這是gRPC 連線至Quicknode所必需的 - 設定: 讀取與解析
Vixen.toml關於endpoint、憑證及串流的設定 - 執行時間: 打造一隻 Vixen
執行時間僅需一條指令管線將生成的指令解析器至限價單處理器, 接著開始串流
該 Pipeline::new 透過呼叫將解析器傳遞給處理器。所產生的 指令解析器 負責處理訂閱篩選(程式位址、失敗交易、投票交易)及反序列化。您的處理器僅會接收針對 Jupiter Limit Order v2 程式所解析且已標記類型的指令資料。
建置並執行應用程式
編譯專案:
cargo 建置
請使用設定參數執行此程式。設定 RUST_LOG=info 若要查看處理程式的輸出內容及 Vixen 的生命週期事件:
RUST_LOG=資訊 cargo 執行 -- --config ./Vixen.toml
預期輸出
連線成功後,您將看到 Vixen 的生命週期日誌記錄,隨後會顯示mainnet限價單事件。以下是這三種事件類型的輸出範例:
2026-04-08T14:32:01.123456Z INFO jupiter_lo_vixen: New limit order placed - 2026-04-08T14:32:01.123456Z tx=5UjQ...abc maker=7xKm...def making_amount="100 USDC (EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v)" taking_amount="1.5 SOL (So11111111111111111111111111111111111111112)" expired_at=2026-04-15T00:00:00Z
2026-04-08T14:33:15.654321Z INFO jupiter_lo_vixen: Limit order filled - 2026-04-08T14:33:15.654321Z tx=3Kpx...ghi taker=9mRv...jkl output_mint=So11111111111111111111111111111111111111112 input_amount="100 USDC (EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v)"
2026-04-08T14:35:42.789012Z INFO jupiter_lo_vixen: Limit order cancelled - 2026-04-08T14:35:42.789012Z tx=8FnY...mno maker=7xKm...def order=4vTq...pqr
每個條目包含一個 ISO 8601 時間戳記、交易簽名,以及該事件類型的相關帳戶與金額。代幣金額以人可讀的形式顯示,其中代幣代號是透過 Jupiter 的代幣 API 解析而得。
擴展您的顯示器
您所建構的架構具有靈活性。以下是一些擴充該架構的方法:
- 監控其他 Jupiter 程式:將 IDL 檔案替換為 Jupiter DCA、Perps 或任何其他 Anchor 程式。處理流程結構保持不變;僅有 IDL 檔案與處理邏輯會有所變更。
- 同時監控多個程式:Vixen v0.6.1 支援多重程式訂閱。新增第二條指令管線,可在同一執行環境中同時監控限價單 v1 與 v2。
- 新增帳戶監控:除了指令監控之外,請新增一個帳戶處理流程,用以追蹤特定限價單帳戶狀態的變更。
- 將事件儲存至資料庫:擴充處理程序,將已解析的事件寫入 PostgreSQL、ClickHouse 或其他資料儲存庫,以便進行歷史分析。
常見問題
什麼是Solana gRPC 它如何實現Solana 上的即時監控?
Solana gRPC 高效能的gRPC 用於即時串流Solana 資料,包括交易和帳戶更新。它讓 Rust 應用程式能夠訂閱特定程式(例如 Jupiter),以取得低延遲的限價單資料流,且無需進行輪詢。
在Solana 的脈絡下,Vixen 究竟是什麼?
Vixen 是一個基於Solana gRPC 構建類型化資料管線的開源 Rust 框架。它會自動處理gRPC 、串流過濾以及指令反序列化,因此您只需針對類型化的 Rust 結構體編寫業務邏輯,而非直接處理原始位元組。其核心抽象概念包括:負責解碼指令的「解析器」(Parser)、負責處理指令的「處理器」(Handler),以及在受管理的執行環境中將兩者連接起來的「管線」(Pipeline)。
除了「木星限價單」之外,我還能使用 Vixen 來監控其他程式嗎?
是的。Vixen 的 proc-macro 可與任何發佈 IDL 的 Anchor 程式配合使用。請使用 Anchor CLI 擷取 IDL,將其轉換為 Codama 格式,然後傳遞給 include_vixen_parser!。生成的解析器與管線結構保持不變,僅有 IDL 檔案及您的處理邏輯會有所變更。
為什麼 TransactionPrefilter 會排除失敗的交易?
Vixen v0.6.1 在其 TransactionPrefilter 中新增了「失敗」欄位。將其設定為排除失敗的交易,可確保僅有已確認且成功執行的交易會傳送至您的處理程序。對於限價單監控器而言,此舉可避免記錄諸如「失敗的成交嘗試」等事件——此類事件實際上從未在鏈上執行過。
使用 Vixen 是否需要擁有Quicknode ?
Vixen 本身是一個開源框架。然而,它需要一個Solana gRPC endpoint 資料串流。Quicknode Solana gRPC 包含在 Scale 和 Business 方案中,或可透過 Build 和 Accelerate 方案的附加功能取得),您可endpoint 儀表板endpoint 任何Quicknode Solana endpoint 啟用此功能。
什麼是 Codama,為什麼需要這個轉換步驟?
Codama 是一種 IDL 格式,其提供的類型資訊比 Anchor 的原生 IDL 格式更為豐富。Vixen 的程序巨集需要 Codama 格式,才能產生精確的類型化結構體和枚舉。codama convert 指令負責在兩種格式之間進行轉換。正是這個一次性轉換步驟,才能為任何 Anchor 程式啟用 Vixen 的編譯時程式碼生成功能。
總結
您已建置了一個即時木星限價單監控系統,該系統透過Solana gRPC streams 交易,利用 Vixen 的 IDL 程式碼生成器將其解析為帶有資料型的 Rust 結構體,並以人類可讀的標記輸出形式記錄下單、成交及取消等事件。在此基礎上,您只需替換對應的 IDL,即可將相同模式套用至任何 Anchor 程式,使 Vixen 成為建構Solana 管線的多功能基礎架構。
