From 6b2d3278504ee2c06420afbe1295d33dc1852e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= <4456749@users.noreply.github.com> Date: Wed, 13 Mar 2024 12:30:08 +0100 Subject: [PATCH] Adding cache support for ABI fetching --- components/actions/action.tsx | 2 +- components/input/function-call-form.tsx | 3 +- hooks/useAbi.ts | 108 +++++++++++++----------- hooks/useMetadata.ts | 6 +- utils/types.ts | 8 ++ 5 files changed, 72 insertions(+), 55 deletions(-) diff --git a/components/actions/action.tsx b/components/actions/action.tsx index ac4b8fdc..3165b26d 100644 --- a/components/actions/action.tsx +++ b/components/actions/action.tsx @@ -68,7 +68,7 @@ export const ActionCard = function ({ action, idx }: ActionCardProps) {
-

Contract call

+

Contract

{action.to}

diff --git a/components/input/function-call-form.tsx b/components/input/function-call-form.tsx index 2c82d626..e0b96c43 100644 --- a/components/input/function-call-form.tsx +++ b/components/input/function-call-form.tsx @@ -23,6 +23,7 @@ export const FunctionCallForm: FC = ({ value, data, }); + setTargetContract(""); }; return ( @@ -47,7 +48,7 @@ export const FunctionCallForm: FC = ({
-

Enter the address of the contract to interact with

+

Enter the address of the contract to call in a new action

{ const { addAlert } = useAlertContext(); const publicClient = usePublicClient({ chainId: PUB_CHAIN.id }); - const [abi, setAbi] = useState(); - const [isLoading, setIsLoading] = useState(false); - useEffect(() => { - if (!publicClient) return; - else if (!isAddress(contractAddress)) return; + const { + data: abi, + isLoading, + error, + } = useQuery({ + queryKey: [contractAddress || "", !!publicClient], + queryFn: () => { + if (!contractAddress || !isAddress(contractAddress) || !publicClient) { + return Promise.resolve([]); + } - setIsLoading(true); - const abiLoader = new whatsabi.loaders.EtherscanABILoader({ - apiKey: PUB_ETHERSCAN_API_KEY, - }); + const abiLoader = new whatsabi.loaders.EtherscanABILoader({ + apiKey: PUB_ETHERSCAN_API_KEY, + }); - whatsabi - .autoload(contractAddress!, { - provider: publicClient, - abiLoader, - followProxies: true, - enableExperimentalMetadata: true, - }) - .then(({ abi }) => { - const functionItems: AbiFunction[] = []; - for (const item of abi) { - if (item.type === "event") continue; + return whatsabi + .autoload(contractAddress!, { + provider: publicClient, + abiLoader, + followProxies: true, + enableExperimentalMetadata: true, + }) + .then(({ abi }) => { + const functionItems: AbiFunction[] = []; + for (const item of abi) { + if (item.type === "event") continue; - functionItems.push({ - name: (item as any).name ?? "(function)", - inputs: item.inputs ?? [], - outputs: item.outputs ?? [], - stateMutability: item.stateMutability ?? "payable", - type: item.type, - }); - } - functionItems.sort((a, b) => { - if ( - ["pure", "view"].includes(a.stateMutability) && - ["pure", "view"].includes(b.stateMutability) - ) { + functionItems.push({ + name: (item as any).name ?? "(function)", + inputs: item.inputs ?? [], + outputs: item.outputs ?? [], + stateMutability: item.stateMutability ?? "payable", + type: item.type, + }); + } + functionItems.sort((a, b) => { + if ( + ["pure", "view"].includes(a.stateMutability) && + ["pure", "view"].includes(b.stateMutability) + ) { + return 0; + } else if (["pure", "view"].includes(a.stateMutability)) return 1; + else if (["pure", "view"].includes(b.stateMutability)) return -1; return 0; - } else if (["pure", "view"].includes(a.stateMutability)) return 1; - else if (["pure", "view"].includes(b.stateMutability)) return -1; - return 0; - }); - setAbi(functionItems); - setIsLoading(false); - }) - .catch((err) => { - console.error(err); - setIsLoading(false); - addAlert("Cannot fetch", { - description: "The details of the contract could not be fetched", - type: "error", + }); + return functionItems; + }) + .catch((err) => { + console.error(err); + addAlert("Cannot fetch", { + description: "The details of the contract could not be fetched", + type: "error", + }); + throw err; }); - }); - }, [contractAddress]); + }, + retry: 4, + refetchOnMount: false, + refetchOnReconnect: false, + retryOnMount: true, + staleTime: Infinity, + }); return { abi: abi ?? [], isLoading, + error, }; }; diff --git a/hooks/useMetadata.ts b/hooks/useMetadata.ts index dfb1e546..ee6351cb 100644 --- a/hooks/useMetadata.ts +++ b/hooks/useMetadata.ts @@ -1,11 +1,9 @@ import { fetchJsonFromIpfs } from "@/utils/ipfs"; +import { JsonValue } from "@/utils/types"; import { useQuery } from "@tanstack/react-query"; import { fromHex } from "viem"; -type JsonValue = string | number | boolean; -type JsonObject = JsonValue | Record | Array; - -export function useMetadata(ipfsUri?: string) { +export function useMetadata(ipfsUri?: string) { const { data, isLoading, isSuccess, error } = useQuery({ queryKey: [ipfsUri || ""], queryFn: () => { diff --git a/utils/types.ts b/utils/types.ts index c57bf243..848d4b9e 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -12,3 +12,11 @@ export interface IAlert { explorerLink?: string; dismissTimeout?: ReturnType; } + +// General types + +type JsonLiteral = string | number | boolean; +export type JsonValue = + | JsonLiteral + | Record + | Array;