Skip to content

Commit aee5c73

Browse files
Show contract creation information in the Contract Overview card (#180)
1 parent 2c694b7 commit aee5c73

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

packages/nextjs/components/scaffold-eth/Contract/ContractUI.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import { ContractWriteMethods } from "./ContractWriteMethods";
66
import { AbiFunction } from "abitype";
77
import { Abi, Address as AddressType } from "viem";
88
import { useContractRead } from "wagmi";
9+
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline";
910
import { MiniFooter } from "~~/components/MiniFooter";
1011
import { Address, Balance, MethodSelector } from "~~/components/scaffold-eth";
1112
import { useNetworkColor } from "~~/hooks/scaffold-eth";
13+
import useFetchContractCreationInfo from "~~/hooks/useFetchContractCreationInfo";
1214
import { useGlobalState } from "~~/services/store/store";
13-
import { getTargetNetworks } from "~~/utils/scaffold-eth";
15+
import { getBlockExplorerTxLink, getTargetNetworks } from "~~/utils/scaffold-eth";
1416

1517
type ContractUIProps = {
1618
className?: string;
@@ -70,6 +72,11 @@ export const ContractUI = ({ className = "", initialContractData }: ContractUIPr
7072
const router = useRouter();
7173
const { network } = router.query as { network?: string };
7274

75+
const { contractCreationInfo, isLoading: isContractCreationLoading } = useFetchContractCreationInfo({
76+
contractAddress: initialContractData.address,
77+
chainId,
78+
});
79+
7380
const updateUrlWithSelectedMethods = (selectedMethods: string[]) => {
7481
const currentQuery = new URLSearchParams(window.location.search);
7582
if (selectedMethods.length > 0) {
@@ -220,6 +227,28 @@ export const ContractUI = ({ className = "", initialContractData }: ContractUIPr
220227
</span>
221228
</p>
222229
)}
230+
{!isContractCreationLoading && contractCreationInfo && (
231+
<div className="my-0 text-sm flex items-center gap-2">
232+
<span className="font-bold">Created at:</span>
233+
{isContractCreationLoading ? (
234+
<span className="loading loading-spinner loading-xs"></span>
235+
) : (
236+
contractCreationInfo && (
237+
<>
238+
<span>Block {contractCreationInfo.blockNumber}</span>
239+
<a
240+
href={getBlockExplorerTxLink(chainId, contractCreationInfo.txHash)}
241+
target="_blank"
242+
rel="noopener noreferrer"
243+
className="link no-underline"
244+
>
245+
<ArrowTopRightOnSquareIcon className="w-4 h-4" />
246+
</a>
247+
</>
248+
)
249+
)}
250+
</div>
251+
)}
223252
</div>
224253
<div className="bg-base-200 shadow-xl rounded-2xl px-6 py-4">
225254
<span className="block font-bold pb-3">Contract Data</span>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { useQuery } from "@tanstack/react-query";
2+
import { Address } from "viem";
3+
4+
type ContractCreationInfo = {
5+
blockNumber: string;
6+
txHash: string;
7+
};
8+
9+
type UseFetchContractCreationInfoParams = {
10+
contractAddress: Address;
11+
chainId: number;
12+
};
13+
14+
const useFetchContractCreationInfo = ({ contractAddress, chainId }: UseFetchContractCreationInfoParams) => {
15+
const fetchContractCreation = async (): Promise<ContractCreationInfo> => {
16+
const apiKey = process.env.NEXT_PUBLIC_ETHERSCAN_V2_API_KEY;
17+
const response = await fetch(
18+
`https://api.etherscan.io/v2/api?chainid=${chainId}&module=contract&action=getcontractcreation&contractaddresses=${contractAddress}&apikey=${apiKey}`,
19+
);
20+
const data = await response.json();
21+
22+
if (data.status !== "1" || !data.result || data.result.length === 0) {
23+
throw new Error("Failed to fetch contract creation data");
24+
}
25+
26+
const creationInfo = data.result[0];
27+
return {
28+
blockNumber: creationInfo.blockNumber,
29+
txHash: creationInfo.txHash,
30+
};
31+
};
32+
33+
const { data, error, isLoading } = useQuery({
34+
queryKey: ["contractCreationInfo", { contractAddress, chainId }],
35+
queryFn: fetchContractCreation,
36+
enabled: Boolean(contractAddress) && chainId !== 31337,
37+
retry: false,
38+
});
39+
40+
return {
41+
contractCreationInfo: data,
42+
error,
43+
isLoading,
44+
};
45+
};
46+
47+
export default useFetchContractCreationInfo;

0 commit comments

Comments
 (0)