Merge branch 'feature/optimize-detect-contracts' into develop

This commit is contained in:
Willian Mitsuda 2021-12-02 16:29:07 -03:00
commit 9443a91a46
8 changed files with 99 additions and 56 deletions

View File

@ -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>

View File

@ -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>

27
src/hooks.ts Normal file
View File

@ -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;
};

View File

@ -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;

View File

@ -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();

View File

@ -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>

View File

@ -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;

View File

@ -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;
};