The flash line reserves one line, so a message that wrapped pushed the screen below it down. #flash-msg no longer wraps: text too long for it is cut with an ellipsis, and showFlash() puts the whole message in its title. Every message is also reworded to at most 50 characters so none is cut, and the add-token screens flash a fixed line for any error other than the two lookup messages, logging the detail. A new end-to-end test writes a message several lines long into the line and fails if the line or the screen below it moves. Model: opus-5-5
85 lines
3.8 KiB
JavaScript
85 lines
3.8 KiB
JavaScript
// Wallets already in stored state whose key cannot be used, and the copy that
|
|
// explains them.
|
|
//
|
|
// Refusing a non-master extended private key at import time does nothing for a
|
|
// wallet imported before that refusal existed. Such a wallet is detected here,
|
|
// at wallet-list render time, so the user meets the explanation on the list
|
|
// screen rather than an exception on the send screen. Nothing here modifies or
|
|
// removes a wallet: the record is the user's data.
|
|
|
|
const { parseExtendedKey } = require("./wallet");
|
|
|
|
const NON_MASTER_XPRV = "non-master-xprv";
|
|
|
|
// An "xprv" wallet stores the neutered BIP-44 Ethereum node, four levels below
|
|
// the key that was imported: the current import path derives the absolute
|
|
// m/44'/60'/0'/0 from a depth-0 key, and the pre-#210 path derived the same
|
|
// four levels as a relative path beneath whatever depth it was given. A master
|
|
// import therefore stores a depth-4 xpub and a depth-d import stores depth
|
|
// d + 4, which makes the stored xpub an exact read on the imported key's
|
|
// depth — and it is readable without the password, unlike the key itself.
|
|
const BIP44_ETH_XPUB_DEPTH = 4;
|
|
|
|
const DEFECTS = {
|
|
[NON_MASTER_XPRV]: {
|
|
id: NON_MASTER_XPRV,
|
|
heading: "This wallet's addresses were derived incorrectly.",
|
|
paragraphs: [
|
|
"This wallet was imported from an extended private key that is " +
|
|
"not a master key. An earlier version applied the Ethereum " +
|
|
"derivation path beneath that key instead of from a master " +
|
|
"key, so the addresses listed here are not the ones that key " +
|
|
"produces under the standard path.",
|
|
"Signing and sending are disabled for this wallet. The addresses " +
|
|
"do descend from the extended private key you imported, so " +
|
|
"anything they hold is still reachable by software that " +
|
|
"repeats the same non-standard derivation. Check them in a " +
|
|
"block explorer before deciding what to do.",
|
|
"To see the addresses this key produces under the standard path, " +
|
|
"import the master extended private key, or the recovery " +
|
|
"phrase it came from, as a new wallet. Nothing here has been " +
|
|
"changed or removed, and this wallet stays until you delete " +
|
|
"it yourself.",
|
|
],
|
|
// One line, for the flash on a blocked Send and the inline error on
|
|
// the approval screens. It must fit on the flash line; see showFlash()
|
|
// in src/popup/views/helpers.js.
|
|
shortMessage: "This wallet cannot sign. See the wallet list.",
|
|
},
|
|
};
|
|
|
|
// The defect record for a wallet, or null if there is nothing wrong with it
|
|
// that this module can see. Read-only.
|
|
//
|
|
// A wallet whose xpub will not parse gets null rather than a defect: there is
|
|
// no basis in that case to tell the user their key was not a master key, and a
|
|
// wrong explanation is worse than none.
|
|
function walletDefect(walletData) {
|
|
if (!walletData || walletData.type !== "xprv") return null;
|
|
const node = parseExtendedKey(walletData.xpub);
|
|
if (!node) return null;
|
|
if (node.depth === BIP44_ETH_XPUB_DEPTH) return null;
|
|
return DEFECTS[NON_MASTER_XPRV];
|
|
}
|
|
|
|
// The notice block for the wallet list, or "" for a wallet with no defect.
|
|
// The copy is fixed text from this module, so it needs no escaping.
|
|
function walletDefectHtml(walletData) {
|
|
const defect = walletDefect(walletData);
|
|
if (!defect) return "";
|
|
let html =
|
|
'<div class="border border-red-500 border-dashed p-2 my-1 text-xs text-red-500">';
|
|
html += `<div class="font-bold mb-1">${defect.heading}</div>`;
|
|
for (const p of defect.paragraphs) {
|
|
html += `<p class="mb-1">${p}</p>`;
|
|
}
|
|
html += "</div>";
|
|
return html;
|
|
}
|
|
|
|
module.exports = {
|
|
NON_MASTER_XPRV,
|
|
walletDefect,
|
|
walletDefectHtml,
|
|
};
|