1+ import type { Address } from 'viem' ;
2+
3+ // Define the type for the contract object wagmi uses
4+ export type ContractConfig = {
5+ name : string ;
6+ address : Address ;
7+ chainId : number ;
8+ isProxy ?: boolean ;
9+ } ;
10+
11+ interface FilfoxProxyResponse {
12+ proxyImpl : string | null ;
13+ abi : string | null ;
14+ }
15+
16+ // Unified ABI fetcher: routes to proxy or direct ABI fetch logic based on contract type.
17+ // If the contract is a proxy (isProxy=true), fetches the implementation ABI; otherwise, fetches the contract's own ABI.
18+ export async function fetchContractAbi ( contract : ContractConfig ) : Promise < { body : string } > {
19+ if ( contract . isProxy ) {
20+ return fetchProxyAbi ( contract ) ;
21+ } else {
22+ return fetchDirectAbi ( contract ) ;
23+ }
24+ }
25+
26+ /**
27+ * Fetches the ABI for contract's implementation from Filfox.
28+ * @param contract The contract configuration from wagmi.
29+ * @returns A promise resolving to the ABI content for wagmi.
30+ */
31+ async function fetchDirectAbi ( contract : ContractConfig ) : Promise < { body : string } > {
32+ return fetchAbiFromAddress ( contract . address , contract . name , contract . chainId ) ;
33+ }
34+
35+ /**
36+ * Fetches the ABI for a proxy contract's implementation from Filfox.
37+ * @param contract The contract configuration from wagmi.
38+ * @returns A promise resolving to the ABI content for wagmi.
39+ */
40+ async function fetchProxyAbi ( contract : ContractConfig ) : Promise < { body : string } > {
41+ // 1. Fetch the implementation address from the proxy contract.
42+ const proxyUrl = `https://filfox.info/api/v1/address/${ contract . address } /contract` ;
43+ const proxyResponse = await fetch ( proxyUrl , {
44+ headers : { 'Accept' : 'application/json' } ,
45+ } ) ;
46+ if ( ! proxyResponse . ok ) {
47+ throw new Error (
48+ `Failed to fetch data for proxy contract. Status: ${ proxyResponse . status } ` ,
49+ ) ;
50+ }
51+ const proxyData = await proxyResponse . json ( ) as FilfoxProxyResponse ;
52+ const implementationAddress = proxyData ?. proxyImpl ;
53+ if ( ! implementationAddress || implementationAddress === "null" ) {
54+ throw new Error (
55+ `Could not find implementation address ('proxyImpl') in API response for ${ contract . name } .` ,
56+ ) ;
57+ }
58+
59+ // 2. Fetch the ABI from the implementation contract using the helper
60+ return fetchAbiFromAddress ( implementationAddress as Address , contract . name , contract . chainId ) ;
61+ }
62+
63+ // Internal helper to fetch and parse ABI from Filfox for a given address
64+ async function fetchAbiFromAddress ( address : Address , name : string , chainId : number ) : Promise < { body : string } > {
65+ try {
66+ const url = `https://filfox.info/api/v1/address/${ address } /contract` ;
67+ const response = await fetch ( url , {
68+ headers : { 'Accept' : 'application/json' } ,
69+ } ) ;
70+ if ( ! response . ok ) {
71+ throw new Error (
72+ `Failed to fetch data for contract. Status: ${ response . status } ` ,
73+ ) ;
74+ }
75+ const data = await response . json ( ) as FilfoxProxyResponse ;
76+ const abiString = data ?. abi ;
77+ if ( typeof abiString !== 'string' || abiString . length === 0 ) {
78+ throw new Error (
79+ `Failed to parse ABI. The '.abi' field may be missing, null, or not a valid string.`
80+ ) ;
81+ }
82+ const abi = JSON . parse ( abiString ) ;
83+ console . log ( `Successfully fetched ABI for ${ name } .` ) ;
84+ return {
85+ body : JSON . stringify ( abi , null , 2 ) ,
86+ } ;
87+ } catch ( error ) {
88+ console . error (
89+ `Failed to fetch ABI for ${ name } on chain ${ chainId } :` ,
90+ error ,
91+ ) ;
92+ throw error ;
93+ }
94+ }
0 commit comments