From e5ffbb4634b7105b1335d3c9198c9a0084285963 Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 26 Feb 2026 16:41:15 +0700 Subject: [PATCH] Show 25 most recent transactions from all addresses on home screen Fetch transactions for every address across all wallets in parallel, merge and deduplicate by hash, apply anti-poisoning filters, sort by block number, and display the top 25 below the wallet list. Clicking a transaction navigates to the address detail page for the relevant address. Shows "Loading..." placeholder to prevent layout shift. --- src/popup/index.html | 8 ++ src/popup/views/home.js | 160 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/src/popup/index.html b/src/popup/index.html index 30d77d6..c6de379 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -217,6 +217,14 @@
+ +
+

Recent Transactions

+
+
Loading...
+
+
+
String(n).padStart(2, "0"); + return ( + d.getFullYear() + + "-" + + pad(d.getMonth() + 1) + + "-" + + pad(d.getDate()) + + " " + + pad(d.getHours()) + + ":" + + pad(d.getMinutes()) + + ":" + + pad(d.getSeconds()) + ); +} + +let homeTxs = []; + +function renderHomeTxList(ctx) { + const list = $("home-tx-list"); + if (!list) return; + if (homeTxs.length === 0) { + list.innerHTML = + '
No transactions found.
'; + return; + } + let html = ""; + let i = 0; + for (const tx of homeTxs) { + const counterparty = tx.direction === "sent" ? tx.to : tx.from; + const dirLabel = tx.direction === "sent" ? "Sent" : "Received"; + const amountStr = escapeHtml(tx.value + " " + tx.symbol); + const maxAddr = Math.max(10, 36 - Math.max(0, amountStr.length - 10)); + const displayAddr = 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 += `
`; + html += `
${ago}${dirLabel}${err}
`; + html += `
${dot}${addrStr}${amountStr}
`; + html += `
`; + i++; + } + list.innerHTML = html; + list.querySelectorAll(".home-tx-row").forEach((row) => { + row.addEventListener("click", () => { + const idx = parseInt(row.dataset.tx, 10); + const tx = homeTxs[idx]; + // Find which wallet/address this tx belongs to and navigate + for (let wi = 0; wi < state.wallets.length; wi++) { + for ( + let ai = 0; + ai < state.wallets[wi].addresses.length; + ai++ + ) { + const addr = state.wallets[wi].addresses[ai].address; + if ( + addr.toLowerCase() === tx.from.toLowerCase() || + addr.toLowerCase() === tx.to.toLowerCase() + ) { + state.selectedWallet = wi; + state.selectedAddress = ai; + ctx.showAddressDetail(); + return; + } + } + } + }); + }); +} + +async function loadHomeTxs(ctx) { + const allAddresses = []; + for (const w of state.wallets) { + for (const a of w.addresses) { + allAddresses.push(a.address); + } + } + if (allAddresses.length === 0) return; + + const filters = { + hideLowHolderTokens: state.hideLowHolderTokens, + hideFraudContracts: state.hideFraudContracts, + hideDustTransactions: state.hideDustTransactions, + dustThresholdGwei: state.dustThresholdGwei, + fraudContracts: state.fraudContracts, + }; + + try { + const fetches = allAddresses.map((addr) => + fetchRecentTransactions(addr, state.blockscoutUrl), + ); + const results = await Promise.all(fetches); + + // Merge, deduplicate by hash, filter, sort, take 25 + const seen = new Set(); + let merged = []; + for (const txs of results) { + for (const tx of txs) { + if (seen.has(tx.hash)) continue; + seen.add(tx.hash); + merged.push(tx); + } + } + + const filtered = filterTransactions(merged, filters); + + // Persist any newly discovered fraud contracts + if (filtered.newFraudContracts.length > 0) { + for (const addr of filtered.newFraudContracts) { + if (!state.fraudContracts.includes(addr)) { + state.fraudContracts.push(addr); + } + } + await saveState(); + } + + merged = filtered.transactions; + merged.sort((a, b) => b.blockNumber - a.blockNumber); + homeTxs = merged.slice(0, 25); + renderHomeTxList(ctx); + } catch (e) { + log.errorf("loadHomeTxs failed:", e.message); + const list = $("home-tx-list"); + if (list) { + list.innerHTML = + '
Failed to load transactions.
'; + } + } +} + function render(ctx) { const container = $("wallet-list"); if (state.wallets.length === 0) { @@ -211,6 +370,7 @@ function render(ctx) { renderTotalValue(); renderActiveAddress(); + loadHomeTxs(ctx); } function selectActiveAddress() {