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 LogEntry from "./LogEntry";
import { TransactionData } from "../types";
import { Metadata } from "../useSourcify";
import { Metadata, useMultipleMetadata } from "../useSourcify";
import { SourcifySource } from "../url";
type LogsProps = {
txData: TransactionData;
@ -11,22 +12,45 @@ type LogsProps = {
};
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(() => {
if (!metadata || !txData) {
return undefined;
}
const abi = metadata.output.abi;
const intf = new Interface(abi as any);
return txData.confirmedData?.logs.map((l) =>
l.address === txData.to
? intf.parseLog({
topics: l.topics,
data: l.data,
})
: undefined
);
}, [metadata, txData]);
return txData.confirmedData?.logs.map((l) => {
const mt = metadatas[l.address];
if (!mt) {
return undefined;
}
const abi = mt.output.abi;
const intf = new Interface(abi as any);
return intf.parseLog({
topics: l.topics,
data: l.data,
});
});
}, [metadatas, metadata, txData]);
return (
<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 = (
checksummedAddress: string | undefined,
chainId: number | undefined,
source: SourcifySource
) => {
): Metadata | null | undefined => {
const [rawMetadata, setRawMetadata] = useState<Metadata | null | undefined>();
useEffect(() => {
@ -53,25 +80,13 @@ export const useSourcify = (
const abortController = new AbortController();
const fetchMetadata = async () => {
try {
const contractMetadataURL = sourcifyMetadata(
checksummedAddress,
chainId,
source
);
const result = await fetch(contractMetadataURL, {
signal: abortController.signal,
});
if (result.ok) {
const _metadata = await result.json();
setRawMetadata(_metadata);
} else {
setRawMetadata(null);
}
} catch (err) {
console.error(err);
setRawMetadata(null);
}
const _metadata = await fetchSourcifyMetadata(
checksummedAddress,
chainId,
source,
abortController
);
setRawMetadata(_metadata);
};
fetchMetadata();
@ -83,6 +98,54 @@ export const useSourcify = (
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 = (
checksummedAddress: string,
networkId: number,