Repository navigation
feat(stellar): add cancellation and timeouts to the remaining Horizon helpers - #255
Merged
truthixify merged 4 commits intoOct 16, 2026
Conversation
… helpers findStrictReceivePath(), buildMultisigStealthWithdraw() and submitOfflineStellarTransaction() accept an AbortSignal and the same timeouts as the Horizon and RPC clients. Failures map onto the error taxonomy: the new RPCAbortedError, RPCTimeoutError, RPCRequestError and HorizonResponseError. Refs wraith-protocol#235
The cancellation and timeout support in the one-shot Horizon helpers brings the Stellar ESM entry to 30.68 KB; develop measured 30.22 KB of the 30.5 KB budget. Refs wraith-protocol#235
|
@aratass 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! 🚀 |
truthixify
approved these changes
Oct 16, 2026
truthixify
left a comment
Contributor
There was a problem hiding this comment.
Cancellation and deadlines are consistently threaded through the remaining Horizon helpers. The focused timeout/error suite passes 75/75 locally and all required CI checks are green.
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.
Closes #235.
Summary
findStrictReceivePath(),buildMultisigStealthWithdraw()andsubmitOfflineStellarTransaction()could not be cancelled, and the account lookup and the submission had no deadline, so a stalled Horizon request could hang them. This PR brings all three in line with the Horizon and RPC clients from #202:Optional
signalandtimeoutson each helper. Path finding and the multisig account lookup take them in their options object; submission takes a new optional third argument,submitOfflineStellarTransaction(xdr, network, { signal, timeouts }).Every failure maps onto the error taxonomy.
RPCAbortedError(WRAITH/NETWORK/RPC_ABORTED), the signal'sreasononcauseRPCTimeoutError,attempt: 1RPCRequestError, the Horizon body oncontext.responseTextHorizonResponseErrorfrom fix(stellar): read and validate Horizon strict-receive responses #251, with the failing part onfieldFake-timer tests for every path of all three helpers.
Design
Built on fix(stellar): read and validate Horizon strict-receive responses #251. Path finding keeps its request format, record validation and capped body read; this PR only links the caller's signal to its
AttemptDeadlineand letstimeoutsoverride the Horizon client defaults.The account lookup and the submission go through one internal helper,
src/chains/stellar/request.ts(requestHorizonJson), which sends a single attempt through the sameAttemptDeadline. The fetch and the body read race the deadline, so a fetch that ignores the signal still times out, and timers are cleared once the request settles.AttemptDeadlinegainsabort(error). A caller abort cancels the in-flight fetch and rejects withRPCAbortedErrorinstead of a bareAbortError. An already aborted signal rejects before anything is sent.No retries. These helpers made one request before and still do; a submission must not be repeated blindly.
Defaults:
findStrictReceivePath,buildMultisigStealthWithdrawsubmitOfflineStellarTransactionHorizon answers
POST /transactionsonly once the transaction is in a ledger or its own wait expires, so a short headers timeout would cut off normal submissions. The JSDoc and docs warn that a timed-out or aborted submission may still be applied, so callers should look up the hash before resubmitting.BuildMultisigStealthWithdrawOptionsalready hastimeout, the transaction's validity window in seconds. Its doc now says so, to keep it apart from the newtimeouts.Behaviour changes (under Changed in the CHANGELOG)
buildMultisigStealthWithdraw(): a non-2xx status from the account lookup is now anRPCRequestErrorinstead of a plainError, and an incomplete account record is aHorizonResponseError.submitOfflineStellarTransaction(): reports the full/transactionsURL onRPCRequestError(it was the base URL), throwsHorizonResponseErrorfor a success body that is not a JSON object, and gives up after 60 s by default.{ timeouts: { requestMs: 0 } }restores waiting indefinitely.Semver
Additive: new optional
signalandtimeoutsoptions, a new optional third argument onsubmitOfflineStellarTransaction(), and the newRPCAbortedErrorexport. The error-type changes and the 60 s submission default above are behaviour changes, so the CHANGELOG entries sit in the Upcoming: 2.0.0 section (Added and Changed).Bundle size
After #251, develop measures 30.22 kB of the 30.5 kB Stellar ESM budget; this PR brings it to 30.68 kB. As
BUNDLE_SIZE.mdasks, the budget change is in the same PR, in its ownchore(size)commit, with a note in the table (new budget 31 kB). Happy to drop that commit and trim instead if you'd rather keep 30.5 kB.Tests
test/chains/stellar/helper-timeouts.test.ts(35 tests). Each helper runs the same nine fake-timer cases: the signal reachesfetchand no timers are left; an already aborted signal (no fetch); an abort in flight; the default timeout fires at exactly its value, not 1 ms before; custom timeouts; a fetch that ignores the abort; a body that stalls after the headers; an HTTP error with its body; a success body that is not JSON. Plus account record and submission response checks.test/errors.test.ts: instanceof chain, code, docs link and non-serialisedcauseforRPCAbortedError.Checks run locally:
pnpm format:check,pnpm build,pnpm test(1,527 SDK tests and the Svelte package),pnpm test:types,pnpm test:exports,pnpm size,pnpm api:check(reports updated inetc/) andpnpm pack:check.Note
docs/offline-signing.mdimports the offline helpers from@wraith-protocol/sdk/chains/stellar, butsrc/chains/stellar/index.tsdoes not export them. I left the exports unchanged to keep this PR to the issue. Happy to export them here or in a follow-up.