fix: deleting the last wallet leaves hasWallet true, resets selection unconditionally, and skips the active-address broadcast #156

Closed
opened 2026-08-09 03:43:48 +02:00 by clawbot · 0 comments
Collaborator

Problem

Delete wallet is implemented and reachable (Home gear -> Settings -> per-wallet
[x] -> password-gated confirm at src/popup/views/deleteWallet.js:52), but
it has three defects.

1. Deleting the last wallet leaves state.hasWallet === true.
deleteWallet.js:75-82 nulls selectedWallet, selectedAddress and
activeAddress and calls showView("welcome"), but never sets
state.hasWallet = false. On the next popup open, src/popup/index.js:265
(if (!state.hasWallet)) is false, so the user lands on Home rendering "No
wallets yet. Add one to get started." (src/popup/views/home.js:219-220)
instead of the Welcome screen. README.md:270-276 specifies Welcome is the
root screen when no wallets exist.

2. Selection is reset unconditionally. deleteWallet.js:85-88 forces
selectedWallet = 0; selectedAddress = 0 and moves activeAddress to wallet
0 even when the deleted wallet was not the active one. Deleting an unrelated
wallet silently moves the user's active address.

3. No AUTISTMASK_ACTIVE_CHANGED broadcast after the active address
changes on delete. Compare home.js:277, which does broadcast on address
switch. Connected dApps keep seeing a deleted address until some other event
triggers a broadcast — the site believes it is still connected to an account
whose key no longer exists in the wallet.

Implementation requirements

  • Set state.hasWallet = false when the last wallet is removed, and persist
    before navigating. Verify the Welcome screen is what actually renders on a
    fresh popup open afterwards, not just immediately after the delete.
  • Only adjust selectedWallet / selectedAddress / activeAddress when the
    deleted wallet actually contained the current selection. When it did,
    fall back deterministically (e.g. to the first remaining wallet's first
    address) and say what the rule is in the PR. When it did not, leave the
    user's selection exactly where it was, accounting for the index shift caused
    by the splice at deleteWallet.js:65.
  • Emit AUTISTMASK_ACTIVE_CHANGED whenever the active address changes as a
    result of the delete, matching the existing call shape at home.js:277.
    Also consider whether accountsChanged needs to reach connected dApps via
    broadcastAccountsChanged (src/background/index.js:567-590) — a deleted
    address should not remain an authorized account.
  • The existing allowedSites / deniedSites cleanup at deleteWallet.js:67-71
    looks correct; keep it and confirm it covers every address of an HD wallet,
    not just the first.
  • Keep the delete confirmation password-gated exactly as it is.

Definition of done

  • Deleting the only wallet, then closing and reopening the popup, lands on
    the Welcome screen.
  • Deleting a non-active wallet leaves the active address unchanged, and
    the selection still points at the same wallet it did before (correct
    index after the splice).
  • Deleting the active wallet moves the selection to a defined fallback and
    broadcasts AUTISTMASK_ACTIVE_CHANGED.
  • A connected dApp observes the account change rather than continuing to
    see a deleted address.
  • Site permissions for every address of the deleted wallet are removed
    from both allowedSites and deniedSites.
  • Unit tests cover the state transitions for all three cases (last wallet,
    active wallet, non-active wallet).
  • TODO.md updated in the same commit; the README TODO checkbox for
    "Delete wallet (with confirmation)" is ticked, since the feature exists.
  • make check passes.
## Problem Delete wallet is implemented and reachable (Home gear -> Settings -> per-wallet `[x]` -> password-gated confirm at `src/popup/views/deleteWallet.js:52`), but it has three defects. **1. Deleting the last wallet leaves `state.hasWallet === true`.** `deleteWallet.js:75-82` nulls `selectedWallet`, `selectedAddress` and `activeAddress` and calls `showView("welcome")`, but never sets `state.hasWallet = false`. On the next popup open, `src/popup/index.js:265` (`if (!state.hasWallet)`) is false, so the user lands on Home rendering "No wallets yet. Add one to get started." (`src/popup/views/home.js:219-220`) instead of the Welcome screen. `README.md:270-276` specifies Welcome is the root screen when no wallets exist. **2. Selection is reset unconditionally.** `deleteWallet.js:85-88` forces `selectedWallet = 0; selectedAddress = 0` and moves `activeAddress` to wallet 0 even when the deleted wallet was not the active one. Deleting an unrelated wallet silently moves the user's active address. **3. No `AUTISTMASK_ACTIVE_CHANGED` broadcast** after the active address changes on delete. Compare `home.js:277`, which does broadcast on address switch. Connected dApps keep seeing a deleted address until some other event triggers a broadcast — the site believes it is still connected to an account whose key no longer exists in the wallet. ## Implementation requirements - Set `state.hasWallet = false` when the last wallet is removed, and persist before navigating. Verify the Welcome screen is what actually renders on a fresh popup open afterwards, not just immediately after the delete. - Only adjust `selectedWallet` / `selectedAddress` / `activeAddress` when the deleted wallet actually contained the current selection. When it did, fall back deterministically (e.g. to the first remaining wallet's first address) and say what the rule is in the PR. When it did not, leave the user's selection exactly where it was, accounting for the index shift caused by the `splice` at `deleteWallet.js:65`. - Emit `AUTISTMASK_ACTIVE_CHANGED` whenever the active address changes as a result of the delete, matching the existing call shape at `home.js:277`. Also consider whether `accountsChanged` needs to reach connected dApps via `broadcastAccountsChanged` (`src/background/index.js:567-590`) — a deleted address should not remain an authorized account. - The existing `allowedSites` / `deniedSites` cleanup at `deleteWallet.js:67-71` looks correct; keep it and confirm it covers every address of an HD wallet, not just the first. - Keep the delete confirmation password-gated exactly as it is. ## Definition of done - [ ] Deleting the only wallet, then closing and reopening the popup, lands on the Welcome screen. - [ ] Deleting a non-active wallet leaves the active address unchanged, and the selection still points at the same wallet it did before (correct index after the splice). - [ ] Deleting the active wallet moves the selection to a defined fallback and broadcasts `AUTISTMASK_ACTIVE_CHANGED`. - [ ] A connected dApp observes the account change rather than continuing to see a deleted address. - [ ] Site permissions for every address of the deleted wallet are removed from both `allowedSites` and `deniedSites`. - [ ] Unit tests cover the state transitions for all three cases (last wallet, active wallet, non-active wallet). - [ ] `TODO.md` updated in the same commit; the README TODO checkbox for "Delete wallet (with confirmation)" is ticked, since the feature exists. - [ ] `make check` passes.
clawbot added this to the 1.0.0 milestone 2026-08-09 03:43:48 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#156