Skip to content

feat: add createBatchStreams for bulk stream creation - #391

Open
Viky207 wants to merge 2 commits into
conduit-protocol:mainfrom
Viky207:feature/create-batch-streams
Open

feat: add createBatchStreams for bulk stream creation#391
Viky207 wants to merge 2 commits into
conduit-protocol:mainfrom
Viky207:feature/create-batch-streams

Conversation

@Viky207

@Viky207 Viky207 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Overview

This PR adds a batch stream creation API that allows callers to create many streams while minimizing the number of user signatures required.

Changes

  • Added StreamsModule.createBatchStreams(configs: StreamConfig[])
  • Builds batched contract-call transactions with multiple invokeHostFunction operations
  • Chunks larger request sets into multiple transactions to stay within Soroban transaction limits
  • Added validation and simulation/assembly handling consistent with the existing stream creation flow

Closes #338
Closes #339

@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@Viky207 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Jaydbrown Jaydbrown left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the chunking/validation structure is solid, but there's a real correctness bug in the multi-chunk case that needs fixing before merge:

Sequence number collision across chunks: createBatchStreams() calls buildBatchContractCallTx() once per chunk, and each call independently does server.getAccount(caller) to fetch a fresh Account object:

// src/soroban.ts, buildBatchContractCallTx
const server  = createRpcServer(rpcUrl);
let account;
try {
  account = await server.getAccount(caller);
} catch (err) { ... }
...
const builder = new TransactionBuilder(account, { ... });

TransactionBuilder.build() reads source.sequenceNumber() + 1 and only calls source.incrementSequenceNumber() on that same Account object afterward (see node_modules/@stellar/stellar-base/lib/transaction_builder.js:565,623). Since none of these transactions are submitted on-chain before the next chunk's getAccount() call runs, every chunk fetches the same last-confirmed on-chain sequence number and produces a transaction with the same sequence + 1.

Concretely: with MAX_BATCH_SIZE = 10, calling createBatchStreams() with 11+ configs (2 chunks) returns transactions that all carry the identical sequence number. A caller who signs and submits them in order will have the first one succeed and every subsequent one rejected on-chain with a bad-sequence error — silently defeating the entire point of a "bulk stream creation" API, since it doesn't actually work past 10 streams.

The existing test ('chunks configs into groups of MAX_BATCH_SIZE') only exercises exactly 10 configs → 1 chunk, so it can't catch this — there's no test with 11+ configs / 2+ chunks asserting the returned transactions have distinct, incrementing sequence numbers.

Suggested fix: fetch the Account once in createBatchStreams() (or thread it through buildBatchContractCallTx as an optional parameter instead of having that function call getAccount() itself), and reuse the same Account object across chunks so each new TransactionBuilder(account, ...) call sees the previous chunk's incremented sequence. Please also add a regression test with >10 configs asserting the returned transactions have strictly increasing sequence numbers.

Everything else here (validation-before-work, chunking logic, doc comments) looks good — happy to take another look once this is fixed.

Viky207 and others added 2 commits July 30, 2026 15:29
…t-protocol#338, conduit-protocol#339)

- Add StreamConfig type alias for CreateStreamParams in types/index.ts
- Add buildBatchContractCallTx helper in soroban.ts for multi-operation transactions
- Add createBatchStreams(configs) method to StreamsModule that:
  - Validates all configs before processing
  - Chunks configs into groups of MAX_BATCH_SIZE (10) to respect Soroban tx size limits
  - Builds a single transaction with multiple invokeHostFunction operations per chunk
  - Simulates and assembles each transaction, returning prepared Transaction[]
  - Returns empty array for empty input
- Add comprehensive tests for createBatchStreams in streams-success.test.ts
The original approach here (from before this session's `main` gained a
proper multi-transaction batch primitive) built one transaction per chunk
of MAX_BATCH_SIZE configs, packing multiple invoke_host_function operations
into it via repeated addOperation() calls -- Soroban permits exactly one
invoke_host_function per transaction, so that would have been rejected by
the network outright, on top of a real sequence-number collision bug
(fetching a fresh Account per chunk, so every chunk after the first got the
same last-confirmed sequence number and only the first chunk's transaction
could ever land on-chain).

Reimplemented as a thin StreamsModule method that builds each config's
create_stream args exactly like create() does, then delegates the actual
transaction construction to buildBatchTransactions() (batch-tx.ts, already
merged) -- which builds one real transaction per operation and fetches the
sender's sequence number once, incrementing it per index, so every
transaction in the batch stays independently submittable regardless of
batch size. Per-config client-side validation is isolated (one bad config
doesn't block the rest), mirroring batchWithdraw()'s existing
independent-per-item reporting.

Adds a regression test asserting 15 configs (spanning what would have been
2 chunks under the old MAX_BATCH_SIZE=10 design) get 15 distinct, strictly
increasing sequence numbers and that the source account is fetched exactly
once.
@Jaydbrown
Jaydbrown force-pushed the feature/create-batch-streams branch from add136d to ae6a3ed Compare July 30, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Implement batch stream creation Feature: Support Freighter wallet directly in SDK

3 participants