Feat/wallet signing ux - #299
Open
N-thnI wants to merge 8 commits into
Open
Conversation
…e warning banners Adds fee inspection to signature_timeout_alert so the user sees what a pending signature will cost before approving it. - app/lib/signature_timeout_alert.ts extracts the estimated fee from a Soroban (minResourceFee) or classic (fee) simulation result and buckets it into none/elevated/exceeded/error severities against a standard 1_000_000 stroop bound. - SignatureTimeoutFeeWarningBanner renders the warning with severity-driven design tokens; SignatureTimeoutAlert composes it with the timeout notice and an optional retry action. - assertSignatureFeeWithinBounds throws for callers that want to hard-stop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gives WalletBadge real interactive affordances built from Tailwind utilities and the repo design tokens. - New optional onClick makes the badge actionable; it then renders as a <button> with hover:bg-surface-card / hover:border-accent-soft, an accent focus-visible ring offset against surface-page, and disabled:opacity-50 / disabled:cursor-not-allowed. The disabled:hover:* variants neutralise hover so a disabled badge stays visually inert. - New disabled prop; the badge also auto-disables while status is loading. - The disconnect control gains matching hover, focus-visible and disabled styling, and sits beside the badge when the badge is itself a button. - Status token classes, data-testid and data-status are unchanged, so the existing WalletBadge suites still pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wallet providers picked from the selector list can hang indefinitely, so every signature request is now raced against a timeout clock. - signWithWalletSelectorTimeout races the provider callback against a 60s default bound. On expiry it aborts the operation through an AbortSignal handed to the provider, zeroes and nulls the request payload, and rejects with WalletSelectorTimeoutError. - A pending-operation registry tracks in-flight requests and is emptied on every exit path (success, provider error, timeout) so no controller or buffer outlives its request. - abortAllWalletSelectorOperations cancels everything in flight for the modal-close / unmount path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Persists the signer's active address so a page reload no longer drops the user back to a disconnected state. - Versioned envelope (address, walletId, networkPassphrase, connectedAt) written to localStorage under transaction_signer_active_session. - Parsing validates the schema version, the Stellar address format and every field, and rejects any payload carrying a secret key, seed, mnemonic or auth token. Invalid payloads are dropped from storage so the next reload starts clean. - TransactionSignerSessionStore mirrors the session in memory, rehydrates on construction, and exposes restore()/clear()/overrideStorage(). - Storage access is guarded throughout, so SSR and blocked-storage browsers degrade to an empty session instead of throwing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@N-thnI 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! 🚀 |
…n merge main independently added modules with the same names this branch created -- app/lib/signature_timeout_alert.ts (Goldii-locks#243-Goldii-locks#247), app/lib/wallet_selector_modal.ts and SignatureTimeoutAlert.tsx -- with entirely different APIs. The merge resolved each file to main's version, which dropped this branch's implementations while keeping its tests, leaving 38 type errors. Re-applies the lost work additively so both feature sets coexist. No name collides between the two APIs, so nothing of main's is overwritten this time: * signature_timeout_alert.ts gains the simulation fee-inspection API (inspectSignatureFee, the severity buckets, the stroop helpers and the two error types) appended after main's timeout/rejection/availability sections, reusing its existing LOG_PREFIX. * wallet_selector_modal.ts gains the timeout-clock API (signWithWalletSelectorTimeout, the abort registry and the memory clearing) appended after main's network-mismatch, caching and loading sections. The standalone alert wrapper this branch had added is dropped: main's SignatureTimeoutAlert now owns that name and covers the timeout UI. The fee banner is instead rendered *inside* it behind two new optional props (simulation, feeLimitStroops), which is closer to the original issue -- the simulation is inspected inside signature_timeout_alert -- and leaves main's existing props and tests untouched. The alert also stays visible for a fee warning alone, not just a timeout or network mismatch. The fee-warning suite now stubs WalletContext, because the alert pulls in the Stellar Wallets Kit at module scope and this suite is about fee inspection. tsc clean; the four suites on this branch pass (152 tests).
…lect @stellar/freighter-api ships only a CommonJS bundle -- its package.json declares `main` but no `module` or `exports` ESM entry -- so Vite could not statically resolve the named imports that freighter_connector.ts and the Wallets Kit rely on. Any suite whose import graph reached WalletContext died at collection with: SyntaxError: The requested module '@stellar/freighter-api' does not provide an export named 'getAddress' The export does exist; it is only reachable through CJS interop. Adding both packages to server.deps.inline lets Vite transform the bundle and synthesise the named exports. This is pre-existing breakage on main, not from this branch's work -- both affected suites fail the same way on origin with this branch's changes stashed. Fixing it here because it blocks CI on the PR. Effect: freighter_connector.component.test.tsx now passes in full, and signature_timeout_alert.test.tsx actually executes instead of silently not running -- which surfaces one genuine pre-existing failure in it. Suite goes from 1445 to 1469 tests collected. Still failing, all pre-existing and all in main's own suites, none touched by this branch: 4 in freighter_multisig_hook.test.ts (envelope parsing) and 1 loader-counter test in signature_timeout_alert.test.tsx. Left for their owners rather than fixed blind here.
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 #254
closes #224
closes #217
closes #250
Summary
Four wallet-flow improvements: fee warnings on the signature timeout alert,
interactive states on the wallet badge, timeout clocks in the wallet selector,
and session persistence for the transaction signer
Changes
signature_timeout_alert— fee warning bannersNone of these four modules existed as files, so each follows the repo's
established per-module convention (
app/lib/<module>.ts+ components + tests),modeled on the closest existing analogue.
app/lib/signature_timeout_alert.tsextracts the estimated fee from a Soroban(
minResourceFee) or classic (fee) simulation result and buckets it intonone/elevated/exceeded/erroragainst a 1,000,000-stroop bound.SignatureTimeoutFeeWarningBannerrenders it with severity-driven designtokens;
SignatureTimeoutAlertcomposes it with the timeout notice and anoptional retry action.
assertSignatureFeeWithinBoundsthrows, for callers that want to hard-stoprather than render a banner.
wallet_badge— hover, focus-visible and disabled statesonClickmakes the badge actionable; it then renders as a<button>withhover:bg-surface-card, an accentfocus-visiblering offsetagainst
surface-page, anddisabled:opacity-50/disabled:cursor-not-allowed.disabled:hover:*variants neutralise hover so a disabled badge staysvisually inert.
disabledprop; the badge also auto-disables whilestatus="loading".the badge is itself a button (buttons cannot nest).
data-testidanddata-statusare unchanged, so bothexisting WalletBadge suites still pass untouched.
wallet_selector_modal— transaction timeout clockssignWithWalletSelectorTimeoutraces the provider callback against a 60sdefault bound.
AbortSignalhanded to the provider, zeroesand nulls the request payload, and rejects with
WalletSelectorTimeoutError.every exit path — success, provider error, timeout — so no controller or
buffer outlives its request.
abortAllWalletSelectorOperations()covers modal close / unmount.transaction_signer_component— session persistenceaddress,walletId,networkPassphrase,connectedAt)in
localStorage.field, and rejects any payload carrying a secret key, seed, mnemonic or auth
token. Invalid payloads are dropped from storage so the next reload starts
clean.
TransactionSignerSessionStoremirrors the session in memory, rehydrates onconstruction, and exposes
restore()/clear()/overrideStorage().degrade to an empty session instead of throwing.
Testing
153 new tests across four files:
signature_timeout_alert_fee_warning.test.tsx— fee extraction, severitybucketing, the exceeded/elevated/error boundaries, banner rendering and
console warnings.
wallet-badge-interactive-states.test.tsx— class assertions for each stateplus real behaviour: keyboard focus, Enter activation, disabled skipped by
tab order, handlers not firing while disabled.
wallet_selector_modal_timeout.test.ts— abort-on-timeout, memory clearing,registry emptied on all three exit paths, concurrent requests.
transaction_signer_persistence.test.ts— round-trip across reload, corruptand version-mismatched payloads, sensitive-field rejection, storage failures.
Suite goes from 74 files / 1059 tests to 78 files / 1212 tests, all passing.
tsc --noEmitandeslintboth clean.