Replace useMultipleMetadata by SWR

This commit is contained in:
Willian Mitsuda 2022-08-09 21:39:31 -03:00
parent 17d44433ca
commit a2c2403d05
No known key found for this signature in database
6 changed files with 56 additions and 168 deletions

View File

@ -23,7 +23,7 @@ import Contracts from "./address/Contracts";
import { RuntimeContext } from "./useRuntime";
import { useAppConfigContext } from "./useAppConfig";
import { useAddressOrENS } from "./useResolvedAddresses";
import { useMultipleMetadata } from "./sourcify/useSourcify";
import { useSourcifyMetadata } from "./sourcify/useSourcify";
import { ChecksummedAddress } from "./types";
import { useAddressesWithCode } from "./useErigonHooks";
import { useChainInfo } from "./useChainInfo";
@ -65,7 +65,6 @@ const Address: React.FC = () => {
}
}, [addressOrName, checksummedAddress, isENS]);
const { sourcifySource } = useAppConfigContext();
const checksummedAddressAsArray = useMemo(
() => (checksummedAddress !== undefined ? [checksummedAddress] : []),
[checksummedAddress]
@ -74,16 +73,13 @@ const Address: React.FC = () => {
provider,
checksummedAddressAsArray
);
const metadatas = useMultipleMetadata(
undefined,
contractAddresses,
// TODO: restore filter to only check Sourcify metadata if the address is a contract (hasCode)
const { sourcifySource } = useAppConfigContext();
const addressMetadata = useSourcifyMetadata(
checksummedAddress,
provider?.network.chainId,
sourcifySource
);
const addressMetadata =
checksummedAddress !== undefined
? metadatas[checksummedAddress]
: undefined;
const { network, faucets } = useChainInfo();

View File

@ -98,10 +98,7 @@ const TransactionPageContent: React.FC<TransactionPageContentProps> = ({
/>
}
/>
<Route
path="logs"
element={<Logs txData={txData} metadata={metadata} />}
/>
<Route path="logs" element={<Logs txData={txData} />} />
<Route path="trace" element={<Trace txData={txData} />} />
</Routes>
</React.Suspense>

View File

@ -1,33 +0,0 @@
import { useMemo } from "react";
import { JsonRpcProvider } from "@ethersproject/providers";
import { ChecksummedAddress } from "./types";
import { Metadata, useMultipleMetadata } from "./sourcify/useSourcify";
import { useAppConfigContext } from "./useAppConfig";
import { useAddressesWithCode } from "./useErigonHooks";
const useDedupedAddresses = (
addresses: ChecksummedAddress[]
): ChecksummedAddress[] => {
return useMemo(() => {
const deduped = new Set(addresses);
return [...deduped];
}, [addresses]);
};
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

@ -121,55 +121,6 @@ export const useSourcifyMetadata = (
return data;
};
export const useMultipleMetadata = (
baseMetadatas: Record<string, Metadata | null> | undefined,
addresses: ChecksummedAddress[] | undefined,
chainId: number | undefined,
source: SourcifySource
): Record<ChecksummedAddress, Metadata | null | undefined> => {
const [rawMetadata, setRawMetadata] = useState<
Record<string, Metadata | null | undefined>
>({});
useEffect(() => {
if (addresses === undefined || chainId === undefined) {
return;
}
setRawMetadata({});
const abortController = new AbortController();
const fetchMetadata = async (_addresses: string[]) => {
const fetchers: Promise<Metadata | null>[] = [];
for (const address of _addresses) {
fetchers.push(
fetchSourcifyMetadata(address, chainId, source, abortController)
);
}
const results = await Promise.all(fetchers);
if (abortController.signal.aborted) {
return;
}
let metadatas: Record<string, Metadata | null> = {};
if (baseMetadatas) {
metadatas = { ...baseMetadatas };
}
for (let i = 0; i < results.length; i++) {
metadatas[_addresses[i]] = results[i];
}
setRawMetadata(metadatas);
};
const filtered = addresses.filter((a) => baseMetadatas?.[a] === undefined);
fetchMetadata(filtered);
return () => {
abortController.abort();
};
}, [baseMetadatas, addresses, chainId, source]);
return rawMetadata;
};
export const useContract = (
checksummedAddress: string,
networkId: number,

View File

@ -1,6 +1,6 @@
import React, { useMemo } from "react";
import React, { useContext, useMemo } from "react";
import { Log } from "@ethersproject/abstract-provider";
import { Fragment, Interface, LogDescription } from "@ethersproject/abi";
import { Fragment, Interface } from "@ethersproject/abi";
import { Tab } from "@headlessui/react";
import TransactionAddress from "../components/TransactionAddress";
import Copy from "../components/Copy";
@ -8,15 +8,41 @@ import ModeTab from "../components/ModeTab";
import DecodedParamsTable from "./decoder/DecodedParamsTable";
import DecodedLogSignature from "./decoder/DecodedLogSignature";
import { useTopic0 } from "../useTopic0";
import { ChecksummedAddress } from "../types";
import { Metadata } from "../sourcify/useSourcify";
import { RuntimeContext } from "../useRuntime";
import { useAppConfigContext } from "../useAppConfig";
import { useSourcifyMetadata } from "../sourcify/useSourcify";
type LogEntryProps = {
log: Log;
logDesc: LogDescription | null | undefined;
};
const LogEntry: React.FC<LogEntryProps> = ({ log, logDesc }) => {
const LogEntry: React.FC<LogEntryProps> = ({ log }) => {
const { provider } = useContext(RuntimeContext);
const { sourcifySource } = useAppConfigContext();
const metadata = useSourcifyMetadata(
log.address,
provider?.network.chainId,
sourcifySource
);
const logDesc = useMemo(() => {
if (!metadata) {
return metadata;
}
const abi = metadata.output.abi;
const intf = new Interface(abi as any);
try {
return intf.parseLog({
topics: log.topics,
data: log.data,
});
} catch (err) {
console.warn("Couldn't find function signature", err);
return null;
}
}, [log, metadata]);
const rawTopic0 = log.topics[0];
const topic0 = useTopic0(rawTopic0);

View File

@ -1,77 +1,28 @@
import React, { useContext, useMemo } from "react";
import { Interface } from "@ethersproject/abi";
import React from "react";
import ContentFrame from "../ContentFrame";
import LogEntry from "./LogEntry";
import { TransactionData } from "../types";
import { Metadata } from "../sourcify/useSourcify";
import { RuntimeContext } from "../useRuntime";
import { useContractsMetadata } from "../hooks";
type LogsProps = {
txData: TransactionData;
metadata: Metadata | null | undefined;
};
const Logs: React.FC<LogsProps> = ({ txData, metadata }) => {
const baseMetadatas = useMemo((): Record<string, Metadata | null> => {
if (!txData.to || metadata === undefined) {
return {};
}
const md: Record<string, Metadata | null> = {};
md[txData.to] = metadata;
return md;
}, [txData.to, metadata]);
const logAddresses = useMemo(
() => txData.confirmedData?.logs.map((l) => l.address) ?? [],
[txData]
);
const { provider } = useContext(RuntimeContext);
const metadatas = useContractsMetadata(logAddresses, provider, baseMetadatas);
const logDescs = useMemo(() => {
if (!txData) {
return undefined;
}
return txData.confirmedData?.logs.map((l) => {
const mt = metadatas[l.address];
if (!mt) {
return mt;
}
const abi = mt.output.abi;
const intf = new Interface(abi as any);
try {
return intf.parseLog({
topics: l.topics,
data: l.data,
});
} catch (err) {
console.warn("Couldn't find function signature", err);
return null;
}
});
}, [metadatas, txData]);
return (
<ContentFrame tabs>
{txData.confirmedData && (
<>
{txData.confirmedData.logs.length > 0 ? (
<>
{txData.confirmedData.logs.map((l, i) => (
<LogEntry key={i} log={l} logDesc={logDescs?.[i]} />
))}
</>
) : (
<div className="text-sm py-4">Transaction didn't emit any logs</div>
)}
</>
)}
</ContentFrame>
);
};
const Logs: React.FC<LogsProps> = ({ txData }) => (
<ContentFrame tabs>
{txData.confirmedData && (
<>
{txData.confirmedData.logs.length > 0 ? (
<>
{txData.confirmedData.logs.map((l, i) => (
<LogEntry key={i} log={l} />
))}
</>
) : (
<div className="text-sm py-4">Transaction didn't emit any logs</div>
)}
</>
)}
</ContentFrame>
);
export default React.memo(Logs);