Skip to main content

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
This is designed for latency-sensitive use cases like copy trading, MEV detection, and real-time monitoring where you need to know a transaction exists as fast as possible.

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

ProgramIDInstructions
PumpFun6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6Pcreate, buy, sell
PumpSwap (AMM)pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEAbuy, sell, create_pool, deposit, withdraw
Raydium CPMMCPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1Cswap_base_input, swap_base_output, create_pool
Raydium LaunchLabLanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3ujcreate, buy_exact_in, buy_exact_out, sell_exact_in, sell_exact_out, migrate
Meteora DBCdbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqNswap, initialize, migrate
Meteora DAMM v2cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGGswap, create_pool, add_liquidity, remove_liquidity

Filtering

Filters are set on the initial request and can be updated mid-stream by sending a new SubscribeRequest. Sending a new map replaces all previous filters atomically.
FilterTypeDescription
programsrepeated enumWhich DEX programs to include. Empty = all.
instruction_typesrepeated stringe.g. ["buy", "sell"]. Empty = all for selected programs.
accounts_includerepeated stringOR logic — tx must contain ANY of these accounts (base58).
accounts_excluderepeated stringReject tx if ANY of these accounts appear.
accounts_requiredrepeated stringAND 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;
}