Skip to content

[1625] [frontend] Map Freighter wallet errors to error codes and use backoff in wallet polling - #1699

Merged
Junirezz merged 5 commits into
Junirezz:mainfrom
ToryMic:fix/1625-frontend-map-freighter-wallet-errors-to-error-codes-and-use-backoff-in-wallet-polling
Oct 19, 2026
Merged

Junirezz merged 5 commits into
Junirezz:mainfrom
ToryMic:fix/1625-frontend-map-freighter-wallet-errors-to-error-codes-and-use-backoff-in-wallet-polling

Conversation

@ToryMic

@ToryMic ToryMic commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1625

Closes 1625

Summary

useWalletConnection treated every getAddress failure as "no address": Freighter
reports some failures in-band ({ address: "", error: { code, message } })
instead of throwing, and that payload was silently dropped. Wallet polling was also
a fixed setInterval, so a failing/absent Freighter extension was polled forever at
the same rate.

This PR maps those in-band errors onto the existing wallet error codes (and the
existing i18n keys), funnels every wallet_session_start write through one helper,
and replaces the fixed interval with a capped exponential backoff.

Changes

Freighter errors map to codes + i18n keys

  • frontend/src/lib/walletConnectionState.ts: new classifyFreighterApiError()
    which classifies an in-band Freighter payload (getAddress, isAllowed,
    isConnected, …) with the same rules as thrown errors and keeps the original
    message plus the Freighter code for diagnostics.
  • frontend/src/hooks/useWalletConnection.ts: performConnect now classifies
    getAddress().error before falling back to NO_ADDRESS, dispatching
    CONNECT_FAILED with a typed error. The UI keeps rendering copy from
    walletErrorI18nKeys(code) (WalletConnect), so a user rejection now shows the
    rejection copy instead of the generic "no address" text.

wallet_session_start has a single writer

  • frontend/src/lib/walletSession.ts: new WALLET_SESSION_START_KEY,
    getWalletSessionStart() and startWalletSession().
  • useWalletConnection.ts and frontend/src/context/AuthContext.tsx now read/write
    that key only through these helpers (no direct localStorage access for this key).

Polling backs off after failures

  • useWalletConnection.ts: the poll loop is now a recursive setTimeout using the
    exported pure helper getWalletPollDelay(consecutiveFailures). The delay doubles
    per consecutive failure (10s → 20s → 40s → …) and is capped at 60s (1.6s in
    tests); any successful poll resets the counter. Errors during a poll are caught,
    logged and counted as a failure instead of escaping the setInterval callback.

Tests

  • New frontend/src/hooks/useWalletConnection.test.tsx:
    • a Freighter error response ({ address: "", error: { code: 3, message: "User rejected the request." } })
      produces USER_REJECTED + the matching walletErrorI18nKeys, not NO_ADDRESS;
    • a permission payload produces PERMISSION_DENIED and keeps the message + code;
    • no address and no error still falls back to NO_ADDRESS;
    • a successful connect writes wallet_session_start through lib/walletSession;
    • getWalletPollDelay grows per failure and is capped;
    • with fake timers, a permanently failing Freighter is polled ~4 times in 1.5s
      (the fixed 100ms test interval would poll ~15 times).
  • frontend/src/lib/walletConnectionState.test.ts: classifyFreighterApiError
    cases (rejection, permission, not-installed → non-retryable, unknown payload,
    code suffix).
  • frontend/src/lib/walletSession.test.ts: session-start helper cases.
  • frontend/src/components/SessionExpiryWarning.test.tsx: mock switched to
    importOriginal so the real session helpers stay available.

Verification

  • TZ=UTC npx vitest run → 129 files / 1391 tests passing
  • npm run lint → 0 errors (37 pre-existing warnings, unchanged)
  • npx tsc -b → clean
  • npm run build → exit 0
  • npm run check-size → 7/7 checks passed

Notes

Contracts lint + test + build, Rust + WASM CI, Cargo Security Audit,
Slither, NPM/PNPM Audit, GitHub Dependency Review and
Governance & PR Standards Validation fail identically on main (verified against
the current baseline PRs); they are unrelated to this change.

ToryMic added 5 commits October 19, 2026 06:42
Freighter surfaces some failures in-band (`{ address: "", error }`)
instead of throwing, and `useWalletConnection` dropped that payload, so
every `getAddress` failure collapsed into a generic NO_ADDRESS error.

- add `classifyFreighterApiError` so in-band Freighter payloads map onto
  the existing wallet error codes (and therefore the existing i18n keys
  rendered by `WalletConnect`)
- classify `getAddress` errors before falling back to NO_ADDRESS
- route every `wallet_session_start` write through new
  `getWalletSessionStart` / `startWalletSession` helpers in
  `lib/walletSession`, and read it from `AuthContext` via the same helper
- replace the fixed `setInterval` wallet poll with a recursive
  `setTimeout` that backs off exponentially (capped) after consecutive
  failures and resets on success
- cover the error mapping, the session-start write and the polling
  backoff with unit tests

Closes 1625
@ToryMic
ToryMic requested a review from Junirezz as a code owner October 19, 2026 11:01
@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

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

@Junirezz
Junirezz merged commit f18eecc into Junirezz:main Oct 19, 2026
20 of 31 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.

[frontend] Map Freighter wallet errors to error codes and use backoff in wallet polling

2 participants