Repository navigation
core: Soroban RPC client with retry, timeout, and circuit breaking - #70
Merged
joelpeace48-cell merged 1 commit intoAug 25, 2026
Merged
Conversation
Adds src/soroban: a resilient wrapper around Soroban RPC, since public RPC endpoints are rate-limited and intermittently unavailable. - Every call is bounded by a timeout enforced by racing against a timer (not by relying on the callee to honor an AbortSignal), so a hung transport still returns rather than blocking forever. - Idempotent operations (simulate, getTransactionStatus) get exponential backoff with full jitter, bounded by maxAttempts. - A circuit breaker trips after consecutive failures and fails fast while open, rather than queuing requests behind a dead endpoint. - Transaction submission is never retried by the client. The only recovery path after a submit error is pollUntilConfirmed, which polls by transaction hash — blind-retrying a submit is how double-spends happen. - Errors are typed (SorobanTransportError / SorobanTimeoutError / SorobanSimulationError / SorobanContractError / CircuitOpenError) instead of opaque strings, so callers can branch on failure kind. - Tests run against a mocked RPC transport, covering transient transport failures, a hung/timed-out call, circuit-open behavior after repeated failures, and the poll-after-429 recovery path. Kept to a lightweight fetch-based JSON-RPC transport rather than pulling in the full @stellar/stellar-sdk, so the higher-level transaction builders can be layered on top later without touching the retry/timeout/circuit-breaking behavior added here. Closes FinesseStudioLab#44.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
There was no Soroban integration at all — no client, no transaction handling — despite that being the service's stated purpose. Public RPC endpoints are rate-limited and intermittently unavailable, so a naive implementation would be flaky in exactly the way that erodes trust in a custody-adjacent service.
What this adds
New module:
src/soroban/AbortSignal— so a hung transport still returns (with a timeout error) instead of blocking forever.maxAttempts— applied only to idempotent operations (simulate,getTransactionStatus).src/soroban/circuitBreaker.ts) that trips after consecutive failures and fails fast while open, instead of queuing requests behind a dead endpoint.submit()is never retried by the client. The only recovery path after a submit error ispollUntilConfirmed(), which polls by transaction hash — blind-retrying a submit is how double-spends happen.submitAndConfirm()chains submit → poll for callers that want the full flow.SorobanTransportError,SorobanTimeoutError,SorobanSimulationError,SorobanContractError,CircuitOpenError— so callers can branch on failure kind instead of parsing message strings.Kept to a lightweight
fetch-based JSON-RPC transport rather than pulling in the full@stellar/stellar-sdk, so this stays small and easy to mock, and the SDK's higher-level transaction builders can be layered on top later without touching the retry/timeout/circuit-breaking behavior here.Testing
src/soroban/client.test.tsruns against a mockedRpcTransport, covering:submit()never being retried internally, even on failureAll existing tests continue to pass;
npm run lint,npm run build,npm test, andnpm audit --audit-level=highare all clean on this branch.Scope note
This PR only adds
src/soroban/**(new files) — it does not touch any file shared with the other two PRs open against this issue tracker (#54,#58), so it should apply independently of merge order.Closes #44.