diff --git a/src/shared/transactions.js b/src/shared/transactions.js index e12d310..ad45698 100644 --- a/src/shared/transactions.js +++ b/src/shared/transactions.js @@ -153,9 +153,11 @@ async function fetchRecentTransactions(address, blockscoutUrl, count = 25) { // When a token transfer shares a hash with a normal tx, the normal tx // is the contract call (0 ETH) and the token transfer has the real - // amount and symbol. Replace the normal tx with the token transfer, - // but preserve contract call metadata (direction, label, method) so - // swaps and other contract interactions display correctly. + // amount and symbol. A single transaction (e.g. a swap) can produce + // multiple token transfers (one per token involved), so we key token + // transfers by hash + contract address to keep all of them. We also + // preserve contract-call metadata (direction, label, method) from the + // matching normal tx so swaps display correctly. for (const tt of ttJson.items || []) { const parsed = parseTokenTransfer(tt, addrLower); const existing = txsByHash.get(parsed.hash); @@ -164,8 +166,13 @@ async function fetchRecentTransactions(address, blockscoutUrl, count = 25) { parsed.directionLabel = existing.directionLabel; parsed.isContractCall = true; parsed.method = existing.method; + // Remove the bare-hash normal tx so it doesn't appear as a + // duplicate with empty value; token transfers replace it. + txsByHash.delete(parsed.hash); } - txsByHash.set(parsed.hash, parsed); + // Use composite key so multiple token transfers per tx are kept. + const ttKey = parsed.hash + ":" + (parsed.contractAddress || ""); + txsByHash.set(ttKey, parsed); } const txs = [...txsByHash.values()];