@@ -11,12 +11,52 @@ export const fetchContractFromEtherscan = async (plugin, endpoint: string | Netw
1111 if ( ! etherscanKey ) etherscanKey = '2HKUX5ZVASZIKWJM8MIQVCRUVZ6JAWT531'
1212
1313 if ( etherscanKey ) {
14+ // Extract chain ID and build endpoint string once
15+ let chainId = 1 // Default to Ethereum mainnet
16+ let endpointStr : string
1417 if ( typeof endpoint === 'object' && endpoint !== null && 'id' in endpoint && 'name' in endpoint ) {
15- endpoint = endpoint . id == 1 ? 'api.etherscan.io' : 'api-' + endpoint . name + '.etherscan.io'
18+ chainId = endpoint . id
19+ const normalized = String ( endpoint . name || '' ) . toLowerCase ( )
20+ endpointStr = endpoint . id == 1 ? 'api.etherscan.io' : 'api-' + normalized + '.etherscan.io'
21+ } else {
22+ endpointStr = endpoint as string
1623 }
1724 try {
18- data = await fetch ( 'https://' + endpoint + '/api?module=contract&action=getsourcecode&address=' + contractAddress + '&apikey=' + etherscanKey )
19- data = await data . json ( )
25+ // Prefer central V2 API host with chainid param (works across Etherscan-supported networks)
26+ const v2CentralUrl = 'https://api.etherscan.io/v2/api?chainid=' + chainId + '&module=contract&action=getsourcecode&address=' + contractAddress + '&apikey=' + etherscanKey
27+ let response = await fetch ( v2CentralUrl )
28+ const centralV2Status = response . status ;
29+ const centralV2StatusText = response . statusText ;
30+
31+ // If central V2 not OK, try per-network V2, then per-network V1
32+ if ( ! response . ok ) {
33+ const v2PerNetworkUrl = 'https://' + endpointStr + '/v2/api?chainid=' + chainId + '&module=contract&action=getsourcecode&address=' + contractAddress + '&apikey=' + etherscanKey
34+ const v2PerNetworkResponse = await fetch ( v2PerNetworkUrl )
35+ const v2PerNetworkStatus = v2PerNetworkResponse . status ;
36+ const v2PerNetworkStatusText = v2PerNetworkResponse . statusText ;
37+ if ( v2PerNetworkResponse . ok ) {
38+ response = v2PerNetworkResponse ;
39+ } else {
40+ const v1Url = 'https://' + endpointStr + '/api?module=contract&action=getsourcecode&address=' + contractAddress + '&apikey=' + etherscanKey
41+ const v1Response = await fetch ( v1Url )
42+ const v1Status = v1Response . status ;
43+ const v1StatusText = v1Response . statusText ;
44+ if ( v1Response . ok ) {
45+ response = v1Response ;
46+ } else {
47+ // All three endpoints failed, throw a descriptive error
48+ throw new Error (
49+ `All Etherscan API endpoints failed:\n` +
50+ `Central V2: ${ v2CentralUrl } [${ centralV2Status } ${ centralV2StatusText } ]\n` +
51+ `Per-network V2: ${ v2PerNetworkUrl } [${ v2PerNetworkStatus } ${ v2PerNetworkStatusText } ]\n` +
52+ `Per-network V1: ${ v1Url } [${ v1Status } ${ v1StatusText } ]`
53+ ) ;
54+ }
55+ }
56+ }
57+
58+ data = await response . json ( )
59+
2060 // etherscan api doc https://docs.etherscan.io/api-endpoints/contracts
2161 if ( data . message === 'OK' && data . status === "1" ) {
2262 if ( data . result . length ) {
0 commit comments