Skip to content

Commit 0038c99

Browse files
update home page
1 parent 37f10ef commit 0038c99

File tree

3 files changed

+73
-69
lines changed

3 files changed

+73
-69
lines changed

packages/nextjs/hooks/useFetchContractAbi.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
import { useState } from "react";
22
import { useQuery } from "@tanstack/react-query";
3-
import { fetchContractABIFromAnyABI, fetchContractABIFromEtherscan } from "~~/utils/abi";
3+
import { isAddress } from "viem";
4+
import { UsePublicClientReturnType } from "wagmi";
5+
import { fetchContractABIFromAnyABI, fetchContractABIFromEtherscan, parseAndCorrectJSON } from "~~/utils/abi";
46
import { detectProxyTarget } from "~~/utils/abi-ninja/proxyContracts";
57

68
const ANYABI_TIMEOUT = 3000;
79

8-
const useFetchContractAbi = (contractAddress: string, parsedNetworkId: number, publicClient: any) => {
10+
type FetchContractAbiParams = {
11+
contractAddress: string;
12+
chainId: number;
13+
publicClient: UsePublicClientReturnType;
14+
};
15+
16+
const useFetchContractAbi = ({ contractAddress, chainId, publicClient }: FetchContractAbiParams) => {
917
const [implementationAddress, setImplementationAddress] = useState<string | null>(null);
1018

1119
const fetchAbi = async () => {
20+
if (!isAddress(contractAddress)) {
21+
throw new Error("Invalid contract address");
22+
}
23+
1224
try {
1325
const implAddress = await detectProxyTarget(contractAddress, publicClient);
1426
if (implAddress) {
@@ -23,7 +35,7 @@ const useFetchContractAbi = (contractAddress: string, parsedNetworkId: number, p
2335
});
2436

2537
// Race between the AnyABI fetch and the timeout
26-
const abi = await Promise.race([fetchContractABIFromAnyABI(addressToUse, parsedNetworkId), timeoutPromise]);
38+
const abi = await Promise.race([fetchContractABIFromAnyABI(addressToUse, chainId), timeoutPromise]);
2739

2840
if (!abi) throw new Error("Got empty or undefined ABI from AnyABI");
2941

@@ -32,15 +44,16 @@ const useFetchContractAbi = (contractAddress: string, parsedNetworkId: number, p
3244
console.error("Error or timeout fetching ABI from AnyABI: ", error);
3345
console.log("Falling back to Etherscan...");
3446

35-
const abiString = await fetchContractABIFromEtherscan(contractAddress, parsedNetworkId);
36-
const parsedAbi = JSON.parse(abiString);
47+
const abiString = await fetchContractABIFromEtherscan(contractAddress, chainId);
48+
const parsedAbi = parseAndCorrectJSON(abiString);
3749
return { abi: parsedAbi, address: contractAddress };
3850
}
3951
};
4052

4153
const { data, error, isLoading } = useQuery({
42-
queryKey: ["contractAbi", { contractAddress, chainId: parsedNetworkId }],
54+
queryKey: ["contractAbi", { contractAddress, chainId: chainId }],
4355
queryFn: fetchAbi,
56+
enabled: isAddress(contractAddress) && chainId !== 31337,
4457
});
4558

4659
return {

packages/nextjs/pages/[contractAddress]/[network].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const ContractDetailPage = ({ addressFromUrl, chainIdFromUrl }: ServerSideProps)
8686
error: fetchError,
8787
isLoading,
8888
implementationAddress,
89-
} = useFetchContractAbi(contractAddress, parseInt(network), publicClient);
89+
} = useFetchContractAbi({ contractAddress, chainId: parseInt(network), publicClient });
9090

9191
const effectiveContractData = isUseLocalAbi && contractData ? contractData : fetchedContractData;
9292

packages/nextjs/pages/index.tsx

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from "react";
1+
import { useCallback, useEffect, useState } from "react";
22
import Image from "next/image";
33
import Link from "next/link";
44
import { useRouter } from "next/router";
@@ -12,9 +12,9 @@ import { MiniFooter } from "~~/components/MiniFooter";
1212
import { NetworksDropdown } from "~~/components/NetworksDropdown/NetworksDropdown";
1313
import { SwitchTheme } from "~~/components/SwitchTheme";
1414
import { AddressInput } from "~~/components/scaffold-eth";
15+
import useFetchContractAbi from "~~/hooks/useFetchContractAbi";
1516
import { useAbiNinjaState } from "~~/services/store/store";
16-
import { fetchContractABIFromAnyABI, fetchContractABIFromEtherscan, parseAndCorrectJSON } from "~~/utils/abi";
17-
import { detectProxyTarget } from "~~/utils/abi-ninja/proxyContracts";
17+
import { parseAndCorrectJSON } from "~~/utils/abi";
1818
import { notification } from "~~/utils/scaffold-eth";
1919

2020
enum TabName {
@@ -30,7 +30,6 @@ const Home: NextPage = () => {
3030
const [verifiedContractAddress, setVerifiedContractAddress] = useState("");
3131
const [localAbiContractAddress, setLocalAbiContractAddress] = useState("");
3232
const [localContractAbi, setLocalContractAbi] = useState("");
33-
const [isFetchingAbi, setIsFetchingAbi] = useState(false);
3433

3534
const publicClient = usePublicClient({
3635
chainId: parseInt(network),
@@ -42,66 +41,64 @@ const Home: NextPage = () => {
4241
setImplementationAddress: state.setImplementationAddress,
4342
}));
4443

45-
const [isAbiAvailable, setIsAbiAvailable] = useState(false);
46-
4744
const router = useRouter();
4845

49-
useEffect(() => {
50-
const fetchContractAbi = async () => {
51-
setIsFetchingAbi(true);
52-
try {
53-
const implementationAddress = await detectProxyTarget(verifiedContractAddress as Address, publicClient);
54-
55-
if (implementationAddress) {
56-
setImplementationAddress(implementationAddress);
57-
}
58-
const abi = await fetchContractABIFromAnyABI(
59-
implementationAddress || verifiedContractAddress,
60-
parseInt(network),
61-
);
62-
if (!abi) throw new Error("Got empty or undefined ABI from AnyABI");
63-
setContractAbi(abi);
64-
setIsAbiAvailable(true);
65-
} catch (error) {
66-
console.error("Error fetching ABI from AnyABI: ", error);
67-
console.log("Trying to fetch ABI from Etherscan...");
68-
try {
69-
const abiString = await fetchContractABIFromEtherscan(verifiedContractAddress, parseInt(network));
70-
const abi = JSON.parse(abiString);
71-
setContractAbi(abi);
72-
setIsAbiAvailable(true);
73-
} catch (etherscanError: any) {
74-
setIsAbiAvailable(false);
75-
console.error("Error fetching ABI from Etherscan: ", etherscanError);
46+
const {
47+
contractData,
48+
error,
49+
isLoading: isFetchingAbi,
50+
implementationAddress,
51+
} = useFetchContractAbi({ contractAddress: verifiedContractAddress, chainId: parseInt(network), publicClient });
7652

77-
const bytecode = await publicClient?.getBytecode({
78-
address: verifiedContractAddress as Address,
79-
});
80-
const isContract = Boolean(bytecode) && bytecode !== "0x";
53+
const isAbiAvailable = contractData?.abi && contractData.abi.length > 0;
8154

82-
if (isContract) {
83-
setLocalAbiContractAddress(verifiedContractAddress);
84-
setActiveTab(TabName.addressAbi);
85-
} else {
86-
notification.error("Address is not a contract, are you sure you are on the correct chain?");
87-
}
88-
}
89-
} finally {
90-
setIsFetchingAbi(false);
91-
}
92-
};
55+
const handleFetchError = useCallback(async () => {
56+
try {
57+
const bytecode = await publicClient?.getBytecode({
58+
address: verifiedContractAddress as Address,
59+
});
60+
const isContract = Boolean(bytecode) && bytecode !== "0x";
9361

94-
if (isAddress(verifiedContractAddress)) {
95-
if (network === "31337") {
96-
setActiveTab(TabName.addressAbi);
62+
if (isContract) {
9763
setLocalAbiContractAddress(verifiedContractAddress);
98-
return;
64+
setActiveTab(TabName.addressAbi);
65+
} else {
66+
notification.error("Address is not a contract, are you sure you are on the correct chain?");
9967
}
100-
fetchContractAbi();
101-
} else {
102-
setIsAbiAvailable(false);
68+
} catch (error) {
69+
console.error("Error checking if address is a contract:", error);
70+
notification.error("Error checking if address is a contract. Please try again.");
71+
}
72+
}, [publicClient, verifiedContractAddress, setLocalAbiContractAddress, setActiveTab]);
73+
74+
useEffect(() => {
75+
if (implementationAddress) {
76+
setImplementationAddress(implementationAddress);
77+
}
78+
79+
if (contractData?.abi) {
80+
setContractAbi(contractData.abi);
81+
}
82+
83+
if (network === "31337") {
84+
setActiveTab(TabName.addressAbi);
85+
setLocalAbiContractAddress(verifiedContractAddress);
86+
return;
87+
}
88+
89+
if (error && isAddress(verifiedContractAddress)) {
90+
handleFetchError();
10391
}
104-
}, [verifiedContractAddress, network, setContractAbi, publicClient, setImplementationAddress]);
92+
}, [
93+
contractData,
94+
error,
95+
implementationAddress,
96+
network,
97+
verifiedContractAddress,
98+
handleFetchError,
99+
setContractAbi,
100+
setImplementationAddress,
101+
]);
105102

106103
useEffect(() => {
107104
if (router.pathname === "/") {
@@ -132,7 +129,6 @@ const Home: NextPage = () => {
132129
};
133130

134131
const fetchAbiFromHeimdall = async (contractAddress: Address) => {
135-
setIsFetchingAbi(true);
136132
try {
137133
const rpcUrlWithoutHttps = publicClient?.chain.rpcUrls.default.http[0].substring(8);
138134
const response = await fetch(
@@ -141,19 +137,14 @@ const Home: NextPage = () => {
141137
const abi = await response.json();
142138
if (abi.length === 0) {
143139
notification.error("Failed to fetch ABI from Heimdall. Please try again or enter ABI manually.");
144-
setIsFetchingAbi(false);
145140
return;
146141
}
147142
setContractAbi(abi);
148-
setIsAbiAvailable(true);
149143
setAbiContractAddress(contractAddress);
150144
router.push(`/${contractAddress}/${network}`);
151145
} catch (error) {
152146
console.error("Error fetching ABI from Heimdall: ", error);
153147
notification.error("Failed to fetch ABI from Heimdall. Please try again or enter ABI manually.");
154-
setIsAbiAvailable(false);
155-
} finally {
156-
setIsFetchingAbi(false);
157148
}
158149
};
159150

0 commit comments

Comments
 (0)