From ca6e9054f98c82cb4bff95392721a6e6eff9b510 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 28 Feb 2026 15:58:47 -0800 Subject: [PATCH] fix: cross-wallet-type duplicate detection for all import methods - Private key import now checks ALL wallets (hd, xprv, key) for address conflicts - xprv import now checks xpub against existing xpubs and addresses across all wallet types - Mnemonic import now checks xpub against xprv wallets and addresses across all types - Extract findWalletByAddress() and findWalletByXpub() helpers for consistent dedup closes #111 --- src/popup/views/addWallet.js | 60 ++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/popup/views/addWallet.js b/src/popup/views/addWallet.js index 9fcfed6..bcf582e 100644 --- a/src/popup/views/addWallet.js +++ b/src/popup/views/addWallet.js @@ -11,6 +11,25 @@ const { encryptWithPassword } = require("../../shared/vault"); const { state, saveState } = require("../../shared/state"); const { scanForAddresses } = require("../../shared/balances"); +/** + * Check if an address already exists in ANY wallet (hd, xprv, or key). + * Returns the wallet object if found, or undefined. + */ +function findWalletByAddress(addr) { + const lower = addr.toLowerCase(); + return state.wallets.find((w) => + w.addresses.some((a) => a.address.toLowerCase() === lower), + ); +} + +/** + * Check if an xpub already exists in any HD-type wallet (hd or xprv). + * Returns the wallet object if found, or undefined. + */ +function findWalletByXpub(xpub) { + return state.wallets.find((w) => w.xpub && w.xpub === xpub); +} + let currentMode = "mnemonic"; const MODES = ["mnemonic", "privkey", "xprv"]; @@ -97,18 +116,18 @@ async function importMnemonic(ctx) { const pw = validatePassword(); if (!pw) return; const { xpub, firstAddress } = hdWalletFromMnemonic(mnemonic); - const duplicate = state.wallets.find( - (w) => - w.type === "hd" && - w.addresses[0] && - w.addresses[0].address.toLowerCase() === firstAddress.toLowerCase(), - ); - if (duplicate) { + const xpubDup = findWalletByXpub(xpub); + if (xpubDup) { showFlash( - "This recovery phrase is already added (" + duplicate.name + ").", + "This recovery phrase is already added (" + xpubDup.name + ").", ); return; } + const addrDup = findWalletByAddress(firstAddress); + if (addrDup) { + showFlash("Address already exists in wallet (" + addrDup.name + ")."); + return; + } const encrypted = await encryptWithPassword(mnemonic, pw); const walletNum = state.wallets.length + 1; const wallet = { @@ -162,15 +181,10 @@ async function importPrivateKey(ctx) { } const pw = validatePassword(); if (!pw) return; - const duplicate = state.wallets.find( - (w) => - w.type === "key" && - w.addresses[0] && - w.addresses[0].address.toLowerCase() === addr.toLowerCase(), - ); + const duplicate = findWalletByAddress(addr); if (duplicate) { showFlash( - "This private key is already added (" + duplicate.name + ").", + "This address already exists in wallet (" + duplicate.name + ").", ); return; } @@ -208,14 +222,14 @@ async function importXprvKey(ctx) { return; } const { xpub, firstAddress } = result; - const duplicate = state.wallets.find( - (w) => - (w.type === "hd" || w.type === "xprv") && - w.addresses[0] && - w.addresses[0].address.toLowerCase() === firstAddress.toLowerCase(), - ); - if (duplicate) { - showFlash("This key is already added (" + duplicate.name + ")."); + const xpubDup = findWalletByXpub(xpub); + if (xpubDup) { + showFlash("This key is already added (" + xpubDup.name + ")."); + return; + } + const addrDup = findWalletByAddress(firstAddress); + if (addrDup) { + showFlash("Address already exists in wallet (" + addrDup.name + ")."); return; } const pw = validatePassword();