Documentation Index
Fetch the complete documentation index at: https://docs.vali.wtf/llms.txt
Use this file to discover all available pages before exploring further.
vRPC
vRPC is a pre-confirmation transaction streaming service. It decodes transactions directly from Solana’s shred layer (turbine) — before the validator replays them — giving you the lowest possible latency for new transaction detection. vRPC operates at the shred layer, so transactions are available before replay completes. This means:- No transaction metadata (no balances, no logs, no CPI trace)
- No execution status (you don’t know if it succeeded or failed)
- You get: signature, account keys, decoded instruction args, slot
Connecting
Endpoint: your-node:9000
Protocol: gRPC bidirectional streaming
Method: vrpc.Vrpc/SubscribeDecoded
// Example: subscribe to PumpFun buys
const request = {
subscriptions: {
"pf-buys": {
programs: ["PUMP_FUN"],
instruction_types: ["buy"]
}
}
};
Supported Programs
| Program | ID | Instructions |
|---|---|---|
| PumpFun | 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P | create, buy, sell |
| PumpSwap (AMM) | pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA | buy, sell, create_pool, deposit, withdraw |
| Raydium CPMM | CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C | swap_base_input, swap_base_output, create_pool |
| Raydium LaunchLab | LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj | create, buy_exact_in, buy_exact_out, sell_exact_in, sell_exact_out, migrate |
| Meteora DBC | dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN | swap, initialize, migrate |
| Meteora DAMM v2 | cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG | swap, create_pool, add_liquidity, remove_liquidity |
Filtering
Filters are set on the initial request and can be updated mid-stream by sending a newSubscribeRequest. Sending a new map replaces all previous filters atomically.
| Filter | Type | Description |
|---|---|---|
programs | repeated enum | Which DEX programs to include. Empty = all. |
instruction_types | repeated string | e.g. ["buy", "sell"]. Empty = all for selected programs. |
accounts_include | repeated string | OR logic — tx must contain ANY of these accounts (base58). |
accounts_exclude | repeated string | Reject tx if ANY of these accounts appear. |
accounts_required | repeated string | AND logic — tx must contain ALL of these accounts. |
Proto Definition
syntax = "proto3";
package vrpc;
// ============================================================
// vRPC — Decoded Shredstream Service
// ============================================================
service Vrpc {
// Bidirectional streaming: client sends filter updates, server sends decoded transactions.
// Client sends initial SubscribeRequest on connect, can update filters mid-stream.
rpc SubscribeDecoded(stream SubscribeRequest) returns (stream SubscribeUpdate) {}
}
// ============================================================
// Enums
// ============================================================
enum DexProgram {
DEX_PROGRAM_UNSPECIFIED = 0;
PUMP_FUN = 1;
PUMP_AMM = 2;
RAYDIUM_CPMM = 3;
RAYDIUM_LAUNCH_LAB = 4;
METEORA_DBC = 5;
METEORA_DAMM_V2 = 6;
JUPITER_PUMP_FUN = 7;
JUPITER_PUMP_AMM = 8;
JUPITER_RAYDIUM_CPMM = 9;
JUPITER_RAYDIUM_LAUNCH_LAB = 10;
JUPITER_METEORA_DBC = 11;
JUPITER_METEORA_DAMM_V2 = 12;
}
// ============================================================
// Request
// ============================================================
message SubscribeRequest {
// Named subscription filters. Key = client-chosen filter ID (e.g. "pf-buys").
// Sending a new map replaces all previous filters atomically.
// Empty map = no filtering (receive everything).
map<string, ProgramFilter> subscriptions = 1;
// Optional ping for keepalive
optional int32 ping_id = 2;
}
message ProgramFilter {
// Which programs to include. Empty = all programs.
repeated DexProgram programs = 1;
// Optional: only include these instruction types (e.g. "buy", "sell", "swap").
// Empty = all instruction types for the selected programs.
repeated string instruction_types = 2;
// Optional: only include transactions where ANY of these accounts appear in account_keys.
// Each entry is a base58-encoded pubkey. Empty = no include filter.
repeated string accounts_include = 3;
// Optional: exclude transactions where ANY of these accounts appear in account_keys.
// Each entry is a base58-encoded pubkey. Empty = no exclude filter.
repeated string accounts_exclude = 4;
// Optional: only include transactions where ALL of these accounts appear in account_keys.
// Each entry is a base58-encoded pubkey. Empty = no required filter.
repeated string accounts_required = 5;
}
// ============================================================
// Response
// ============================================================
message SubscribeUpdate {
oneof update {
DecodedTransaction transaction = 1;
int32 pong = 2;
SlotNotification slot = 3;
JupiterUpdate jupiter = 4;
}
}
message SlotNotification {
uint64 slot = 1;
}
message JupiterUpdate {
// Base transaction envelope for the Jupiter-routed transaction.
// This reuses the existing client-visible transaction shape.
DecodedTransaction envelope = 1;
// Decoded top-level Jupiter instruction that produced this update.
JupiterTopLevelInstruction top_level_instruction = 2;
// Canonical client-facing wrapped DEX legs.
repeated JupiterDexLeg dex_legs = 3;
// Indices into dex_legs that matched the current subscription set.
repeated uint32 matched_leg_indices = 4;
}
enum JupiterLegSource {
JUPITER_LEG_SOURCE_UNSPECIFIED = 0;
JUPITER_LEG_SOURCE_CURRENT_TRANSACTION = 1;
JUPITER_LEG_SOURCE_INFERRED_ROUTE = 2;
JUPITER_LEG_SOURCE_EXECUTED_INNER = 3;
}
message JupiterDexLeg {
DexProgram wrapped_program = 1;
DecodedInstruction instruction = 2;
JupiterLegSource source = 3;
uint32 top_level_instruction_index = 4;
uint32 route_step_index = 5;
string swap_variant = 6;
string logical_instruction_name = 7;
optional uint32 split_percent = 8;
optional uint32 split_bps = 9;
// Single-hop route-level input amount when it can be derived from the signed Jupiter route.
// For exact-in routes this is the exact input; for exact-out routes this is the quoted input.
optional uint64 route_input_amount = 10;
// Single-hop route-level output amount when it can be derived from the signed Jupiter route.
// For exact-in routes this is the quoted output; for exact-out routes this is the exact output.
optional uint64 route_output_amount = 11;
}
message JupiterTopLevelInstruction {
string instruction_name = 1;
uint32 instruction_index = 2;
bytes raw_data = 3;
repeated uint32 account_indices = 4;
repeated string resolved_accounts = 5;
repeated JupiterNamedAccount named_accounts = 6;
repeated string remaining_accounts = 7;
map<string, string> decoded_args = 8;
optional JupiterRouteSummary route = 9;
optional string decode_error = 10;
}
message JupiterNamedAccount {
string name = 1;
string pubkey = 2;
bool writable = 3;
bool signer = 4;
bool optional = 5;
optional string expected_address = 6;
}
message JupiterRouteSummary {
string variant = 1;
uint32 route_plan_step_count = 2;
uint32 opaque_route_plan_bytes_len = 3;
optional uint64 exact_in_amount = 4;
optional uint64 exact_out_amount = 5;
optional uint64 quoted_in_amount = 6;
optional uint64 quoted_out_amount = 7;
uint32 slippage_bps = 8;
uint32 platform_fee_bps = 9;
optional uint32 positive_slippage_bps = 10;
optional uint32 shared_accounts_route_id = 11;
bool uses_token_ledger = 12;
repeated JupiterRouteStep route_steps = 13;
}
message JupiterRouteStep {
string swap_variant = 1;
optional string normalized_dex_label = 2;
optional uint32 split_percent = 3;
optional uint32 split_bps = 4;
uint32 input_index = 5;
uint32 output_index = 6;
map<string, string> swap_fields = 7;
}
message ServerTiming {
// Server wall-clock timestamps in Unix epoch nanoseconds.
uint64 first_read_unix_nanos = 1;
uint64 capture_done_unix_nanos = 2;
uint64 deshred_done_unix_nanos = 3;
uint64 decode_done_unix_nanos = 4;
uint64 publish_unix_nanos = 5;
// Set per subscriber when the outbound task dequeues the message from the broadcast channel.
uint64 subscriber_recv_unix_nanos = 6;
}
// ============================================================
// Decoded Transaction
// ============================================================
message DecodedTransaction {
// Slot this transaction appeared in
uint64 slot = 1;
// Transaction signature (first signature, 64 bytes)
bytes signature = 2;
// Transaction index within the entry batch
uint32 tx_index = 3;
// Fee payer / signer pubkey (32 bytes)
bytes signer = 4;
// All static account keys from the transaction (32 bytes each).
// For v0 txns, LUT-resolved addresses are NOT included in v1.
repeated bytes account_keys = 5;
// Decoded instructions that matched target programs.
// A single transaction can have multiple matches (e.g. multi-hop swap).
repeated DecodedInstruction decoded_instructions = 6;
// Whether this is a v0 transaction with address lookup tables.
// When true, account_keys may be incomplete (LUT resolution deferred).
bool uses_lookup_tables = 7;
// Which subscription filter IDs matched this transaction
repeated string matched_filters = 8;
// Optional server-side timing metadata to help benchmark end-to-end latency.
optional ServerTiming server_timing = 9;
}
// ============================================================
// Decoded Instruction
// ============================================================
message DecodedInstruction {
// Which program this instruction belongs to
DexProgram program = 1;
// Human-readable instruction name (e.g. "buy", "swap", "create_pool")
string instruction_name = 2;
// Index of this instruction in the transaction's instruction list
uint32 instruction_index = 3;
// Account indices into DecodedTransaction.account_keys
repeated uint32 account_indices = 4;
// Raw instruction data (discriminator + args) for forward-compat
bytes raw_data = 5;
// Decoded instruction variant
oneof decoded {
// === PumpFun ===
PumpFunCreate pump_fun_create = 10;
PumpFunBuy pump_fun_buy = 11;
PumpFunSell pump_fun_sell = 12;
// === Pump AMM (PumpSwap) ===
PumpAmmBuy pump_amm_buy = 20;
PumpAmmSell pump_amm_sell = 21;
PumpAmmCreatePool pump_amm_create_pool = 22;
PumpAmmDeposit pump_amm_deposit = 23;
PumpAmmWithdraw pump_amm_withdraw = 24;
// === Raydium CPMM ===
CpmmSwapBaseInput cpmm_swap_base_input = 30;
CpmmSwapBaseOutput cpmm_swap_base_output = 31;
CpmmCreatePool cpmm_create_pool = 32;
// === Raydium LaunchLab ===
LaunchLabCreatePool launch_lab_create = 40;
LaunchLabBuyExactIn launch_lab_buy_exact_in = 41;
LaunchLabBuyExactOut launch_lab_buy_exact_out = 42;
LaunchLabSellExactIn launch_lab_sell_exact_in = 43;
LaunchLabSellExactOut launch_lab_sell_exact_out = 44;
LaunchLabMigrate launch_lab_migrate = 45;
// === Meteora DBC ===
DbcSwap dbc_swap = 50;
DbcInitializeVirtualPool dbc_initialize = 51;
DbcMigrateToDammV2 dbc_migrate = 52;
// === Meteora DAMM v2 ===
DammV2Swap damm_v2_swap = 60;
DammV2CreatePool damm_v2_create_pool = 61;
DammV2AddLiquidity damm_v2_add_liquidity = 62;
DammV2RemoveLiquidity damm_v2_remove_liquidity = 63;
}
}
// ============================================================
// PumpFun Instructions
// Program: 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
// ============================================================
message PumpFunCreate {
string name = 1;
string symbol = 2;
string uri = 3;
}
message PumpFunBuy {
uint64 amount = 1;
uint64 max_sol_cost = 2;
}
message PumpFunSell {
uint64 amount = 1;
uint64 min_sol_output = 2;
}
// ============================================================
// Pump AMM (PumpSwap) Instructions
// Program: pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA
// ============================================================
message PumpAmmBuy {
uint64 base_amount_out = 1;
uint64 max_quote_amount_in = 2;
}
message PumpAmmSell {
uint64 base_amount_in = 1;
uint64 min_quote_amount_out = 2;
}
message PumpAmmCreatePool {
uint32 index = 1;
uint64 base_amount = 2;
uint64 quote_amount = 3;
}
message PumpAmmDeposit {
uint64 lp_token_amount_out = 1;
uint64 max_base_amount_in = 2;
uint64 max_quote_amount_in = 3;
}
message PumpAmmWithdraw {
uint64 lp_token_amount_in = 1;
uint64 min_base_amount_out = 2;
uint64 min_quote_amount_out = 3;
}
// ============================================================
// Raydium CPMM Instructions
// Program: CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
// ============================================================
message CpmmSwapBaseInput {
uint64 amount_in = 1;
uint64 minimum_amount_out = 2;
}
message CpmmSwapBaseOutput {
uint64 max_amount_in = 1;
uint64 amount_out = 2;
}
message CpmmCreatePool {
uint64 init_amount_0 = 1;
uint64 init_amount_1 = 2;
uint64 open_time = 3;
}
// ============================================================
// Raydium LaunchLab Instructions
// Program: LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj
// ============================================================
message LaunchLabCreatePool {
string name = 1;
string symbol = 2;
string uri = 3;
uint32 decimals = 4;
uint64 total_supply = 5;
}
message LaunchLabBuyExactIn {
uint64 amount_in = 1;
uint64 minimum_amount_out = 2;
uint64 share_fee_bps = 3;
}
message LaunchLabBuyExactOut {
uint64 amount_out = 1;
uint64 maximum_amount_in = 2;
uint64 share_fee_bps = 3;
}
message LaunchLabSellExactIn {
uint64 amount_in = 1;
uint64 minimum_amount_out = 2;
uint64 share_fee_bps = 3;
}
message LaunchLabSellExactOut {
uint64 amount_out = 1;
uint64 maximum_amount_in = 2;
uint64 share_fee_bps = 3;
}
message LaunchLabMigrate {
// Permissionless migration - no args
}
// ============================================================
// Meteora DBC Instructions
// Program: dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN
// ============================================================
message DbcSwap {
uint64 amount_in = 1;
uint64 minimum_amount_out = 2;
}
message DbcInitializeVirtualPool {
// Complex config params - include key fields
bytes pool_config = 1;
}
message DbcMigrateToDammV2 {
// Permissionless migration
}
// ============================================================
// Meteora DAMM v2 Instructions
// Program: cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
// ============================================================
message DammV2Swap {
uint64 amount_in = 1;
uint64 minimum_amount_out = 2;
}
message DammV2CreatePool {
// Pool creation params
bytes config = 1;
}
message DammV2AddLiquidity {
uint64 max_token_a_amount = 1;
uint64 max_token_b_amount = 2;
uint64 min_lp_amount = 3;
}
message DammV2RemoveLiquidity {
uint64 lp_amount = 1;
uint64 min_token_a_amount = 2;
uint64 min_token_b_amount = 3;
}