@@ -11,12 +11,52 @@ export const fetchContractFromEtherscan = async (plugin, endpoint: string | Netw
11
11
if ( ! etherscanKey ) etherscanKey = '2HKUX5ZVASZIKWJM8MIQVCRUVZ6JAWT531'
12
12
13
13
if ( etherscanKey ) {
14
+ // Extract chain ID and build endpoint string once
15
+ let chainId = 1 // Default to Ethereum mainnet
16
+ let endpointStr : string
14
17
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
16
23
}
17
24
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
+
20
60
// etherscan api doc https://docs.etherscan.io/api-endpoints/contracts
21
61
if ( data . message === 'OK' && data . status === "1" ) {
22
62
if ( data . result . length ) {
0 commit comments