Developer docs

PTBVM

A neutral on-chain composition VM for Solana. Chain independent programs into one atomic transaction where the runtime result of step N feeds step N+1, with no hardcoded router. Token-2022 composes with zero special-casing.

The gap

Sui has Programmable Transaction Blocks: the runtime return of call N flows into call N+1. Solana has atomic multi-instruction txs and set/get_return_data, but top-level instructions are independent and cannot consume each other's runtime return values. Every protocol that needs this hardcodes its own router. PTBVM is the neutral substrate that does it for any program.

Model

A Plan is an ordered list of Steps. Each step invokes a target program, can splice register values into its instruction data, can read accounts from registers, can capture its return value into a register, and can open/close a hot-potato obligation. The VM owns a per-owner register file PDA (8 u64 slots). After the plan, every obligation opened must be closed or the tx reverts.

brick   = a Step (one program call)
compose = registers flowing between steps
gate    = obligations must net to zero before finalize

SDK quickstart

import { PlanBuilder, initRegistersIx, disc, u64le } from "@/lib/ptbvm";

// 1. one-time: create your register file
const tx = new Transaction().add(initRegistersIx(owner));

// 2. build a plan: swap -> capture out -> deposit that exact amount
const plan = new PlanBuilder(owner);
plan.step({
  program: SWAP,
  accounts: [{ pubkey: pool, isWritable: false }],
  data: Buffer.concat([disc("global", "swap_mock"), u64le(100)]),
  captureInto: 0,                       // store swap's u64 return in reg 0
});
plan.step({
  program: VAULT,
  accounts: [{ pubkey: vault, isWritable: true }],
  data: Buffer.concat([disc("global", "deposit"), u64le(0)]),
  dataSplices: [{ offset: 8, register: 0 }],   // splice reg0 over the amount
});

// 3. one atomic tx
await sendTransaction(new Transaction().add(plan.compile()), connection);

Step fields

  • program · target program to CPI into.
  • accounts · fixed pubkeys, or a register holding a pubkey from an earlier step.
  • data · the inner instruction data.
  • captureInto · store this step's u64 return value in register N.
  • dataSplices · overwrite 8 bytes of data at an offset with register N (e.g. an amount).
  • obligation · open / close the hot-potato counter.

Token-2022

PTBVM is program-agnostic, so Token-2022 and its extensions (transfer fees, transfer hooks) compose as plan steps with no special-casing. Build a Token-2022 instruction the normal way and hand its (programId, keys, data) to a step.

Try it

Run a pre-built plan with no code at /recipes, or assemble your own in the 3D builder.

On-chain

Program (devnet): A2kR2uTGLYfCqimqF4piRDh7aHfLRDf4gBg8LvmfMLrz