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 "+"). getSignerForAddress()
derives at that index, refuses a record without one, and refuses any key
whose address differs from the record's. The confirmation screen signs
as the From address it shows, not the selected one. The export screen
reports a refusal instead of calling the password wrong.

Model: opus-5-5
This commit is contained in:
2026-10-14 10:56:43 +00:00
parent f1a13a50a6
commit 4770849ff8
12 changed files with 612 additions and 34 deletions
+10 -2
View File
@@ -1455,7 +1455,11 @@ describe("background population to popup signing to verification", () => {
// What the popup does with it: signs it as given, populating nothing.
async function popupSigns(approvedTx) {
const localSigner = getSignerForAddress(walletData, 0, SIGNER_KEY);
const localSigner = getSignerForAddress(
walletData,
{ address: signer.address },
SIGNER_KEY,
);
return localSigner.signTransaction({ ...approvedTx });
}
@@ -1550,7 +1554,11 @@ describe("background population to popup signing to verification", () => {
// address the user has switched to.
test("the approved from stops the popup signing with another key", async () => {
const approvedTx = await backgroundPrepares(TX_PARAMS);
const otherSigner = getSignerForAddress(walletData, 0, OTHER_KEY);
const otherSigner = getSignerForAddress(
walletData,
{ address: other.address },
OTHER_KEY,
);
await expect(
otherSigner.signTransaction({ ...approvedTx }),
).rejects.toThrow(/from address mismatch/);