Skip to content

feat(client): classify Soroban simulation failures and opt-in state restoration - #311

Merged
Dione-b merged 1 commit into
mainfrom
feat/soroban-simulation-restore
Oct 20, 2026
Merged

Dione-b merged 1 commit into
mainfrom
feat/soroban-simulation-restore

Conversation

@Dione-b

@Dione-b Dione-b commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Supersedes #255 by @deslawson (credited as co-author). That branch no longer built after two merges from main, and the author did not respond to the review, so this PR rebuilds the same feature on current main with the review points addressed. Closes #240.

Motivation

Soroban simulation failures such as an unfunded source account, budget or fee limits, and archived contract state all surfaced as generic CAATINGA_XDR_PREPARE_FAILED / CAATINGA_XDR_SUBMIT_FAILED errors, or as raw SDK errors, with no way to restore archived state through the client.

Behavior

  • New public error codes (additive): CAATINGA_SIMULATION_ACCOUNT_NOT_FOUND, CAATINGA_SIMULATION_RESOURCE_LIMIT, CAATINGA_SIMULATION_ENTRY_ARCHIVED.
  • invoke(method, args, { restore: true }) forwards restore and a wallet signer to the generated binding, which submits a RestoreFootprint transaction first.
  • Where errors are classified:
    • read() / simulate(), including errors thrown by the binding's result getter (stellar-sdk SimulationFailedError / ExpiredStateError);
    • invoke(), including errors raised inside signAndSend;
    • while the binding builds the method.

Changes from #255 (review points)

  • assertWalletNetwork still runs before createTransaction, so a restore is never signed on the wrong network. There is a test for this.
  • Classifier (moved to the neutral module packages/client/src/errors/simulation-error.ts):
    • matches field values only, never field names;
    • checks for a non-null restorePreamble directly;
    • patterns are anchored to real strings, such as Error(Budget, ExceededLimit), txNO_ACCOUNT, ENTRY_ARCHIVED and stellar-sdk's "You need to restore some contract state";
    • "…429: rate limit exceeded" and { restorePreamble: null } no longer match; both cases are tested.
  • Non-simulation errors thrown while building the method (for example argument conversion) propagate unchanged instead of becoming XDR_PREPARE_FAILED.
  • Hint and docs no longer claim that restorePreamble is kept on error.cause.
  • restore option key: an object is read as options only when every key is an option key (main's heuristic). An argument object with other keys is kept, and docs explain how to pass a contract arg named restore.
  • Tests added for invoke-args, the result getter, signAndSend, the restore signer's XDR_SIGN_FAILED paths (rejection and empty result), and classifier false positives.

Tests

pnpm typecheck, pnpm lint, pnpm format, and pnpm test all pass locally:

Package Tests
client 185
core 658
cli 313
zk 100

Release impact

Minor for @caatinga/core and @caatinga/client; see .changeset/soroban-simulation-restore.md.

Compatibility: callers that branch on XDR_PREPARE_FAILED / XDR_SUBMIT_FAILED for these specific failures now receive the new codes. Other errors are unchanged.

Rollback: revert this PR. No artifacts or persisted data are affected.

…estoration

Rebuilds #255 by @deslawson on current main.

- New public codes: CAATINGA_SIMULATION_ACCOUNT_NOT_FOUND,
  CAATINGA_SIMULATION_RESOURCE_LIMIT, CAATINGA_SIMULATION_ENTRY_ARCHIVED.
- Classifier lives in packages/client/src/errors/simulation-error.ts and
  matches only field values (never field names) against strings Soroban
  RPC, stellar-core and stellar-sdk emit, plus a non-null restorePreamble,
  so "429: rate limit exceeded" is no longer a resource limit.
- Errors thrown by the binding's result getter (read/simulate) and inside
  signAndSend (invoke) are classified; unknown errors raised while the
  binding builds the method propagate unchanged.
- invoke(method, args, { restore: true }) forwards restore and a wallet
  signer to the binding; assertWalletNetwork still runs before
  createTransaction, and restore signing failures map to XDR_SIGN_FAILED.
- Changeset documents the code changes for callers that branched on
  XDR_PREPARE_FAILED / XDR_SUBMIT_FAILED.

Closes #240

Co-authored-by: Lex0865 <destinylawson007@gmail.com>
@Dione-b
Dione-b merged commit a32263c into main Oct 20, 2026
3 checks passed
@Dione-b
Dione-b deleted the feat/soroban-simulation-restore branch October 20, 2026 17:59
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.

client: all simulate failures collapse to XDR_PREPARE_FAILED; restore/archival not handled

1 participant