feat(gui): wallet setup wizard, named wallets, and wallet switcher#1148
feat(gui): wallet setup wizard, named wallets, and wallet switcher#1148binarybaron wants to merge 7 commits into
Conversation
Applied from stash 85824882 (feat/bob-concurrent-swaps) onto master. - Seed selection dialog is now a step-based wizard driven by a single state machine (mode flows in a FLOWS table, reducer with guarded transitions): create a wallet with user-chosen name/directory and a mandatory seed backup step, restore from seed with word autocomplete, or open a wallet file (drag & drop + recent wallets). - New wallets are stored under a user-chosen name instead of a unix timestamp; creation refuses to overwrite an existing wallet (<name> and <name>.keys checked without extension truncation). - Wallet switcher on the Monero wallet page: records a PendingWalletAction marker consumed on next startup, then relaunches. - New Tauri commands: get_seed_words (vendored English wordlist, verified identical to monero/src/mnemonics/english.h), get_recent_wallets, set_pending_wallet.
Review findings from three parallel reviewers, applied: Backend: - Wallet create/open failures (e.g. duplicate wallet name) no longer abort context initialization: the open loop treats every per-attempt failure as one outcome and re-prompts the seed chooser, matching the existing password-rejection recovery. - Pending-wallet marker: atomic write (tmp + rename), corrupt markers are discarded with a warning instead of failing startup, and an Open marker pointing at a deleted wallet falls back to the chooser. - new_wallet_path hoisted to module level; also rejects empty names and non-absolute directories at the IPC trust boundary. - TauriEmitter::request_seed_selection_with_recent_wallets renamed to request_seed_selection, taking SeedSelectionDetails directly. - SetPendingWalletArgs derives the data dir via eigenwallet_data::new, same source as the startup reader. Wizard (state machine completed): - Form fields moved into the editing variant; backingUp carries the editing state for rollback and owns the backup confirmation; reset rebuilds everything so no password/seed leaks across requests. - walletCreationStarted guarded to RandomSeed@nameLocation. - Async seed validation tagged with the seed it belongs to (no stale responses), primary/legacy buttons surface errors via snackbar. - BackupSeedStep: checkbox controlled by parent; a failed seed fetch unlocks Finish instead of hard-locking the modal; 5 retries not 60. - NameLocationStep: no error styling on pristine name field. Switcher: - Failed relaunch neutralizes the marker so a later manual launch cannot silently switch wallets. - Picking a .keys file resolves to the wallet file itself. - Confirm dialog keeps its copy while fading out; explicit warning when a funds-locked swap is running; chip label capped at 220px. - NewPasswordInput setPassword prop loosened to (password: string) => void (it never used functional updates).
Scope the PR down to the setup wizard. Removed: - WalletSwitcher component and its MoneroWalletPage overlay - get_recent_wallets / set_pending_wallet Tauri commands and their request types - PendingWalletAction and the pending_wallet marker read/write plus resolve_startup_seed_choice (startup asks the chooser directly again) Kept from the switcher review where it still applies: - OpenWalletStep resolves a picked/dropped <name>.keys file to the wallet file itself - NameLocationStep Browse now uses PromiseInvokeButton (async folder picker with error snackbar) instead of a bare Button
Trims the wizard further: the restore step is a plain multiline TextField again (as on master). Removes SeedPhraseInput, the get_seed_words command and request types, and the vendored 1626-word English wordlist (swap/src/cli/api/seed_words.rs). Seed validity is still checked via the existing check_seed command.
| const path = event.payload.paths[0]; | ||
| // Users commonly pick the `<name>.keys` file; the wallet is the | ||
| // file without that extension. | ||
| if (path) setWalletPath(path.replace(/\.keys$/, "")); |
There was a problem hiding this comment.
Keys suffix strips wallet basename
Medium Severity
Drag-and-drop and the file picker always remove a trailing .keys from the chosen path. That is correct when the user selects the keys sidecar, but if the wallet’s on-disk name itself ends with .keys (allowed by the name step), selecting the main wallet file strips that suffix and sends the wrong wallet_path to open.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 99882c5. Configure here.
The init flow now lives in swap/src/cli/api/wallet_setup.rs as an
explicit state machine:
ChooseSeed -> OpenWallet -> BackupSeed -> Finish
Every state that needs user input blocks on a Tauri approval; failures
and password rejections fall back to ChooseSeed. New SeedBackup
approval (ApprovalRequestType::SeedBackup) carries the freshly created
wallet's seed + restore height from Rust, so the GUI no longer polls
moneroWalletAvailable and re-fetches the seed with retries.
Frontend consequences:
- BackupSeedStep is purely presentational (props in, checkbox out);
the retry loop, failure state, and availability gating are gone.
- The dialog renders whichever backend request is pending (SeedBackup
-> backup step, SeedSelection -> wizard) plus a local spinner while
the wallet is being created; its reducer shrinks to pure wizard
navigation (mode/step/fields) - backingUp/finished phases, rollback
resume state, and creation events are deleted.
- useIsMoneroWalletAvailable removed (last consumer gone).
Same UI look throughout: dialog shell, breadcrumbs, steps unchanged.
The legacy-wallet helpers and their tests move along into
wallet_setup.rs; mod wallet in api.rs keeps only init_bitcoin_wallet.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3100afd. Configure here.
| ? ("wizard" as const) | ||
| : waitingForWallet | ||
| ? ("waiting" as const) | ||
| : null; |
There was a problem hiding this comment.
Spinner blocks after skipped backup
High Severity
After creating a wallet, waitingForWallet keeps the setup dialog open until a SeedBackup approval arrives. If the backend skips that step (for example when reading the seed fails and startup continues anyway), no approval is emitted and waitingForWallet is never cleared, so the modal stays on “Creating your new wallet…” over a loaded app.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3100afd. Configure here.
Reorder the RandomSeed flow in the FLOWS table: chooseMode -> nameLocation -> randomPassword -> backupSeed. The password step now carries the createWallet action; everything else derives from the table.
The reset effect for the SeedBackup approval had the approval object in its dependency array; the object's identity changes on every store update (approvals are re-emitted during startup), so the effect re-ran constantly and cleared backupConfirmed. Key it on the stable request_id with the same ref guard the selection reset uses.


No description provided.