Add support for multiple log emitter addresses

This commit is contained in:
Willian Mitsuda 2021-09-20 18:15:00 -03:00
parent 18275f86a2
commit 7f15a12f4a
2 changed files with 119 additions and 32 deletions

View File

@ -3,7 +3,8 @@ 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 { Metadata } from "../useSourcify"; import { Metadata, useMultipleMetadata } from "../useSourcify";
import { SourcifySource } from "../url";
type LogsProps = { type LogsProps = {
txData: TransactionData; txData: TransactionData;
@ -11,22 +12,45 @@ type LogsProps = {
}; };
const Logs: React.FC<LogsProps> = ({ txData, metadata }) => { 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 metadatas = useMultipleMetadata(
baseMetadatas,
logAddresses,
1,
SourcifySource.CUSTOM_SNAPSHOT_SERVER
);
const logDesc = useMemo(() => { const logDesc = useMemo(() => {
if (!metadata || !txData) { if (!metadata || !txData) {
return undefined; return undefined;
} }
const abi = metadata.output.abi; return txData.confirmedData?.logs.map((l) => {
const intf = new Interface(abi as any); const mt = metadatas[l.address];
return txData.confirmedData?.logs.map((l) => if (!mt) {
l.address === txData.to return undefined;
? intf.parseLog({ }
topics: l.topics,
data: l.data, const abi = mt.output.abi;
}) const intf = new Interface(abi as any);
: undefined return intf.parseLog({
); topics: l.topics,
}, [metadata, txData]); data: l.data,
});
});
}, [metadatas, metadata, txData]);
return ( return (
<ContentFrame tabs> <ContentFrame tabs>

View File

@ -38,11 +38,38 @@ export type Metadata = {
}; };
}; };
export const fetchSourcifyMetadata = async (
checksummedAddress: string,
chainId: number,
source: SourcifySource,
abortController: AbortController
): Promise<Metadata | null> => {
try {
const contractMetadataURL = sourcifyMetadata(
checksummedAddress,
chainId,
source
);
const result = await fetch(contractMetadataURL, {
signal: abortController.signal,
});
if (result.ok) {
const _metadata = await result.json();
return _metadata;
}
return null;
} catch (err) {
console.error(err);
return null;
}
};
export const useSourcify = ( export const useSourcify = (
checksummedAddress: string | undefined, checksummedAddress: string | undefined,
chainId: number | undefined, chainId: number | undefined,
source: SourcifySource source: SourcifySource
) => { ): Metadata | null | undefined => {
const [rawMetadata, setRawMetadata] = useState<Metadata | null | undefined>(); const [rawMetadata, setRawMetadata] = useState<Metadata | null | undefined>();
useEffect(() => { useEffect(() => {
@ -53,25 +80,13 @@ export const useSourcify = (
const abortController = new AbortController(); const abortController = new AbortController();
const fetchMetadata = async () => { const fetchMetadata = async () => {
try { const _metadata = await fetchSourcifyMetadata(
const contractMetadataURL = sourcifyMetadata( checksummedAddress,
checksummedAddress, chainId,
chainId, source,
source abortController
); );
const result = await fetch(contractMetadataURL, { setRawMetadata(_metadata);
signal: abortController.signal,
});
if (result.ok) {
const _metadata = await result.json();
setRawMetadata(_metadata);
} else {
setRawMetadata(null);
}
} catch (err) {
console.error(err);
setRawMetadata(null);
}
}; };
fetchMetadata(); fetchMetadata();
@ -83,6 +98,54 @@ export const useSourcify = (
return rawMetadata; return rawMetadata;
}; };
export const useMultipleMetadata = (
baseMetadatas: Record<string, Metadata | null>,
checksummedAddress: (string | undefined)[],
chainId: number | undefined,
source: SourcifySource
): Record<string, Metadata | null | undefined> => {
const [rawMetadata, setRawMetadata] = useState<
Record<string, Metadata | null | undefined>
>({});
useEffect(() => {
if (!checksummedAddress || chainId === undefined) {
return;
}
setRawMetadata({});
const abortController = new AbortController();
const fetchMetadata = async (addresses: string[]) => {
const promises: Promise<Metadata | null>[] = [];
for (const addr of addresses) {
promises.push(
fetchSourcifyMetadata(addr, chainId, source, abortController)
);
}
const results = await Promise.all(promises);
const metadatas: Record<string, Metadata | null> = { ...baseMetadatas };
for (let i = 0; i < results.length; i++) {
metadatas[addresses[i]] = results[i];
}
setRawMetadata(metadatas);
};
const deduped = new Set(
checksummedAddress.filter(
(a): a is string => a !== undefined && baseMetadatas[a] === undefined
)
);
fetchMetadata(Array.from(deduped));
return () => {
abortController.abort();
};
}, [baseMetadatas, checksummedAddress, chainId, source]);
return rawMetadata;
};
export const useContract = ( export const useContract = (
checksummedAddress: string, checksummedAddress: string,
networkId: number, networkId: number,