The PlanBuilder client
Assemble a plan in TypeScript and compile it to one instruction.
PlanBuilder is the TypeScript client. You add steps to it, and compile() returns a single TransactionInstruction against the PTBVM program.
The shape of a step
| Field | Type | Note |
|---|---|---|
| program | PublicKey | The program this step invokes via CPI. |
| accounts | AcctInput[] | A fixed pubkey, a register-sourced account, or the authority PDA. |
| data | Uint8Array | The inner instruction data (discriminator + args). |
| dataSplices | { offset, register, width }[] | Register values patched into data before the call. |
| captureInto | number | Register slot to store this step's u64 return value. |
| capturePubkey | boolean | Capture a returned pubkey instead of a u64. |
| signed | boolean | Mark this CPI as signed by the plan's authority PDA. |
| obligation | "open" | "close" | Open or close a hot-potato obligation, paired by obligationTag. |
Interning accounts
Every distinct pubkey you reference is interned into an account pool, so it is listed once and referred to by index. You do not manage indices yourself, pass a PublicKey and the builder deduplicates it. An account can also come from a register ({ register: n }) or be the plan's authority PDA ({ authority: true }).
const plan = new PlanBuilder(owner);
plan.step({ program: A, accounts: [{ pubkey: pool }], data, captureInto: 0 });
plan.step({ program: B, accounts: [{ pubkey: vault, isWritable: true }], data,
dataSplices: [{ offset: 8, register: 0 }] });
const ix = plan.compile(); // one instruction, N inner callsIn this section
- Accounts and PDAs: The registers PDA, the authority PDA, and how accounts are indexed.
- Recipes and the builder: Pre-built plans you can run in one click, and the 3D builder.