Skip to content

feat(soroban-client): batch ledger entry fetch helper (#222) - #273

Merged
manoahLinks merged 2 commits into
crowdpass-live:mainfrom
menawar:feat/issue-222-batch-ledger-entries
Apr 27, 2026
Merged

feat(soroban-client): batch ledger entry fetch helper (#222)#273
manoahLinks merged 2 commits into
crowdpass-live:mainfrom
menawar:feat/issue-222-batch-ledger-entries

Conversation

@menawar

@menawar menawar commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds batchGetLedgerEntries to the tokenbound SDK, a helper for fetching many ledger entries in one workflow with partial-failure handling.

The Soroban RPC's getLedgerEntries:

  • caps each call at ~100 keys,
  • silently omits missing keys from the response,
  • bubbles a single failure for the whole call.

That makes it awkward to consume directly in any read path that wants to fan-out across many keys (account state for a list of TBAs, contract data for a paginated list of events, etc.). This helper wraps the workflow so callers hand it a flat xdr.LedgerKey[] and get back an aligned, observable result.

Behaviour

  • Chunking — input is split into chunks of chunkSize (default DEFAULT_BATCH_CHUNK_SIZE = 100). Override per call if the RPC is configured differently.
  • Concurrency — chunks run in parallel up to concurrency (default DEFAULT_BATCH_CONCURRENCY = 4).
  • Alignment — output entries[i] corresponds to input keys[i]:
    • LedgerEntryResult if the entry was returned.
    • null if the chunk succeeded but no entry came back for that key (i.e. not present on-chain).
    • undefined if the chunk that contained that key failed (see errors).
  • Partial failures — per-chunk RPC errors are captured in result.errors along with the input indexes they covered. Sibling chunks complete and contribute their entries.
  • AggregationlatestLedger is the max across successful chunks; found / missing / failed give a quick status read suitable for telemetry / UI badges.
  • Duplicates — repeated input keys all receive the matching entry without an extra RPC trip per duplicate (a small request still includes both, but a single response entry is fanned back out).
  • Custom identitykeyId is overridable; defaults to the canonical key.toXDR("base64").

The helper takes a structural LedgerEntriesFetcher (the shape of rpc.Server), so it composes with the existing sdk.rpcServer and is trivial to mock. All @stellar/stellar-sdk imports are type-only, so the module is tree-shakeable and the tests run cleanly under jsdom (the existing repo tests break there because the SDK runtime needs a TextEncoder polyfill).

Changes

  • New soroban-client/sdk/src/batchLedgerEntries.ts with batchGetLedgerEntries, BatchLedgerEntriesOptions, BatchLedgerEntriesResult, BatchLedgerChunkError, LedgerEntriesFetcher, and DEFAULT_BATCH_CHUNK_SIZE / DEFAULT_BATCH_CONCURRENCY constants.
  • Re-exported from sdk/src/index.ts.
  • New __tests__/lib/batchLedgerEntries.test.ts (12 unit tests).
  • sdk/README.md gains a "Batch ledger-entry fetch" section.

Testing

cd soroban-client
npx jest __tests__/lib/batchLedgerEntries.test.ts
# → 12 passed; 0 failed

npx eslint sdk/src/batchLedgerEntries.ts __tests__/lib/batchLedgerEntries.test.ts sdk/src/index.ts
# → clean

npx tsc --noEmit  # 9 errors, all pre-existing on main, none in new files

The 12 tests cover:

  • Empty input — short-circuits without calling the RPC.
  • Single chunk — happy path, all entries returned and aligned.
  • Multi-chunk — verifies the exact chunk boundaries.
  • Missing keys — RPC omits entries → helper aligns null at the right index.
  • Partial chunk failure — one chunk throws, sibling chunks still populate; errors records affected indexes.
  • latestLedger is the max across successful chunks.
  • All chunks fail → latestLedger = 0, every index is failed.
  • Duplicate input keys all receive the matching entry.
  • Stranger keys returned by the RPC (defensive) are ignored, not thrown on.
  • concurrency is actually bounded (in-flight count never exceeds it).
  • chunkSize / concurrency validation rejects 0 and non-finite values.
  • Default chunkSize produces the expected number of RPC calls.

Full npm test shows 18 passing tests (was 6 on main); the same 3 unrelated, pre-existing test-suite-load failures remain — none caused by this PR. Pre-existing TS error count is unchanged at 9.

Notes / known limitations

  • Pre-existing breakage on main: three test suites fail to load on main (tokenbound-sdk.test.ts, Hero.test.tsx, Footer.test.tsx) and npx tsc --noEmit reports 9 pre-existing errors in app/[locale]/create-event/page.tsx and lib/soroban.ts. None are caused or worsened by this PR.
  • The helper does not retry transient errors. The intent is to expose partial failure to the caller so they can decide on retry policy — adding e.g. exponential backoff on per-chunk 5xx responses is a clean follow-up.
  • No automatic deduplication of repeated input keys before sending. A small efficiency optimisation would dedupe keys within each chunk; left for a follow-up because it changes the RPC argument count visibly and isn't typically a hot path.

Closes #222

Adds `batchGetLedgerEntries` to the tokenbound SDK. It wraps the RPC's
`getLedgerEntries` so callers can read many keys in one workflow:

- Chunks input keys over the RPC's per-call cap
  (`DEFAULT_BATCH_CHUNK_SIZE = 100`).
- Runs chunks with bounded concurrency
  (`DEFAULT_BATCH_CONCURRENCY = 4`).
- Aligns the response back to input order. Missing keys (silently
  omitted by the RPC) become `null` at their original index, so callers
  can distinguish "not on-chain" from "chunk RPC failed."
- Tolerates partial failures: a single chunk's RPC error is captured in
  the `errors` array along with the input indexes it covered, rather
  than losing every other chunk's data.
- Aggregates `latestLedger` (max across successful chunks) and
  `found` / `missing` / `failed` counters for monitoring.

The helper takes a structural `LedgerEntriesFetcher` (the shape of
`rpc.Server`) and uses type-only imports of `@stellar/stellar-sdk` so it
remains tree-shakeable and testable without the SDK's runtime (which
currently breaks under jsdom without a TextEncoder polyfill).

Tests: 12 unit tests covering empty input, single chunk, multi-chunk,
missing-key alignment, partial chunk failure, latest-ledger aggregation,
all-chunks-fail, duplicate-key handling, stranger-key tolerance,
concurrency limit, validation of chunkSize/concurrency, and default
chunk size behaviour.

Docs: `sdk/README.md` gains a "Batch ledger-entry fetch" section.

Closes #222
@drips-wave

drips-wave Bot commented Apr 26, 2026

Copy link
Copy Markdown

@menawar 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

@manoahLinks
manoahLinks merged commit e7933d6 into crowdpass-live:main Apr 27, 2026
0 of 3 checks passed
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.

soroban-client: Add batch ledger entry fetch helper

2 participants