Skip to content

feat(backend): enhance error recovery for Transaction Signer#1010

Merged
emdevelopa merged 1 commit into
emdevelopa:mainfrom
Chucks1093:feat/issue-915-916-917-918
Jun 25, 2026
Merged

feat(backend): enhance error recovery for Transaction Signer#1010
emdevelopa merged 1 commit into
emdevelopa:mainfrom
Chucks1093:feat/issue-915-916-917-918

Conversation

@Chucks1093

Copy link
Copy Markdown
Contributor

Closes #915
Closes #916
Closes #917
Closes #918

What was done

frontend/src/lib/freighter.ts — typed error recovery for the Transaction Signer

The existing implementation swallowed all errors into a single generic string, making it impossible for callers to distinguish a user rejection from a network mismatch or a wallet not being installed. This change introduces structured error recovery across all four exported functions.

TransactionSignerError and SignerErrorCode

A new typed error class with a code discriminant:

Code When thrown
WALLET_UNAVAILABLE Freighter is not installed or hasn't granted access
USER_REJECTED User explicitly declined signing in the Freighter popup
INVALID_XDR Empty XDR input or unparseable XDR envelope
NETWORK_MISMATCH Freighter's selected network differs from the app's passphrase
SUBMISSION_FAILED Horizon rejected or returned no hash
PUBLIC_KEY_FETCH_FAILED getPublicKey() threw after wallet was confirmed available
UNKNOWN Freighter error that doesn't match any known pattern

classifyFreighterError()

Internal helper that pattern-matches Freighter error messages and maps them to the correct SignerErrorCode. USER_REJECTED is checked first so the UI can offer a retry prompt rather than showing an error banner.

getFreighterPublicKey()

Now calls isFreighterAvailable() as a pre-flight check and throws WALLET_UNAVAILABLE immediately, rather than letting the Freighter SDK produce an opaque failure.

signWithFreighter()

  • Guards empty transactionXDRINVALID_XDR before any async work
  • Pre-flight availability check → WALLET_UNAVAILABLE
  • Delegates Freighter sign errors to classifyFreighterError()
  • Reuses the hardened getFreighterPublicKey() path for the post-sign public key fetch

submitTransaction()

  • Guards empty signedXDRINVALID_XDR
  • Wraps TransactionBuilder.fromXDR in its own try/catch → INVALID_XDR with the original parse message
  • Re-throws TransactionSignerError instances as-is (no double-wrapping)
  • Maps all other Horizon errors → SUBMISSION_FAILED with the original message preserved in cause

frontend/src/lib/freighter.test.ts (new)

12 vitest cases covering every error code path and the success path for all four functions:

  • isFreighterAvailable — allowed / throws
  • getFreighterPublicKey — unavailable, success, fetch failure
  • signWithFreighter — empty XDR, unavailable, user rejected, success
  • submitTransaction — empty XDR, bad parse, success, missing hash

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

@Chucks1093 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel.

A member of the Team first needs to authorize it.

…opa#915)

Replaces the Transaction Signer's bare catch-and-rethrow pattern with
typed, classified errors so callers can branch on failure kind without
string-matching.

Changes to frontend/src/lib/freighter.ts:

- Added TransactionSignerError class with a SignerErrorCode discriminant
  (WALLET_UNAVAILABLE | USER_REJECTED | INVALID_XDR | NETWORK_MISMATCH |
  SUBMISSION_FAILED | PUBLIC_KEY_FETCH_FAILED | UNKNOWN) so upstream
  handlers (usePayment, UI error boundaries) can show context-specific
  messages instead of a generic fallback

- Added classifyFreighterError() which pattern-matches Freighter error
  messages and maps them to the appropriate code; USER_REJECTED is
  detected first so wallet UX can prompt a retry without showing an
  error banner

- getFreighterPublicKey() now calls isFreighterAvailable() before
  attempting the API call, throwing WALLET_UNAVAILABLE immediately if
  Freighter is not installed or has not granted access, rather than
  letting the SDK throw an opaque error

- signWithFreighter() validates the XDR is non-empty (INVALID_XDR),
  checks availability (WALLET_UNAVAILABLE), and delegates Freighter
  errors to classifyFreighterError(); the public-key fetch after signing
  reuses the hardened getFreighterPublicKey() path

- submitTransaction() validates non-empty XDR, wraps fromXDR() in its
  own try/catch with INVALID_XDR, and re-throws Horizon errors as
  SUBMISSION_FAILED while passing through any TransactionSignerError
  that already has a code (avoids double-wrapping)

Added frontend/src/lib/freighter.test.ts with 12 vitest cases covering
all error codes across all four exported functions.

Closes emdevelopa#915
Closes emdevelopa#916
Closes emdevelopa#917
Closes emdevelopa#918
@Chucks1093 Chucks1093 force-pushed the feat/issue-915-916-917-918 branch from 0e50f43 to 79a2a65 Compare June 25, 2026 16:52
@drips-wave

drips-wave Bot commented Jun 25, 2026

Copy link
Copy Markdown

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

@emdevelopa emdevelopa merged commit 9be3a2d into emdevelopa:main Jun 25, 2026
1 of 5 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

2 participants