Skip to content

ADR-005: SDK-Level Batch Creation

Founders launching tokens often need to create vesting schedules for many recipients at once — team members, advisors, investors, community allocations. A single create_stream instruction per recipient would require one transaction per recipient, each with its own signature and base fee.

Two approaches can solve this:

  1. On-chain create_batch instruction — the program accepts an array of recipients and amounts, creating all streams in a single invocation.
  2. SDK-level batch — the SDK packs multiple create_stream instructions into one Solana transaction.

Use SDK-level batch creation — pack multiple create_stream instructions into a single Solana transaction instead of adding an on-chain create_batch instruction.

  1. The SDK derives all stream PDA addresses upfront using predicted vesting_count values.
  2. Multiple create_stream instructions are built and added to a single Transaction.
  3. Solana processes instructions sequentially within a transaction. CreatorConfig.vesting_count increments after each instruction, so the next instruction picks up the next nonce naturally.
  4. Each transaction is one signature, one base fee, and atomic all-or-nothing.
const tx = new Transaction();
let count = config.vestingCount;
for (const [recipient, amount] of recipients) {
const [streamPDA] = getStreamPda(creator, recipient, mint, count, PROGRAM_ID);
// ... derive other PDAs ...
tx.add(await program.methods.createStream(...).accountsPartial(...).instruction());
count = count.add(new BN(1));
}
const txSig = await program.provider.sendAndConfirm(tx);
ApproachProsCons
On-chain create_batch instructionMore streams per transaction; simpler client codeComplex on-chain program; array validation logic; potential for partial write failures; harder to test; more surface area for bugs
SDK-level batch (chosen)Keeps on-chain program simple; uses existing instructions; tested independently; atomic at transaction levelLimited to ~3-4 streams per tx due to 1232-byte limit
  • Simple on-chain program: The core instructions stay small and focused. No array-handling logic, no partial-failure edge cases, no batch-specific error codes.
  • Tested independently: Each create_stream instruction is tested in isolation. SDK-level composition inherits all existing test coverage.
  • Atomic batches: All streams in a transaction succeed or fail together. No partial state.
  • Single signature: All streams in one transaction carry one transaction signature fee.
  • Transaction size limit: Solana’s ~1232-byte transaction limit constrains each batch to approximately 3–4 streams. For a team of 100, you need 25–33 transactions.
  • Sequential, not parallel: Instructions within a transaction execute sequentially, not concurrently. For large batches, total execution time scales linearly.
  • Prediction dependency: PDA derivation requires predicting vesting_count before sending the transaction. If another transaction increments CreatorConfig between prediction and submission, the batch fails. In practice, this is rare for single-user scenarios but worth noting.

If batch size becomes a bottleneck at scale (e.g., DAOs distributing to 1,000+ members), a native create_batch instruction can be added in v2. The on-chain CreatorConfig serialization via vesting_count already supports it — batch creation would just be a different path to the same state.