Token auto-discovery, tx history, balance polling, EIP-6963, UI overhaul
All checks were successful
check / check (push) Successful in 14s

Major changes:
- Fetch token balances and tx history from Blockscout API (configurable)
- Remove manual token discovery (discoverTokens) in favor of Blockscout
- HD address gap scanning on mnemonic import
- Duplicate mnemonic detection on wallet add
- EIP-6963 multi-wallet discovery + selectedAddress updates in inpage
- Two-tier balance refresh: 10s while popup open, 60s background
- Fix $0.00 flash before prices load (return null when no prices)
- No-layout-shift: min-height on total value element
- Aligned balance columns (42ch address width, consistent USD column)
- All errors use flash messages instead of off-screen error divs
- Settings gear in global title bar, add-wallet moved to settings pane
- Settings wells with light grey background, configurable Blockscout URL
- Consistent "< Back" buttons top-left on all views
- Address titles (Address 1.1, 1.2, etc.) on main and detail views
- Send view shows current balance of selected asset
- Clickable affordance policy added to README
- Shortened mnemonic backup warning
- Fix broken background script constant imports
This commit is contained in:
2026-02-26 02:13:39 +07:00
parent 2b2137716c
commit 3bd2b58543
27 changed files with 978 additions and 420 deletions

View File

@@ -1,6 +1,11 @@
// Shared DOM helpers used by all views.
const { DEBUG } = require("../../shared/wallet");
const { DEBUG } = require("../../shared/constants");
const {
formatUsd,
getPrice,
getAddressValueUsd,
} = require("../../shared/prices");
const VIEWS = [
"welcome",
@@ -37,6 +42,7 @@ function showView(name) {
el.classList.toggle("hidden", v !== name);
}
}
clearFlash();
if (DEBUG) {
const banner = document.getElementById("debug-banner");
if (banner) {
@@ -45,4 +51,58 @@ function showView(name) {
}
}
module.exports = { $, showError, hideError, showView };
let flashTimer = null;
function clearFlash() {
if (flashTimer) {
clearTimeout(flashTimer);
flashTimer = null;
}
$("flash-msg").textContent = "";
}
function showFlash(msg, duration = 2000) {
clearFlash();
$("flash-msg").textContent = msg;
flashTimer = setTimeout(() => {
$("flash-msg").textContent = "";
flashTimer = null;
}, duration);
}
function balanceLine(symbol, amount, price) {
const qty = amount.toFixed(4);
const usd = price ? formatUsd(amount * price) : "";
return (
`<div class="flex text-xs">` +
`<span class="flex justify-between shrink-0" style="width:42ch">` +
`<span>${symbol}</span>` +
`<span>${qty}</span>` +
`</span>` +
`<span class="text-right text-muted flex-1">${usd}</span>` +
`</div>`
);
}
function balanceLinesForAddress(addr) {
let html = balanceLine(
"ETH",
parseFloat(addr.balance || "0"),
getPrice("ETH"),
);
for (const t of addr.tokenBalances || []) {
const bal = parseFloat(t.balance || "0");
if (bal === 0) continue;
html += balanceLine(t.symbol, bal, getPrice(t.symbol));
}
return html;
}
module.exports = {
$,
showError,
hideError,
showView,
showFlash,
balanceLinesForAddress,
};