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() {