ADR-005: SDK-Level Batch Creation
Context
Section titled “Context”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:
- On-chain
create_batchinstruction — the program accepts an array of recipients and amounts, creating all streams in a single invocation. - SDK-level batch — the SDK packs multiple
create_streaminstructions into one Solana transaction.
Decision
Section titled “Decision”Use SDK-level batch creation — pack multiple create_stream instructions into a single Solana transaction instead of adding an on-chain create_batch instruction.
How It Works
Section titled “How It Works”- The SDK derives all stream PDA addresses upfront using predicted
vesting_countvalues. - Multiple
create_streaminstructions are built and added to a singleTransaction. - Solana processes instructions sequentially within a transaction.
CreatorConfig.vesting_countincrements after each instruction, so the next instruction picks up the next nonce naturally. - 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);Alternatives Considered
Section titled “Alternatives Considered”| Approach | Pros | Cons |
|---|---|---|
On-chain create_batch instruction | More streams per transaction; simpler client code | Complex 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 level | Limited to ~3-4 streams per tx due to 1232-byte limit |
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- 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_streaminstruction 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.
Negative
Section titled “Negative”- 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_countbefore sending the transaction. If another transaction incrementsCreatorConfigbetween prediction and submission, the batch fails. In practice, this is rare for single-user scenarios but worth noting.
Future Consideration
Section titled “Future Consideration”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.