diff --git a/README.md b/README.md index 2ed0dc3..e7ea57c 100644 --- a/README.md +++ b/README.md @@ -130,8 +130,11 @@ transfer, and the recovery phrase screen — which wallet types are offered it, that it holds nothing before the password is accepted, that a wrong password reveals nothing, that leaving it by either route wipes it — including a leave taken while the decrypt is still running — and that reopening the popup does not -land on it. All outbound network is intercepted at the browser level and served -from fixtures in `tests/e2e/network.js`, so the run is deterministic and fully +land on it. It also covers address removal: which wallets offer the control at +all, that the confirmation states the route back rather than showing an empty +paragraph, that leaving the confirmation removes nothing, and that confirming it +does. All outbound network is intercepted at the browser level and served from +fixtures in `tests/e2e/network.js`, so the run is deterministic and fully offline; unrecognised outbound requests are reported as failures rather than silently allowed. @@ -513,8 +516,9 @@ of it. - Wallet list: each wallet shows its name (tap to rename inline) and a "+" button for HD and xprv wallets, then one block per address with "Address N" (bold when active), the ENS name if resolved, the full address, an - `[info]` button, the address USD total, and a balance line for ETH and for - each token shown for that address + `[info]` button, an `[x]` button (only on HD and xprv wallets holding more + than one address), the address USD total, and a balance line for ETH and + for each token shown for that address - "Recent Transactions": up to 25 transactions merged across every address of every wallet, deduplicated by hash and filtered - "Add additional wallet..." link at bottom @@ -524,6 +528,7 @@ of it. - Tap wallet name → inline rename field (no screen change) - "+" on wallet → derives the next address inline (no screen change) - `[info]` on address → **AddressDetail** + - `[x]` on address → **DeleteAddress** - "Send" → **Send** (refuses with a flash message on a zero balance) - "Receive" → **Receive** (shows active address QR) - Tap home tx row → **TransactionDetail** @@ -884,6 +889,55 @@ of it. nothing deleted - "Back" → previous screen (Settings) +#### DeleteAddress (`delete-address-confirm`) + +- **When**: User tapped the `[x]` next to an address on Home. Offered only on HD + and xprv wallets holding more than one address: the last address of a wallet + is never removable, and a key wallet has exactly one. +- **Elements**: + - "Back" button, "Remove Address" heading + - The address's own label ("Address N") and its wallet's name + - The full address (color dot, etherscan link, tap to copy), with the ENS + name above it if resolved + - Explanation that this only stops the wallet tracking the address: nothing + is destroyed, no key is deleted, and funds stay where they are + - The route back, stated with its limit, because the obvious two are both + refused: "+" derives the next unused index (`nextIndex` is a high-water + mark), and re-importing the wallet's key material is rejected as a + duplicate by `findWalletByXpub` while the wallet is still present. What + works is deleting the whole wallet in Settings — password-gated, and it + destroys the stored secret — then importing again, whereupon + `scanForAddresses()` rediscovers the address **only if it has on-chain + activity**. An address that was never used does not come back. The text is + written by `recoveryPathText()` rather than sitting in `index.html`, so it + can name the wallet's own kind of key material: an xprv wallet has no + recovery phrase to re-import. + - A warning when the address holds anything, ETH or any tracked ERC-20, + followed by the holdings themselves via `balanceLinesForAddress()` and the + USD total via `getAddressValueUsd()`. The sentence names no figure of its + own: the lines round to four decimals, so a sentence built from a rounded + number would report `0.0000 ETH` for an address holding real money. The + predicate is `addressHoldsFunds()` in `src/popup/views/helpers.js`, + unrounded and token-aware. A balance is a warning, never a refusal. + - The rule that a wallet always keeps at least one address, and that + removing the last one means deleting the wallet from Settings + - Error line + - "Remove Address" button +- **Transitions**: + - "Remove Address" → removes the address and its site permissions, then → + previous screen (Home) with an "Address removed." flash message + - "Back" → previous screen (Home), nothing removed +- **Deliberately not password-gated**, unlike DeleteWallet: a password gates the + disclosure or destruction of a secret, and this does neither. The address + stays derivable from key material the wallet still holds. +- The active address moves only if it was the address removed, and then to the + wallet's first remaining address, with `AUTISTMASK_ACTIVE_CHANGED` broadcast + so a connected site stops being told about an address the user removed + (`src/shared/walletDelete.js`). A selection in any other wallet is left alone; + one in this wallet follows the splice. +- The wallet's derivation counter (`nextIndex`) is not rewound, so "+" derives a + fresh address rather than handing back the one just removed. + #### SettingsAddToken (`settings-addtoken`) - **When**: User tapped "+ Add token" in Settings. Tokens added here are tracked @@ -1367,7 +1421,7 @@ Currently supported: ### Wallet Management - [x] Delete wallet (with confirmation) -- [ ] Delete address from HD wallet (with confirmation) +- [x] Delete address from HD wallet (with confirmation) - [x] Show wallet's recovery phrase (requires password) ### Transactions diff --git a/TODO.md b/TODO.md index eb6dd07..f3f820c 100644 --- a/TODO.md +++ b/TODO.md @@ -44,6 +44,11 @@ undefined identifiers, which is how # Completed Steps +- 2026-08-12: An address can be removed from an HD or xprv wallet behind a + confirmation screen that states nothing is destroyed, sharing the deletion + state transitions with wallet deletion so the selection, site permissions and + active-address broadcast follow the same rules + ([#162](https://git.eeqj.de/sneak/AutistMask/issues/162)). - 2026-08-12: An xprv wallet already in storage that was imported from a non-master key is detected from the depth of its stored `xpub`, explained in the wallet list, and blocked from signing, sending and private-key export diff --git a/src/popup/index.html b/src/popup/index.html index 1325c66..3490fd4 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -1142,6 +1142,62 @@ + + +