Compare commits

..

1 Commits

Author SHA1 Message Date
user
cd412209a7 fix: cross-wallet duplicate address detection on import
All checks were successful
check / check (push) Successful in 22s
Previously each import method (mnemonic, private key, xprv) only checked
for duplicates among wallets of the same type. Now all three check the
derived address against ALL existing wallet addresses regardless of type,
and mnemonic/xprv imports also compare xpubs against existing HD/xprv
wallets.

Closes #111
2026-02-28 16:01:40 -08:00
17 changed files with 81 additions and 236 deletions

View File

@@ -107,8 +107,7 @@
</div>
<div
id="add-wallet-phrase-warning"
class="text-xs mb-2 border border-border border-dashed p-2"
style="visibility: hidden"
class="text-xs mb-2 border border-border border-dashed p-2 hidden"
>
Write these words down and keep them safe. Anyone with
them can take your funds; if you lose them, your wallet
@@ -376,8 +375,7 @@
</p>
<div
id="export-privkey-flash"
class="text-xs mb-2 min-h-[1.25rem]"
style="visibility: hidden"
class="text-xs mb-2 hidden"
></div>
<div id="export-privkey-password-section" class="mb-2">
<label class="block mb-1">Password</label>
@@ -581,17 +579,13 @@
<div class="text-xs text-muted mb-1">Your balance</div>
<div id="confirm-balance" class="text-xs"></div>
</div>
<div id="confirm-fee" class="mb-3" style="visibility: hidden">
<div id="confirm-fee" class="mb-3 hidden">
<div class="text-xs text-muted mb-1">
Estimated network fee
</div>
<div id="confirm-fee-amount" class="text-xs"></div>
</div>
<div
id="confirm-warnings"
class="mb-2"
style="visibility: hidden"
></div>
<div id="confirm-warnings" class="mb-2 hidden"></div>
<div
id="confirm-recipient-warning"
class="mb-2"
@@ -607,8 +601,7 @@
</div>
<div
id="confirm-errors"
class="mb-2 border border-border border-dashed p-2"
style="visibility: hidden; min-height: 1.25rem"
class="mb-2 border border-border border-dashed p-2 hidden"
></div>
<div class="mb-2">
<label class="block mb-1 text-xs">Password</label>
@@ -621,7 +614,6 @@
<div
id="confirm-tx-password-error"
class="text-xs mb-2 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<button
id="btn-confirm-send"
@@ -736,8 +728,7 @@
</button>
<div
id="receive-erc20-warning"
class="text-xs border border-border border-dashed p-2 mt-3"
style="visibility: hidden"
class="text-xs border border-border border-dashed p-2 mt-3 hidden"
></div>
</div>
@@ -765,8 +756,7 @@
</div>
<div
id="add-token-info"
class="text-xs text-muted mb-2 min-h-[1.25rem]"
style="visibility: hidden"
class="text-xs text-muted mb-2 hidden"
></div>
<div class="mb-2">
<label class="block mb-1 text-xs text-muted"
@@ -913,12 +903,6 @@
/>
<span class="text-xs text-muted">gwei</span>
</div>
<label
class="text-xs flex items-center gap-1 cursor-pointer mb-1"
>
<input type="checkbox" id="settings-utc-timestamps" />
UTC Timestamps
</label>
</div>
<div class="bg-well p-3 mx-1 mb-3">
@@ -954,8 +938,7 @@
</p>
<div
id="delete-wallet-flash"
class="text-xs text-red-500 mb-2 min-h-[1.25rem]"
style="visibility: hidden"
class="text-xs text-red-500 mb-2 hidden"
></div>
<div class="mb-2">
<label class="block mb-1">Password</label>
@@ -1030,8 +1013,7 @@
/>
<div
id="settings-addtoken-info"
class="text-xs text-muted mt-1 min-h-[1.25rem]"
style="visibility: hidden"
class="text-xs text-muted mt-1 hidden"
></div>
<button
id="btn-settings-addtoken-manual"
@@ -1157,8 +1139,7 @@
</div>
<div
id="approve-tx-error"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
style="visibility: hidden"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem] hidden"
></div>
<div class="flex justify-between">
<button
@@ -1186,10 +1167,8 @@
<div
id="approve-sign-danger-warning"
class="mb-3 p-2 text-xs font-bold"
class="hidden mb-3 p-2 text-xs font-bold"
style="
visibility: hidden;
min-height: 1.25rem;
background: #fee2e2;
color: #991b1b;
border: 2px solid #dc2626;
@@ -1226,8 +1205,7 @@
</div>
<div
id="approve-sign-error"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
style="visibility: hidden"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem] hidden"
></div>
<div class="flex justify-between">
<button

