Merge branch 'feature/optimize-detect-contracts' into develop
This commit is contained in:
commit
9443a91a46
|
@ -8,13 +8,12 @@ import TransactionItem from "../search/TransactionItem";
|
||||||
import UndefinedPageControl from "../search/UndefinedPageControl";
|
import UndefinedPageControl from "../search/UndefinedPageControl";
|
||||||
import { useFeeToggler } from "../search/useFeeToggler";
|
import { useFeeToggler } from "../search/useFeeToggler";
|
||||||
import { SelectionContext, useSelection } from "../useSelection";
|
import { SelectionContext, useSelection } from "../useSelection";
|
||||||
import { useMultipleMetadata } from "../sourcify/useSourcify";
|
|
||||||
import { useMultipleETHUSDOracle } from "../usePriceOracle";
|
import { useMultipleETHUSDOracle } from "../usePriceOracle";
|
||||||
import { RuntimeContext } from "../useRuntime";
|
import { RuntimeContext } from "../useRuntime";
|
||||||
import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses";
|
import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses";
|
||||||
import { useAppConfigContext } from "../useAppConfig";
|
|
||||||
import { useParams, useSearchParams } from "react-router-dom";
|
import { useParams, useSearchParams } from "react-router-dom";
|
||||||
import { ChecksummedAddress } from "../types";
|
import { ChecksummedAddress } from "../types";
|
||||||
|
import { useContractsMetadata } from "../hooks";
|
||||||
|
|
||||||
type AddressTransactionResultsProps = {
|
type AddressTransactionResultsProps = {
|
||||||
address: ChecksummedAddress;
|
address: ChecksummedAddress;
|
||||||
|
@ -119,13 +118,7 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
|
||||||
}
|
}
|
||||||
return _addresses;
|
return _addresses;
|
||||||
}, [address, page]);
|
}, [address, page]);
|
||||||
const { sourcifySource } = useAppConfigContext();
|
const metadatas = useContractsMetadata(addresses, provider);
|
||||||
const metadatas = useMultipleMetadata(
|
|
||||||
undefined,
|
|
||||||
addresses,
|
|
||||||
provider?.network.chainId,
|
|
||||||
sourcifySource
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentFrame tabs>
|
<ContentFrame tabs>
|
||||||
|
|
|
@ -12,8 +12,7 @@ import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses";
|
||||||
import { ChecksummedAddress, ProcessedTransaction } from "../types";
|
import { ChecksummedAddress, ProcessedTransaction } from "../types";
|
||||||
import { PAGE_SIZE } from "../params";
|
import { PAGE_SIZE } from "../params";
|
||||||
import { useMultipleETHUSDOracle } from "../usePriceOracle";
|
import { useMultipleETHUSDOracle } from "../usePriceOracle";
|
||||||
import { useAppConfigContext } from "../useAppConfig";
|
import { useContractsMetadata } from "../hooks";
|
||||||
import { useMultipleMetadata } from "../sourcify/useSourcify";
|
|
||||||
|
|
||||||
type BlockTransactionResultsProps = {
|
type BlockTransactionResultsProps = {
|
||||||
blockTag: BlockTag;
|
blockTag: BlockTag;
|
||||||
|
@ -43,13 +42,7 @@ const BlockTransactionResults: React.FC<BlockTransactionResultsProps> = ({
|
||||||
|
|
||||||
return page.map((t) => t.to).filter((to): to is string => to !== undefined);
|
return page.map((t) => t.to).filter((to): to is string => to !== undefined);
|
||||||
}, [page]);
|
}, [page]);
|
||||||
const { sourcifySource } = useAppConfigContext();
|
const metadatas = useContractsMetadata(addresses, provider);
|
||||||
const metadatas = useMultipleMetadata(
|
|
||||||
undefined,
|
|
||||||
addresses,
|
|
||||||
provider?.network.chainId,
|
|
||||||
sourcifySource
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentFrame>
|
<ContentFrame>
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { JsonRpcProvider } from "@ethersproject/providers";
|
||||||
|
import { ChecksummedAddress } from "./types";
|
||||||
|
import {
|
||||||
|
Metadata,
|
||||||
|
useDedupedAddresses,
|
||||||
|
useMultipleMetadata,
|
||||||
|
} from "./sourcify/useSourcify";
|
||||||
|
import { useAppConfigContext } from "./useAppConfig";
|
||||||
|
import { useAddressesWithCode } from "./useErigonHooks";
|
||||||
|
|
||||||
|
export const useContractsMetadata = (
|
||||||
|
addresses: ChecksummedAddress[],
|
||||||
|
provider: JsonRpcProvider | undefined,
|
||||||
|
baseMetadatas?: Record<string, Metadata | null>
|
||||||
|
) => {
|
||||||
|
const deduped = useDedupedAddresses(addresses);
|
||||||
|
const contracts = useAddressesWithCode(provider, deduped);
|
||||||
|
const { sourcifySource } = useAppConfigContext();
|
||||||
|
const metadatas = useMultipleMetadata(
|
||||||
|
baseMetadatas,
|
||||||
|
contracts,
|
||||||
|
provider?.network.chainId,
|
||||||
|
sourcifySource
|
||||||
|
);
|
||||||
|
|
||||||
|
return metadatas;
|
||||||
|
};
|
|
@ -1,3 +1,3 @@
|
||||||
export const MIN_API_LEVEL = 3;
|
export const MIN_API_LEVEL = 4;
|
||||||
|
|
||||||
export const PAGE_SIZE = 25;
|
export const PAGE_SIZE = 25;
|
||||||
|
|
|
@ -131,51 +131,55 @@ export const useSingleMetadata = (
|
||||||
return address !== undefined ? metadatas[address] : undefined;
|
return address !== undefined ? metadatas[address] : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useDedupedAddresses = (
|
||||||
|
addresses: ChecksummedAddress[]
|
||||||
|
): ChecksummedAddress[] => {
|
||||||
|
return useMemo(() => {
|
||||||
|
const deduped = new Set(addresses);
|
||||||
|
return [...deduped];
|
||||||
|
}, [addresses]);
|
||||||
|
};
|
||||||
|
|
||||||
export const useMultipleMetadata = (
|
export const useMultipleMetadata = (
|
||||||
baseMetadatas: Record<string, Metadata | null> | undefined,
|
baseMetadatas: Record<string, Metadata | null> | undefined,
|
||||||
addresses: (ChecksummedAddress | undefined)[],
|
addresses: ChecksummedAddress[] | undefined,
|
||||||
chainId: number | undefined,
|
chainId: number | undefined,
|
||||||
source: SourcifySource
|
source: SourcifySource
|
||||||
): Record<ChecksummedAddress, Metadata | null | undefined> => {
|
): Record<ChecksummedAddress, Metadata | null | undefined> => {
|
||||||
const [rawMetadata, setRawMetadata] = useState<
|
const [rawMetadata, setRawMetadata] = useState<
|
||||||
Record<string, Metadata | null | undefined>
|
Record<string, Metadata | null | undefined>
|
||||||
>({});
|
>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!addresses || chainId === undefined) {
|
if (addresses === undefined || chainId === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setRawMetadata({});
|
setRawMetadata({});
|
||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const fetchMetadata = async (dedupedAddresses: string[]) => {
|
const fetchMetadata = async (_addresses: string[]) => {
|
||||||
const promises: Promise<Metadata | null>[] = [];
|
const fetchers: Promise<Metadata | null>[] = [];
|
||||||
for (const address of dedupedAddresses) {
|
for (const address of _addresses) {
|
||||||
promises.push(
|
fetchers.push(
|
||||||
fetchSourcifyMetadata(address, chainId, source, abortController)
|
fetchSourcifyMetadata(address, chainId, source, abortController)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await Promise.all(promises);
|
const results = await Promise.all(fetchers);
|
||||||
if (abortController.signal.aborted) {
|
if (abortController.signal.aborted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metadatas: Record<string, Metadata | null> = baseMetadatas
|
let metadatas: Record<string, Metadata | null> = {};
|
||||||
? { ...baseMetadatas }
|
if (baseMetadatas) {
|
||||||
: {};
|
metadatas = { ...baseMetadatas };
|
||||||
|
}
|
||||||
for (let i = 0; i < results.length; i++) {
|
for (let i = 0; i < results.length; i++) {
|
||||||
metadatas[dedupedAddresses[i]] = results[i];
|
metadatas[_addresses[i]] = results[i];
|
||||||
}
|
}
|
||||||
setRawMetadata(metadatas);
|
setRawMetadata(metadatas);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deduped = new Set(
|
const filtered = addresses.filter((a) => baseMetadatas?.[a] === undefined);
|
||||||
addresses.filter(
|
fetchMetadata(filtered);
|
||||||
(a): a is ChecksummedAddress =>
|
|
||||||
a !== undefined && baseMetadatas?.[a] === undefined
|
|
||||||
)
|
|
||||||
);
|
|
||||||
fetchMetadata(Array.from(deduped));
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
abortController.abort();
|
abortController.abort();
|
||||||
|
|
|
@ -37,10 +37,10 @@ import {
|
||||||
use4Bytes,
|
use4Bytes,
|
||||||
useTransactionDescription,
|
useTransactionDescription,
|
||||||
} from "../use4Bytes";
|
} from "../use4Bytes";
|
||||||
import { DevDoc, useMultipleMetadata, UserDoc } from "../sourcify/useSourcify";
|
import { DevDoc, UserDoc } from "../sourcify/useSourcify";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
import { RuntimeContext } from "../useRuntime";
|
import { RuntimeContext } from "../useRuntime";
|
||||||
import { useAppConfigContext } from "../useAppConfig";
|
import { useContractsMetadata } from "../hooks";
|
||||||
|
|
||||||
type DetailsProps = {
|
type DetailsProps = {
|
||||||
txData: TransactionData;
|
txData: TransactionData;
|
||||||
|
@ -95,13 +95,7 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
}
|
}
|
||||||
return _addresses;
|
return _addresses;
|
||||||
}, [txData]);
|
}, [txData]);
|
||||||
const { sourcifySource } = useAppConfigContext();
|
const metadatas = useContractsMetadata(addresses, provider);
|
||||||
const metadatas = useMultipleMetadata(
|
|
||||||
undefined,
|
|
||||||
addresses,
|
|
||||||
provider?.network.chainId,
|
|
||||||
sourcifySource
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentFrame tabs>
|
<ContentFrame tabs>
|
||||||
|
|
|
@ -3,10 +3,10 @@ import { Interface } from "@ethersproject/abi";
|
||||||
import ContentFrame from "../ContentFrame";
|
import ContentFrame from "../ContentFrame";
|
||||||
import LogEntry from "./LogEntry";
|
import LogEntry from "./LogEntry";
|
||||||
import { TransactionData } from "../types";
|
import { TransactionData } from "../types";
|
||||||
import { useAppConfigContext } from "../useAppConfig";
|
import { Metadata } from "../sourcify/useSourcify";
|
||||||
import { Metadata, useMultipleMetadata } from "../sourcify/useSourcify";
|
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
import { RuntimeContext } from "../useRuntime";
|
import { RuntimeContext } from "../useRuntime";
|
||||||
|
import { useContractsMetadata } from "../hooks";
|
||||||
|
|
||||||
type LogsProps = {
|
type LogsProps = {
|
||||||
txData: TransactionData;
|
txData: TransactionData;
|
||||||
|
@ -30,13 +30,8 @@ const Logs: React.FC<LogsProps> = ({ txData, metadata, resolvedAddresses }) => {
|
||||||
[txData]
|
[txData]
|
||||||
);
|
);
|
||||||
const { provider } = useContext(RuntimeContext);
|
const { provider } = useContext(RuntimeContext);
|
||||||
const { sourcifySource } = useAppConfigContext();
|
const metadatas = useContractsMetadata(logAddresses, provider, baseMetadatas);
|
||||||
const metadatas = useMultipleMetadata(
|
|
||||||
baseMetadatas,
|
|
||||||
logAddresses,
|
|
||||||
provider?.network.chainId,
|
|
||||||
sourcifySource
|
|
||||||
);
|
|
||||||
const logDescs = useMemo(() => {
|
const logDescs = useMemo(() => {
|
||||||
if (!txData) {
|
if (!txData) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
InternalOperation,
|
InternalOperation,
|
||||||
ProcessedTransaction,
|
ProcessedTransaction,
|
||||||
OperationType,
|
OperationType,
|
||||||
|
ChecksummedAddress,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import erc20 from "./erc20.json";
|
import erc20 from "./erc20.json";
|
||||||
|
|
||||||
|
@ -440,3 +441,39 @@ export const useUniqueSignatures = (traces: TraceGroup[] | undefined) => {
|
||||||
|
|
||||||
return uniqueSignatures;
|
return uniqueSignatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasCode = async (
|
||||||
|
provider: JsonRpcProvider,
|
||||||
|
address: ChecksummedAddress
|
||||||
|
): Promise<boolean> => {
|
||||||
|
const result = await provider.send("ots_hasCode", [address, "latest"]);
|
||||||
|
return result as boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAddressesWithCode = (
|
||||||
|
provider: JsonRpcProvider | undefined,
|
||||||
|
addresses: ChecksummedAddress[]
|
||||||
|
): ChecksummedAddress[] | undefined => {
|
||||||
|
const [results, setResults] = useState<ChecksummedAddress[] | undefined>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (provider === undefined) {
|
||||||
|
setResults(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const readCodes = async () => {
|
||||||
|
const checkers: Promise<boolean>[] = [];
|
||||||
|
for (const a of addresses) {
|
||||||
|
checkers.push(hasCode(provider, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await Promise.all(checkers);
|
||||||
|
const filtered = addresses.filter((_, i) => result[i]);
|
||||||
|
setResults(filtered);
|
||||||
|
};
|
||||||
|
readCodes();
|
||||||
|
}, [provider, addresses]);
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue