diff --git a/src/Transaction.tsx b/src/Transaction.tsx index a240c7e..7107b32 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -11,6 +11,10 @@ import { useInternalOperations, useTxData } from "./useErigonHooks"; import { useETHUSDOracle } from "./usePriceOracle"; import { useAppConfigContext } from "./useAppConfig"; import { useSourcify, useTransactionDescription } from "./useSourcify"; +import { + transactionDataCollector, + useResolvedAddresses, +} from "./useResolvedAddresses"; const Details = React.lazy( () => @@ -36,6 +40,11 @@ const Transaction: React.FC = () => { const { txhash } = params; const txData = useTxData(provider, txhash); + const addrCollector = useMemo( + () => transactionDataCollector(txData), + [txData] + ); + const resolvedAddresses = useResolvedAddresses(provider, addrCollector); const internalOps = useInternalOperations(provider, txData); const sendsEthToMiner = useMemo(() => { @@ -100,10 +109,15 @@ const Transaction: React.FC = () => { internalOps={internalOps} sendsEthToMiner={sendsEthToMiner} ethUSDPrice={blockETHUSDPrice} + resolvedAddresses={resolvedAddresses} /> - + diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 4746cc5..72f448a 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -38,6 +38,7 @@ import ModeTab from "../components/ModeTab"; import DecodedParamsTable from "./decoder/DecodedParamsTable"; import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; import { DevDoc, UserDoc } from "../useSourcify"; +import { ResolvedAddresses } from "../api/address-resolver"; type DetailsProps = { txData: TransactionData; @@ -47,6 +48,7 @@ type DetailsProps = { internalOps?: InternalOperation[]; sendsEthToMiner: boolean; ethUSDPrice: BigNumber | undefined; + resolvedAddresses: ResolvedAddresses | undefined; }; const Details: React.FC = ({ @@ -57,6 +59,7 @@ const Details: React.FC = ({ internalOps, sendsEthToMiner, ethUSDPrice, + resolvedAddresses, }) => { const hasEIP1559 = txData.confirmedData?.blockBaseFeePerGas !== undefined && @@ -154,6 +157,7 @@ const Details: React.FC = ({ address={txData.from} miner={txData.from === txData.confirmedData?.miner} txFrom + resolvedAddresses={resolvedAddresses} /> @@ -171,6 +175,7 @@ const Details: React.FC = ({ address={txData.to} miner={txData.to === txData.confirmedData?.miner} txTo + resolvedAddresses={resolvedAddresses} /> @@ -188,6 +193,7 @@ const Details: React.FC = ({ address={txData.confirmedData.createdContractAddress!} creation txTo + resolvedAddresses={resolvedAddresses} /> diff --git a/src/transaction/LogEntry.tsx b/src/transaction/LogEntry.tsx index 23ab883..2993e16 100644 --- a/src/transaction/LogEntry.tsx +++ b/src/transaction/LogEntry.tsx @@ -10,14 +10,21 @@ import DecodedParamsTable from "./decoder/DecodedParamsTable"; import DecodedLogSignature from "./decoder/DecodedLogSignature"; import { TransactionData } from "../types"; import { useTopic0 } from "../useTopic0"; +import { ResolvedAddresses } from "../api/address-resolver"; type LogEntryProps = { txData: TransactionData; log: Log; logDesc: LogDescription | null | undefined; + resolvedAddresses: ResolvedAddresses | undefined; }; -const LogEntry: React.FC = ({ txData, log, logDesc }) => { +const LogEntry: React.FC = ({ + txData, + log, + logDesc, + resolvedAddresses, +}) => { const rawTopic0 = log.topics[0]; const topic0 = useTopic0(rawTopic0); @@ -62,6 +69,7 @@ const LogEntry: React.FC = ({ txData, log, logDesc }) => { miner={log.address === txData.confirmedData?.miner} txFrom={log.address === txData.from} txTo={log.address === txData.to} + resolvedAddresses={resolvedAddresses} /> diff --git a/src/transaction/Logs.tsx b/src/transaction/Logs.tsx index 45fe491..1fd4207 100644 --- a/src/transaction/Logs.tsx +++ b/src/transaction/Logs.tsx @@ -5,13 +5,15 @@ import LogEntry from "./LogEntry"; import { TransactionData } from "../types"; import { useAppConfigContext } from "../useAppConfig"; import { Metadata, useMultipleMetadata } from "../useSourcify"; +import { ResolvedAddresses } from "../api/address-resolver"; type LogsProps = { txData: TransactionData; metadata: Metadata | null | undefined; + resolvedAddresses: ResolvedAddresses | undefined; }; -const Logs: React.FC = ({ txData, metadata }) => { +const Logs: React.FC = ({ txData, metadata, resolvedAddresses }) => { const baseMetadatas = useMemo((): Record => { if (!txData.to || metadata === undefined) { return {}; @@ -70,6 +72,7 @@ const Logs: React.FC = ({ txData, metadata }) => { txData={txData} log={l} logDesc={logDescs?.[i]} + resolvedAddresses={resolvedAddresses} /> ))} diff --git a/src/useResolvedAddresses.ts b/src/useResolvedAddresses.ts index 3eefdf0..74042e5 100644 --- a/src/useResolvedAddresses.ts +++ b/src/useResolvedAddresses.ts @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { JsonRpcProvider } from "@ethersproject/providers"; -import { ProcessedTransaction } from "./types"; +import { ProcessedTransaction, TransactionData } from "./types"; import { batchPopulate, ResolvedAddresses } from "./api/address-resolver"; export type AddressCollector = () => string[]; @@ -25,6 +25,42 @@ export const pageCollector = return Array.from(uniqueAddresses); }; +export const transactionDataCollector = + (txData: TransactionData | null | undefined): AddressCollector => + () => { + if (!txData) { + return []; + } + + const uniqueAddresses = new Set(); + + // Standard fields + uniqueAddresses.add(txData.from); + if (txData.to) { + uniqueAddresses.add(txData.to); + } + if (txData.confirmedData?.createdContractAddress) { + uniqueAddresses.add(txData.confirmedData?.createdContractAddress); + } + + // Dig token transfers + for (const t of txData.tokenTransfers) { + uniqueAddresses.add(t.from); + uniqueAddresses.add(t.to); + uniqueAddresses.add(t.token); + } + + // Dig log addresses + if (txData.confirmedData) { + for (const l of txData.confirmedData.logs) { + uniqueAddresses.add(l.address); + // TODO: find a way to dig over decoded address log attributes + } + } + + return Array.from(uniqueAddresses); + }; + export const useResolvedAddresses = ( provider: JsonRpcProvider | undefined, addrCollector: AddressCollector