View File

@@ -19,16 +19,3 @@ body {
width: 396px;
overflow-x: hidden;
}
/* Copy-flash feedback: inverts colors then fades back */
.copy-flash-active {
background-color: var(--color-fg) !important;
color: var(--color-bg) !important;
transition: none;
}
.copy-flash-fade {
transition:
background-color 225ms ease-out,
color 225ms ease-out;
}

View File

@@ -7,8 +7,7 @@ const { log } = require("../../shared/log");
function show() {
$("add-token-address").value = "";
$("add-token-info").textContent = "";
$("add-token-info").style.visibility = "hidden";
$("add-token-info").classList.add("hidden");
const list = $("common-token-list");
list.innerHTML = getTopTokens(25)
.map(
@@ -46,7 +45,7 @@ function init(ctx) {
}
const infoEl = $("add-token-info");
infoEl.textContent = "Looking up token...";
infoEl.style.visibility = "visible";
infoEl.classList.remove("hidden");
log.debugf("Looking up token contract", contractAddr);
try {
const info = await lookupTokenInfo(contractAddr, state.rpcUrl);
@@ -64,8 +63,7 @@ function init(ctx) {
const detail = e.shortMessage || e.message || String(e);
log.errorf("Token lookup failed for", contractAddr, detail);
showFlash(detail);
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
infoEl.classList.add("hidden");
}
});

View File

@@ -11,25 +11,6 @@ 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"];
@@ -71,7 +52,7 @@ function show() {
$("import-xprv-key").value = "";
$("add-wallet-password").value = "";
$("add-wallet-password-confirm").value = "";
$("add-wallet-phrase-warning").style.visibility = "hidden";
$("add-wallet-phrase-warning").classList.add("hidden");
switchMode("mnemonic");
showView("add-wallet");
}
@@ -116,16 +97,24 @@ async function importMnemonic(ctx) {
const pw = validatePassword();
if (!pw) return;
const { xpub, firstAddress } = hdWalletFromMnemonic(mnemonic);
const xpubDup = findWalletByXpub(xpub);
if (xpubDup) {
const addrDup = state.wallets.find((w) =>
w.addresses.some(
(a) => a.address.toLowerCase() === firstAddress.toLowerCase(),
),
);
if (addrDup) {
showFlash(
"This recovery phrase is already added (" + xpubDup.name + ").",
"An address from this phrase already exists in " +
addrDup.name +
".",
);
return;
}
const addrDup = findWalletByAddress(firstAddress);
if (addrDup) {
showFlash("Address already exists in wallet (" + addrDup.name + ").");
const xpubDup = state.wallets.find(
(w) => (w.type === "hd" || w.type === "xprv") && w.xpub === xpub,
);
if (xpubDup) {
showFlash("This recovery phrase matches " + xpubDup.name + ".");
return;
}
const encrypted = await encryptWithPassword(mnemonic, pw);
@@ -181,11 +170,11 @@ async function importPrivateKey(ctx) {
}
const pw = validatePassword();
if (!pw) return;
const duplicate = findWalletByAddress(addr);
const duplicate = state.wallets.find((w) =>
w.addresses.some((a) => a.address.toLowerCase() === addr.toLowerCase()),
);
if (duplicate) {
showFlash(
"This address already exists in wallet (" + duplicate.name + ").",
);
showFlash("This address already exists in " + duplicate.name + ".");
return;
}
const encrypted = await encryptWithPassword(key, pw);
@@ -222,14 +211,22 @@ async function importXprvKey(ctx) {
return;
}
const { xpub, firstAddress } = result;
const xpubDup = findWalletByXpub(xpub);
if (xpubDup) {
showFlash("This key is already added (" + xpubDup.name + ").");
const addrDup = state.wallets.find((w) =>
w.addresses.some(
(a) => a.address.toLowerCase() === firstAddress.toLowerCase(),
),
);
if (addrDup) {
showFlash(
"An address from this key already exists in " + addrDup.name + ".",
);
return;
}
const addrDup = findWalletByAddress(firstAddress);
if (addrDup) {
showFlash("Address already exists in wallet (" + addrDup.name + ").");
const xpubDup = state.wallets.find(
(w) => (w.type === "hd" || w.type === "xprv") && w.xpub === xpub,
);
if (xpubDup) {
showFlash("This key matches " + xpubDup.name + ".");
return;
}
const pw = validatePassword();
@@ -281,7 +278,7 @@ function init(ctx) {
// Generate mnemonic
$("btn-generate-phrase").addEventListener("click", () => {
$("wallet-mnemonic").value = generateMnemonic();
$("add-wallet-phrase-warning").style.visibility = "visible";
$("add-wallet-phrase-warning").classList.remove("hidden");
});
// Import / confirm

View File

@@ -2,7 +2,6 @@ const {
$,
showView,
showFlash,
flashCopyFeedback,
balanceLinesForAddress,
addressDotHtml,
addressTitle,
@@ -95,39 +94,18 @@ function show() {
function isoDate(timestamp) {
const d = new Date(timestamp * 1000);
const pad = (n) => String(n).padStart(2, "0");
if (state.utcTimestamps) {
return (
d.getUTCFullYear() +
"-" +
pad(d.getUTCMonth() + 1) +
"-" +
pad(d.getUTCDate()) +
"T" +
pad(d.getUTCHours()) +
":" +
pad(d.getUTCMinutes()) +
":" +
pad(d.getUTCSeconds()) +
"Z"
);
}
const offsetMin = -d.getTimezoneOffset();
const sign = offsetMin >= 0 ? "+" : "-";
const absOff = Math.abs(offsetMin);
const tzStr = sign + pad(Math.floor(absOff / 60)) + ":" + pad(absOff % 60);
return (
d.getFullYear() +
"-" +
pad(d.getMonth() + 1) +
"-" +
pad(d.getDate()) +
"T" +
" " +
pad(d.getHours()) +
":" +
pad(d.getMinutes()) +
":" +
pad(d.getSeconds()) +
tzStr
pad(d.getSeconds())
);
}
@@ -263,7 +241,6 @@ function init(_ctx) {
if (addr) {
navigator.clipboard.writeText(addr);
showFlash("Copied!");
flashCopyFeedback($("address-full"));
}
});
@@ -333,8 +310,8 @@ function init(_ctx) {
$("export-privkey-address").textContent = addr.address;
$("export-privkey-address").dataset.full = addr.address;
$("export-privkey-password").value = "";
$("export-privkey-flash").classList.add("hidden");
$("export-privkey-flash").textContent = "";
$("export-privkey-flash").style.visibility = "hidden";
$("export-privkey-password-section").classList.remove("hidden");
$("export-privkey-result").classList.add("hidden");
$("export-privkey-value").textContent = "";
@@ -345,7 +322,7 @@ function init(_ctx) {
const password = $("export-privkey-password").value;
if (!password) {
$("export-privkey-flash").textContent = "Password is required.";
$("export-privkey-flash").style.visibility = "visible";
$("export-privkey-flash").classList.remove("hidden");
return;
}
const btn = $("btn-export-privkey-confirm");
@@ -366,10 +343,10 @@ function init(_ctx) {
$("export-privkey-password-section").classList.add("hidden");
$("export-privkey-value").textContent = privateKey;
$("export-privkey-result").classList.remove("hidden");
$("export-privkey-flash").style.visibility = "hidden";
$("export-privkey-flash").classList.add("hidden");
} catch {
$("export-privkey-flash").textContent = "Wrong password.";
$("export-privkey-flash").style.visibility = "visible";
$("export-privkey-flash").classList.remove("hidden");
} finally {
btn.disabled = false;
btn.classList.remove("text-muted");
@@ -381,7 +358,6 @@ function init(_ctx) {
if (key) {
navigator.clipboard.writeText(key);
showFlash("Copied!");
flashCopyFeedback($("export-privkey-value"));
}
});
@@ -390,7 +366,6 @@ function init(_ctx) {
if (full) {
navigator.clipboard.writeText(full);
showFlash("Copied!");
flashCopyFeedback($("export-privkey-address"));
}
});

View File

@@ -5,7 +5,6 @@ const {
$,
showView,
showFlash,
flashCopyFeedback,
addressDotHtml,
addressTitle,
escapeHtml,
@@ -48,39 +47,18 @@ function etherscanAddressLink(address) {
function isoDate(timestamp) {
const d = new Date(timestamp * 1000);
const pad = (n) => String(n).padStart(2, "0");
if (state.utcTimestamps) {
return (
d.getUTCFullYear() +
"-" +
pad(d.getUTCMonth() + 1) +
"-" +
pad(d.getUTCDate()) +
"T" +
pad(d.getUTCHours()) +
":" +
pad(d.getUTCMinutes()) +
":" +
pad(d.getUTCSeconds()) +
"Z"
);
}
const offsetMin = -d.getTimezoneOffset();
const sign = offsetMin >= 0 ? "+" : "-";
const absOff = Math.abs(offsetMin);
const tzStr = sign + pad(Math.floor(absOff / 60)) + ":" + pad(absOff % 60);
return (
d.getFullYear() +
"-" +
pad(d.getMonth() + 1) +
"-" +
pad(d.getDate()) +
"T" +
" " +
pad(d.getHours()) +
":" +
pad(d.getMinutes()) +
":" +
pad(d.getSeconds()) +
tzStr
pad(d.getSeconds())
);
}
@@ -339,7 +317,6 @@ function init(_ctx) {
if (addr) {
navigator.clipboard.writeText(addr);
showFlash("Copied!");
flashCopyFeedback($("address-token-full"));
}
});
@@ -348,7 +325,6 @@ function init(_ctx) {
if (copyEl) {
navigator.clipboard.writeText(copyEl.dataset.copy);
showFlash("Copied!");
flashCopyFeedback(copyEl);
}
});
@@ -397,7 +373,6 @@ function init(_ctx) {
copyEl.addEventListener("click", () => {
navigator.clipboard.writeText(copyEl.dataset.copy);
showFlash("Copied!");
flashCopyFeedback(copyEl);
});
}
updateSendBalance();

View File

@@ -269,7 +269,7 @@ function showTxApproval(details) {
}
$("approve-tx-password").value = "";
hideError("approve-tx-error");
$("approve-tx-error").classList.add("hidden");
showView("approve-tx");
}
@@ -351,10 +351,10 @@ function showSignApproval(details) {
if (warningEl) {
if (sp.dangerWarning) {
warningEl.textContent = sp.dangerWarning;
warningEl.style.visibility = "visible";
warningEl.classList.remove("hidden");
} else {
warningEl.textContent = "";
warningEl.style.visibility = "hidden";
warningEl.classList.add("hidden");
}
}

View File

@@ -15,7 +15,6 @@ const {
hideError,
showView,
showFlash,
flashCopyFeedback,
addressTitle,
addressDotHtml,
escapeHtml,
@@ -118,7 +117,6 @@ function show(txInfo) {
copyEl.onclick = () => {
navigator.clipboard.writeText(copyEl.dataset.copy);
showFlash("Copied!");
flashCopyFeedback(copyEl);
};
}
} else {
@@ -186,10 +184,9 @@ function show(txInfo) {
`<div class="border border-border border-dashed p-2 mb-1 text-xs font-bold">WARNING: ${w}</div>`,
)
.join("");
warningsEl.style.visibility = "visible";
warningsEl.classList.remove("hidden");
} else {
warningsEl.innerHTML = "";
warningsEl.style.visibility = "hidden";
warningsEl.classList.add("hidden");
}
// Check for errors
@@ -227,12 +224,11 @@ function show(txInfo) {
errorsEl.innerHTML = errors
.map((e) => `<div class="text-xs">${e}</div>`)
.join("");
errorsEl.style.visibility = "visible";
errorsEl.classList.remove("hidden");
sendBtn.disabled = true;
sendBtn.classList.add("text-muted");
} else {
errorsEl.innerHTML = "";
errorsEl.style.visibility = "hidden";
errorsEl.classList.add("hidden");
sendBtn.disabled = false;
sendBtn.classList.remove("text-muted");
}
@@ -242,7 +238,7 @@ function show(txInfo) {
hideError("confirm-tx-password-error");
// Gas estimate — show placeholder then fetch async
$("confirm-fee").style.visibility = "visible";
$("confirm-fee").classList.remove("hidden");
$("confirm-fee-amount").textContent = "Estimating...";
state.viewData = { pendingTx: txInfo };
showView("confirm-tx");

View File

@@ -12,7 +12,7 @@ function show(walletIdx) {
wallet.name || "Wallet " + (walletIdx + 1);
$("delete-wallet-password").value = "";
$("delete-wallet-flash").textContent = "";
$("delete-wallet-flash").style.visibility = "hidden";
$("delete-wallet-flash").classList.add("hidden");
showView("delete-wallet-confirm");
}
@@ -29,14 +29,14 @@ function init(_ctx) {
if (!pw) {
$("delete-wallet-flash").textContent =
"Please enter your password.";
$("delete-wallet-flash").style.visibility = "visible";
$("delete-wallet-flash").classList.remove("hidden");
return;
}
if (deleteWalletIndex === null) {
$("delete-wallet-flash").textContent =
"No wallet selected for deletion.";
$("delete-wallet-flash").style.visibility = "visible";
$("delete-wallet-flash").classList.remove("hidden");
return;
}
@@ -52,7 +52,7 @@ function init(_ctx) {
await decryptWithPassword(wallet.encryptedSecret, pw);
} catch (_e) {
$("delete-wallet-flash").textContent = "Wrong password.";
$("delete-wallet-flash").style.visibility = "visible";
$("delete-wallet-flash").classList.remove("hidden");
btn.disabled = false;
btn.classList.remove("text-muted");
return;

View File

@@ -40,13 +40,11 @@ function $(id) {
function showError(id, msg) {
const el = $(id);
el.textContent = msg;
el.style.visibility = "visible";
el.classList.remove("hidden");
}
function hideError(id) {
const el = $(id);
el.textContent = "";
el.style.visibility = "hidden";
$(id).classList.add("hidden");
}
function showView(name) {
@@ -228,39 +226,18 @@ function formatAddressHtml(address, ensName, maxLen, title) {
function isoDate(timestamp) {
const d = new Date(timestamp * 1000);
const pad = (n) => String(n).padStart(2, "0");
if (state.utcTimestamps) {
return (
d.getUTCFullYear() +
"-" +
pad(d.getUTCMonth() + 1) +
"-" +
pad(d.getUTCDate()) +
"T" +
pad(d.getUTCHours()) +
":" +
pad(d.getUTCMinutes()) +
":" +
pad(d.getUTCSeconds()) +
"Z"
);
}
const offsetMin = -d.getTimezoneOffset();
const sign = offsetMin >= 0 ? "+" : "-";
const absOff = Math.abs(offsetMin);
const tzStr = sign + pad(Math.floor(absOff / 60)) + ":" + pad(absOff % 60);
return (
d.getFullYear() +
"-" +
pad(d.getMonth() + 1) +
"-" +
pad(d.getDate()) +
"T" +
" " +
pad(d.getHours()) +
":" +
pad(d.getMinutes()) +
":" +
pad(d.getSeconds()) +
tzStr
pad(d.getSeconds())
);
}
@@ -281,26 +258,12 @@ function timeAgo(timestamp) {
return years + " year" + (years !== 1 ? "s" : "") + " ago";
}
function flashCopyFeedback(el) {
if (!el) return;
el.classList.remove("copy-flash-fade");
el.classList.add("copy-flash-active");
setTimeout(() => {
el.classList.remove("copy-flash-active");
el.classList.add("copy-flash-fade");
setTimeout(() => {
el.classList.remove("copy-flash-fade");
}, 275);
}, 75);
}
module.exports = {
$,
showError,
hideError,
showView,
showFlash,
flashCopyFeedback,
balanceLine,
balanceLinesForAddress,
addressColor,

View File

@@ -2,7 +2,6 @@ const {
$,
showView,
showFlash,
flashCopyFeedback,
balanceLinesForAddress,
isoDate,
timeAgo,
@@ -86,10 +85,9 @@ function renderActiveAddress() {
el.innerHTML =
`<span class="underline decoration-dashed cursor-pointer" id="active-addr-copy">${dot}${escapeHtml(addr)}</span>` +
`<a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a>`;
$("active-addr-copy").addEventListener("click", (e) => {
$("active-addr-copy").addEventListener("click", () => {
navigator.clipboard.writeText(addr);
showFlash("Copied!");
flashCopyFeedback(e.currentTarget);
});
} else {
el.textContent = "";

View File

@@ -2,7 +2,6 @@ const {
$,
showView,
showFlash,
flashCopyFeedback,
formatAddressHtml,
addressTitle,
} = require("./helpers");
@@ -53,21 +52,19 @@ function show() {
"This is an ERC-20 token. Only send " +
symbol +
" on the Ethereum network to this address. Sending tokens on other networks will result in permanent loss.";
warningEl.style.visibility = "visible";
warningEl.classList.remove("hidden");
} else {
warningEl.textContent = "";
warningEl.style.visibility = "hidden";
warningEl.classList.add("hidden");
}
showView("receive");
}
function init(ctx) {
$("receive-address-block").addEventListener("click", (e) => {
$("receive-address-block").addEventListener("click", () => {
const addr = $("receive-address-block").dataset.full;
if (addr) {
navigator.clipboard.writeText(addr);
showFlash("Copied!");
flashCopyFeedback(e.currentTarget);
}
});
@@ -76,7 +73,6 @@ function init(ctx) {
if (addr) {
navigator.clipboard.writeText(addr);
showFlash("Copied!");
flashCopyFeedback($("receive-address-block"));
}
});

View File

@@ -241,12 +241,6 @@ function init(ctx) {
}
});
$("settings-utc-timestamps").checked = state.utcTimestamps;
$("settings-utc-timestamps").addEventListener("change", async () => {
state.utcTimestamps = $("settings-utc-timestamps").checked;
await saveState();
});
$("btn-main-add-wallet").addEventListener("click", ctx.showAddWalletView);
$("btn-settings-add-token").addEventListener(

View File

@@ -73,8 +73,7 @@ function renderDropdown() {
function show() {
$("settings-addtoken-address").value = "";
$("settings-addtoken-info").textContent = "";
$("settings-addtoken-info").style.visibility = "hidden";
$("settings-addtoken-info").classList.add("hidden");
renderTop10();
renderDropdown();
showView("settings-addtoken");
@@ -130,7 +129,7 @@ function init(_ctx) {
}
const infoEl = $("settings-addtoken-info");
infoEl.textContent = "Looking up token...";
infoEl.style.visibility = "visible";
infoEl.classList.remove("hidden");
log.debugf("Looking up token contract", addr);
try {
const info = await lookupTokenInfo(addr, state.rpcUrl);
@@ -144,8 +143,7 @@ function init(_ctx) {
await saveState();
showFlash("Added " + info.symbol);
$("settings-addtoken-address").value = "";
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
infoEl.classList.add("hidden");
renderTop10();
renderDropdown();
ctx.doRefreshAndRender();
@@ -153,8 +151,7 @@ function init(_ctx) {
const detail = e.shortMessage || e.message || String(e);
log.errorf("Token lookup failed for", addr, detail);
showFlash(detail);
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
infoEl.classList.add("hidden");
}
});
}

View File

@@ -5,7 +5,6 @@ const {
$,
showView,
showFlash,
flashCopyFeedback,
addressDotHtml,
addressTitle,
escapeHtml,
@@ -172,7 +171,6 @@ function render() {
el.onclick = () => {
navigator.clipboard.writeText(el.dataset.copy);
showFlash("Copied!");
flashCopyFeedback(el);
};
});
}
@@ -250,7 +248,6 @@ async function loadCalldata(txHash, toAddress) {
el.onclick = () => {
navigator.clipboard.writeText(el.dataset.copy);
showFlash("Copied!");
flashCopyFeedback(el);
};
});
}

View File

@@ -4,7 +4,6 @@ const {
$,
showView,
showFlash,
flashCopyFeedback,
addressDotHtml,
addressTitle,
escapeHtml,
@@ -78,7 +77,6 @@ function attachCopyHandlers(viewId) {
el.onclick = () => {
navigator.clipboard.writeText(el.dataset.copy);
showFlash("Copied!");
flashCopyFeedback(el);
};
});
}

View File

@@ -23,7 +23,6 @@ const DEFAULT_STATE = {
hideFraudContracts: true,
hideDustTransactions: true,
dustThresholdGwei: 100000,
utcTimestamps: false,
fraudContracts: [],
tokenHolderCache: {},
};
@@ -54,7 +53,6 @@ async function saveState() {
hideFraudContracts: state.hideFraudContracts,
hideDustTransactions: state.hideDustTransactions,
dustThresholdGwei: state.dustThresholdGwei,
utcTimestamps: state.utcTimestamps,
fraudContracts: state.fraudContracts,
tokenHolderCache: state.tokenHolderCache,
currentView: state.currentView,
@@ -110,8 +108,6 @@ async function loadState() {
saved.dustThresholdGwei !== undefined
? saved.dustThresholdGwei
: 100000;
state.utcTimestamps =
saved.utcTimestamps !== undefined ? saved.utcTimestamps : false;
state.fraudContracts = saved.fraudContracts || [];
state.tokenHolderCache = saved.tokenHolderCache || {};
state.currentView = saved.currentView || null;