Add address color dots and cached ENS reverse lookups
Some checks failed
check / check (push) Has been cancelled
Some checks failed
check / check (push) Has been cancelled
Deterministic colored dots derived from address bytes (16-color palette) displayed before every address. ENS reverse resolution for transaction counterparties with 12-hour localStorage cache.
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
const { $, showView, showFlash, balanceLinesForAddress } = require("./helpers");
|
||||
const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
balanceLinesForAddress,
|
||||
addressDotHtml,
|
||||
} = require("./helpers");
|
||||
const { state, currentAddress } = require("../../shared/state");
|
||||
const { formatUsd, getAddressValueUsd } = require("../../shared/prices");
|
||||
const { fetchRecentTransactions } = require("../../shared/transactions");
|
||||
const { resolveEnsNames } = require("../../shared/ens");
|
||||
const { updateSendBalance } = require("./send");
|
||||
const { log } = require("../../shared/log");
|
||||
const QRCode = require("qrcode");
|
||||
@@ -13,11 +20,13 @@ function show() {
|
||||
const ai = state.selectedAddress;
|
||||
$("address-title").textContent =
|
||||
wallet.name + " \u2014 Address " + (wi + 1) + "." + (ai + 1);
|
||||
$("address-dot").innerHTML = addressDotHtml(addr.address);
|
||||
$("address-full").textContent = addr.address;
|
||||
$("address-usd-total").textContent = formatUsd(getAddressValueUsd(addr));
|
||||
const ensEl = $("address-ens");
|
||||
if (addr.ensName) {
|
||||
ensEl.textContent = addr.ensName;
|
||||
ensEl.innerHTML =
|
||||
addressDotHtml(addr.address) + escapeHtml(addr.ensName);
|
||||
ensEl.classList.remove("hidden");
|
||||
} else {
|
||||
ensEl.classList.add("hidden");
|
||||
@@ -80,10 +89,30 @@ function escapeHtml(s) {
|
||||
|
||||
let loadedTxs = [];
|
||||
|
||||
let ensNameMap = new Map();
|
||||
|
||||
async function loadTransactions(address) {
|
||||
try {
|
||||
const txs = await fetchRecentTransactions(address, state.blockscoutUrl);
|
||||
loadedTxs = txs;
|
||||
|
||||
// Collect unique counterparty addresses for ENS resolution.
|
||||
const counterparties = [
|
||||
...new Set(
|
||||
txs.map((tx) => (tx.direction === "sent" ? tx.to : tx.from)),
|
||||
),
|
||||
];
|
||||
if (counterparties.length > 0) {
|
||||
try {
|
||||
ensNameMap = await resolveEnsNames(
|
||||
counterparties,
|
||||
state.rpcUrl,
|
||||
);
|
||||
} catch {
|
||||
ensNameMap = new Map();
|
||||
}
|
||||
}
|
||||
|
||||
renderTransactions(txs);
|
||||
} catch (e) {
|
||||
log.errorf("loadTransactions failed:", e.message);
|
||||
@@ -103,17 +132,20 @@ function renderTransactions(txs) {
|
||||
let i = 0;
|
||||
for (const tx of txs) {
|
||||
const counterparty = tx.direction === "sent" ? tx.to : tx.from;
|
||||
const ensName = ensNameMap.get(counterparty) || null;
|
||||
const dirLabel = tx.direction === "sent" ? "Sent" : "Received";
|
||||
const amountStr = escapeHtml(tx.value + " " + tx.symbol);
|
||||
const maxAddr = Math.max(10, 38 - Math.max(0, amountStr.length - 10));
|
||||
const addrStr = escapeHtml(truncateMiddle(counterparty, maxAddr));
|
||||
const displayAddr = ensName || truncateMiddle(counterparty, maxAddr);
|
||||
const addrStr = escapeHtml(displayAddr);
|
||||
const dot = addressDotHtml(counterparty);
|
||||
const err = tx.isError ? " (failed)" : "";
|
||||
const opacity = tx.isError ? " opacity:0.5;" : "";
|
||||
const ago = escapeHtml(timeAgo(tx.timestamp));
|
||||
const iso = escapeHtml(isoDate(tx.timestamp));
|
||||
html += `<div class="tx-row py-2 border-b border-border-light text-xs cursor-pointer hover:bg-hover" data-tx="${i}" style="${opacity}">`;
|
||||
html += `<div class="flex justify-between"><span class="text-muted" title="${iso}">${ago}</span><span>${dirLabel}${err}</span></div>`;
|
||||
html += `<div class="flex justify-between"><span>${addrStr}</span><span>${amountStr}</span></div>`;
|
||||
html += `<div class="flex justify-between"><span class="flex items-center">${dot}${addrStr}</span><span>${amountStr}</span></div>`;
|
||||
html += `</div>`;
|
||||
i++;
|
||||
}
|
||||
@@ -126,10 +158,23 @@ function renderTransactions(txs) {
|
||||
});
|
||||
}
|
||||
|
||||
function txDetailAddressHtml(address) {
|
||||
const ensName = ensNameMap.get(address) || null;
|
||||
const dot = addressDotHtml(address);
|
||||
if (ensName) {
|
||||
return (
|
||||
dot +
|
||||
escapeHtml(ensName) +
|
||||
`<div class="break-all">${escapeHtml(address)}</div>`
|
||||
);
|
||||
}
|
||||
return dot + escapeHtml(address);
|
||||
}
|
||||
|
||||
function showTxDetail(tx) {
|
||||
$("tx-detail-hash").textContent = tx.hash;
|
||||
$("tx-detail-from").textContent = tx.from;
|
||||
$("tx-detail-to").textContent = tx.to;
|
||||
$("tx-detail-from").innerHTML = txDetailAddressHtml(tx.from);
|
||||
$("tx-detail-to").innerHTML = txDetailAddressHtml(tx.to);
|
||||
$("tx-detail-value").textContent = tx.value + " " + tx.symbol;
|
||||
$("tx-detail-time").textContent =
|
||||
isoDate(tx.timestamp) + " (" + timeAgo(tx.timestamp) + ")";
|
||||
|
||||
Reference in New Issue
Block a user