diff --git a/src/address/AddressTransactionResults.tsx b/src/address/AddressTransactionResults.tsx index b13bbd2..4c85c6c 100644 --- a/src/address/AddressTransactionResults.tsx +++ b/src/address/AddressTransactionResults.tsx @@ -8,7 +8,11 @@ import TransactionItem from "../search/TransactionItem"; import UndefinedPageControl from "../search/UndefinedPageControl"; import { useFeeToggler } from "../search/useFeeToggler"; import { SelectionContext, useSelection } from "../useSelection"; -import { useMultipleMetadata } from "../sourcify/useSourcify"; +import { + useDedupedAddresses, + useMultipleMetadata, +} from "../sourcify/useSourcify"; +import { useAddressCodes } from "../useErigonHooks"; import { useMultipleETHUSDOracle } from "../usePriceOracle"; import { RuntimeContext } from "../useRuntime"; import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses"; @@ -120,9 +124,11 @@ const AddressTransactionResults: React.FC = ({ return _addresses; }, [address, page]); const { sourcifySource } = useAppConfigContext(); + const deduped = useDedupedAddresses(addresses); + const checked = useAddressCodes(provider, deduped); const metadatas = useMultipleMetadata( undefined, - addresses, + checked, provider?.network.chainId, sourcifySource ); diff --git a/src/block/BlockTransactionResults.tsx b/src/block/BlockTransactionResults.tsx index f2d8d08..891637b 100644 --- a/src/block/BlockTransactionResults.tsx +++ b/src/block/BlockTransactionResults.tsx @@ -13,7 +13,11 @@ import { ChecksummedAddress, ProcessedTransaction } from "../types"; import { PAGE_SIZE } from "../params"; import { useMultipleETHUSDOracle } from "../usePriceOracle"; import { useAppConfigContext } from "../useAppConfig"; -import { useMultipleMetadata } from "../sourcify/useSourcify"; +import { + useDedupedAddresses, + useMultipleMetadata, +} from "../sourcify/useSourcify"; +import { useAddressCodes } from "../useErigonHooks"; type BlockTransactionResultsProps = { blockTag: BlockTag; @@ -44,9 +48,11 @@ const BlockTransactionResults: React.FC = ({ return page.map((t) => t.to).filter((to): to is string => to !== undefined); }, [page]); const { sourcifySource } = useAppConfigContext(); + const deduped = useDedupedAddresses(addresses); + const checked = useAddressCodes(provider, deduped); const metadatas = useMultipleMetadata( undefined, - addresses, + checked, provider?.network.chainId, sourcifySource ); diff --git a/src/sourcify/useSourcify.ts b/src/sourcify/useSourcify.ts index e4d1ab1..6b1e5d6 100644 --- a/src/sourcify/useSourcify.ts +++ b/src/sourcify/useSourcify.ts @@ -131,51 +131,57 @@ export const useSingleMetadata = ( return address !== undefined ? metadatas[address] : undefined; }; +export const useDedupedAddresses = ( + addresses: (ChecksummedAddress | undefined)[] +): ChecksummedAddress[] => { + return useMemo(() => { + const deduped = new Set( + addresses.filter((a): a is ChecksummedAddress => a !== undefined) + ); + return [...deduped]; + }, [addresses]); +}; + export const useMultipleMetadata = ( baseMetadatas: Record | undefined, - addresses: (ChecksummedAddress | undefined)[], + addresses: ChecksummedAddress[] | undefined, chainId: number | undefined, source: SourcifySource ): Record => { const [rawMetadata, setRawMetadata] = useState< Record >({}); - useEffect(() => { - if (!addresses || chainId === undefined) { + if (addresses === undefined || chainId === undefined) { return; } setRawMetadata({}); const abortController = new AbortController(); - const fetchMetadata = async (dedupedAddresses: string[]) => { - const promises: Promise[] = []; - for (const address of dedupedAddresses) { - promises.push( + const fetchMetadata = async (_addresses: string[]) => { + const fetchers: Promise[] = []; + for (const address of _addresses) { + fetchers.push( fetchSourcifyMetadata(address, chainId, source, abortController) ); } - const results = await Promise.all(promises); + const results = await Promise.all(fetchers); if (abortController.signal.aborted) { return; } - const metadatas: Record = baseMetadatas - ? { ...baseMetadatas } - : {}; + let metadatas: Record = {}; + if (baseMetadatas) { + metadatas = { ...baseMetadatas }; + } for (let i = 0; i < results.length; i++) { - metadatas[dedupedAddresses[i]] = results[i]; + metadatas[_addresses[i]] = results[i]; } setRawMetadata(metadatas); }; - const deduped = new Set( - addresses.filter( - (a): a is ChecksummedAddress => - a !== undefined && baseMetadatas?.[a] === undefined - ) - ); - fetchMetadata(Array.from(deduped)); + const filtered = addresses.filter((a) => baseMetadatas?.[a] === undefined); + fetchMetadata(filtered); return () => { abortController.abort(); diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 994ab51..8799987 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -37,7 +37,13 @@ import { use4Bytes, useTransactionDescription, } from "../use4Bytes"; -import { DevDoc, useMultipleMetadata, UserDoc } from "../sourcify/useSourcify"; +import { + DevDoc, + useDedupedAddresses, + useMultipleMetadata, + UserDoc, +} from "../sourcify/useSourcify"; +import { useAddressCodes } from "../useErigonHooks"; import { ResolvedAddresses } from "../api/address-resolver"; import { RuntimeContext } from "../useRuntime"; import { useAppConfigContext } from "../useAppConfig"; @@ -96,9 +102,11 @@ const Details: React.FC = ({ return _addresses; }, [txData]); const { sourcifySource } = useAppConfigContext(); + const deduped = useDedupedAddresses(addresses); + const checked = useAddressCodes(provider, deduped); const metadatas = useMultipleMetadata( undefined, - addresses, + checked, provider?.network.chainId, sourcifySource ); diff --git a/src/transaction/Logs.tsx b/src/transaction/Logs.tsx index 4a9cc93..d907a37 100644 --- a/src/transaction/Logs.tsx +++ b/src/transaction/Logs.tsx @@ -4,7 +4,12 @@ import ContentFrame from "../ContentFrame"; import LogEntry from "./LogEntry"; import { TransactionData } from "../types"; import { useAppConfigContext } from "../useAppConfig"; -import { Metadata, useMultipleMetadata } from "../sourcify/useSourcify"; +import { + Metadata, + useDedupedAddresses, + useMultipleMetadata, +} from "../sourcify/useSourcify"; +import { useAddressCodes } from "../useErigonHooks"; import { ResolvedAddresses } from "../api/address-resolver"; import { RuntimeContext } from "../useRuntime"; @@ -31,9 +36,11 @@ const Logs: React.FC = ({ txData, metadata, resolvedAddresses }) => { ); const { provider } = useContext(RuntimeContext); const { sourcifySource } = useAppConfigContext(); + const deduped = useDedupedAddresses(logAddresses); + const checked = useAddressCodes(provider, deduped); const metadatas = useMultipleMetadata( baseMetadatas, - logAddresses, + checked, provider?.network.chainId, sourcifySource ); diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 17d629f..adbfce2 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -14,6 +14,7 @@ import { InternalOperation, ProcessedTransaction, OperationType, + ChecksummedAddress, } from "./types"; import erc20 from "./erc20.json"; @@ -440,3 +441,42 @@ export const useUniqueSignatures = (traces: TraceGroup[] | undefined) => { return uniqueSignatures; }; + +const checkCode = async ( + provider: JsonRpcProvider, + address: ChecksummedAddress +): Promise => { + const code = await provider.getCode(address); + if (code !== "0x") { + console.log(`Has code: ${address}`); + } + return code === "0x"; +}; + +export const useAddressCodes = ( + provider: JsonRpcProvider | undefined, + addresses: ChecksummedAddress[] +): ChecksummedAddress[] | undefined => { + const [hasCode, setCode] = useState(); + + useEffect(() => { + if (provider === undefined) { + setCode(undefined); + return; + } + + const readCodes = async () => { + const checkers: Promise[] = []; + for (const a of addresses) { + checkers.push(checkCode(provider, a)); + } + + const result = await Promise.all(checkers); + const filtered = addresses.filter((_, i) => result[i]); + setCode(filtered); + }; + readCodes(); + }, [provider, addresses]); + + return hasCode; +};