Skip to main content

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;

service Vrpc {
  rpc SubscribeDecoded(stream SubscribeRequest) returns (stream SubscribeUpdate) {}
}

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;
}

message SubscribeRequest {
  map<string, ProgramFilter> subscriptions = 1;
  optional int32 ping_id = 2;
}

message ProgramFilter {
  repeated DexProgram programs = 1;
  repeated string instruction_types = 2;
  repeated string accounts_include = 3;
  repeated string accounts_exclude = 4;
  repeated string accounts_required = 5;
}

message SubscribeUpdate {
  oneof update {
    DecodedTransaction transaction = 1;
    int32 pong = 2;
    SlotNotification slot = 3;
  }
}

message SlotNotification {
  uint64 slot = 1;
}

message DecodedTransaction {
  uint64 slot = 1;
  bytes signature = 2;
  uint32 tx_index = 3;
  bytes signer = 4;
  repeated bytes account_keys = 5;
  repeated DecodedInstruction decoded_instructions = 6;
  bool uses_lookup_tables = 7;
  repeated string matched_filters = 8;
}

message DecodedInstruction {
  DexProgram program = 1;
  string instruction_name = 2;
  uint32 instruction_index = 3;
  repeated uint32 account_indices = 4;
  bytes raw_data = 5;

  oneof decoded {
    PumpFunCreate pump_fun_create = 10;
    PumpFunBuy pump_fun_buy = 11;
    PumpFunSell pump_fun_sell = 12;

    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;

    CpmmSwapBaseInput cpmm_swap_base_input = 30;
    CpmmSwapBaseOutput cpmm_swap_base_output = 31;
    CpmmCreatePool cpmm_create_pool = 32;

    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;

    DbcSwap dbc_swap = 50;
    DbcInitializeVirtualPool dbc_initialize = 51;
    DbcMigrateToDammV2 dbc_migrate = 52;

    DammV2Swap damm_v2_swap = 60;
    DammV2CreatePool damm_v2_create_pool = 61;
    DammV2AddLiquidity damm_v2_add_liquidity = 62;
    DammV2RemoveLiquidity damm_v2_remove_liquidity = 63;
  }
}

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;
}

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;
}

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;
}

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 {
}

message DbcSwap {
  uint64 amount_in = 1;
  uint64 minimum_amount_out = 2;
}

message DbcInitializeVirtualPool {
  bytes pool_config = 1;
}

message DbcMigrateToDammV2 {
}

message DammV2Swap {
  uint64 amount_in = 1;
  uint64 minimum_amount_out = 2;
}

message DammV2CreatePool {
  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;
}