fix: sign and export with each address's own derivation index (closes #510)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

Sending, site transactions, site signatures and private key export
derived the key at the address's position in the wallet's list. After
an import whose scan passed over an unused index, or after removing an
address that was not the last, that position named another address's
key.

Each HD and xprv address record now stores the index it was derived at
(at wallet creation, by the import scan, by "+"), and
getSignerForAddress() derives at that index and refuses any key whose
address differs from the record's. The export screen reports that
refusal instead of calling the password wrong.

Model: opus-5-5
This commit is contained in:
2026-10-14 03:09:03 +00:00
parent 8e52528f8b
commit 7b731ea261
12 changed files with 496 additions and 29 deletions
+11 -1
View File
@@ -1188,7 +1188,14 @@ The core hierarchy is **Wallets → Addresses**:
of its stored `xpub` by `src/shared/walletDefects.js`, explained in the
wallet list, and blocked from signing, sending and private-key export. It
is never deleted or rewritten.
- An **address** holds ETH and ERC-20 tokens.
- An **address** holds ETH and ERC-20 tokens. In an HD or xprv wallet each
address record also stores `index`, the derivation index it was made at: 0 for
the first address, the index the import scan found it at, or `nextIndex` when
"+" added it. An address's `index` and its position in the wallet's list
differ once the scan has passed over an unused index or an address has been
removed. Sending, site transactions, site signatures and private-key export
derive the key at `index`, and refuse it unless it is that address's own key
(`getSignerForAddress()` in `src/shared/wallet.js`).
- The user can have multiple wallets, each with multiple addresses (HD) or a
single address (key).
@@ -1514,6 +1521,9 @@ view would leave a wallet one click from deletion.
change)
- "Reveal" (wrong password) → full-sentence error on the error line, nothing
revealed (no screen change)
- "Reveal" (correct password, but the key derived is not this address's own,
see Data Model) → full-sentence error saying so, nothing revealed (no
screen change)
- "Back" → previous screen (AddressDetail)
- Settings gear → **Settings**, whose "Back" goes to AddressDetail: leaving
drops the address the screen was showing, so it also takes the screen off