Skip to content

Commit

Permalink
feat(cli): etherscan api v2 (#4503)
Browse files Browse the repository at this point in the history
* feat(cli): etherscan api v2

* chore: changeset

* chore: up
  • Loading branch information
tmm authored Jan 15, 2025
1 parent 8f22957 commit 8fce8a6
Show file tree
Hide file tree
Showing 8 changed files with 405 additions and 173 deletions.
5 changes: 5 additions & 0 deletions .changeset/eight-squids-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@wagmi/cli": minor
---

Updated Etherscan Plugin to use Etherscan API v2.
13 changes: 10 additions & 3 deletions packages/cli/src/plugins/blockExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export type BlockExplorerConfig = {
* @default 1_800_000 // 30m in ms
*/
cacheDuration?: number | undefined
/**
* Chain ID for block explorer. Appended to the request URL as query param `&chainId=${chainId}`.
*/
chainId?: number | undefined
/**
* Contracts to fetch ABIs for.
*/
Expand Down Expand Up @@ -63,6 +67,7 @@ export function blockExplorer(config: BlockExplorerConfig) {
apiKey,
baseUrl,
cacheDuration,
chainId,
contracts,
getAddress = ({ address }) => {
if (typeof address === 'string') return address
Expand Down Expand Up @@ -91,9 +96,11 @@ export function blockExplorer(config: BlockExplorerConfig) {
request({ address }) {
if (!address) throw new Error('address is required')
return {
url: `${baseUrl}?module=contract&action=getabi&address=${getAddress({
address,
})}${apiKey ? `&apikey=${apiKey}` : ''}`,
url: `${baseUrl}?${chainId ? `chainId=${chainId}&` : ''}module=contract&action=getabi&address=${getAddress(
{
address,
},
)}${apiKey ? `&apikey=${apiKey}` : ''}`,
}
},
})
Expand Down
138 changes: 72 additions & 66 deletions packages/cli/src/plugins/etherscan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,73 +2,11 @@ import type { ContractConfig } from '../config.js'
import type { Compute } from '../types.js'
import { blockExplorer } from './blockExplorer.js'

const apiUrls = {
// Ethereum
[1]: 'https://api.etherscan.io/api',
[5]: 'https://api-goerli.etherscan.io/api',
[17_000]: 'https://api-holesky.etherscan.io/api',
[11_155_111]: 'https://api-sepolia.etherscan.io/api',
// Optimism
[10]: 'https://api-optimistic.etherscan.io/api',
[420]: 'https://api-goerli-optimistic.etherscan.io/api',
[11_155_420]: 'https://api-sepolia-optimistic.etherscan.io/api',
// Base
[84532]: 'https://api-sepolia.basescan.org/api',
[8453]: 'https://api.basescan.org/api',
// Polygon
[137]: 'https://api.polygonscan.com/api',
[80_001]: 'https://api-testnet.polygonscan.com/api',
[80_002]: 'https://api-amoy.polygonscan.com/api',
// Arbitrum
[42_161]: 'https://api.arbiscan.io/api',
[421_613]: 'https://api-goerli.arbiscan.io/api',
[421_614]: 'https://api-sepolia.arbiscan.io/api',
// BNB Smart Chain
[56]: 'https://api.bscscan.com/api',
[97]: 'https://api-testnet.bscscan.com/api',
// Heco Chain
[128]: 'https://api.hecoinfo.com/api',
[256]: 'https://api-testnet.hecoinfo.com/api',
// Sonic
[146]: 'https://api.sonicscan.org/api',
// Fantom
[250]: 'https://api.ftmscan.com/api',
[4_002]: 'https://api-testnet.ftmscan.com/api',
// Avalanche
[43_114]: 'https://api.snowscan.xyz/api',
[43_113]: 'https://api-testnet.snowscan.xyz/api',
// Celo
[42_220]: 'https://api.celoscan.io/api',
[44_787]: 'https://api-alfajores.celoscan.io/api',
// Fraxtal
[252]: 'https://api.fraxscan.com/api',
[2_522]: 'https://api-holesky.fraxscan.com/api',
// Gnosis
[100]: 'https://api.gnosisscan.io/api',
// Blast
[81_457]: 'https://api.blastscan.io/api',
}
type ChainId = keyof typeof apiUrls

export type EtherscanConfig<chainId extends number> = {
/**
* Etherscan API key.
*
* API keys are specific per network and include testnets (e.g. Ethereum Mainnet and Goerli share same API key). Create or manage keys:
* - [__Ethereum__](https://etherscan.io/myapikey)
* - [__Arbitrum__](https://arbiscan.io/myapikey)
* - [__Avalanche__](https://snowscan.xyz/myapikey)
* - [__BNB Smart Chain__](https://bscscan.com/myapikey)
* - [__Base__](https://basescan.org/myapikey)
* - [__Blast__](https://blastscan.io/myapikey)
* - [__Celo__](https://celoscan.io/myapikey)
* - [__Fantom__](https://ftmscan.com/myapikey)
* - [__Fraxtal__](https://fraxscan.com/myapikey)
* - [__Gnosis__](https://gnosisscan.io/myapikey)
* - [__Heco Chain__](https://hecoinfo.com/myapikey)
* - [__Optimism__](https://optimistic.etherscan.io/myapikey)
* - [__Polygon__](https://polygonscan.com/myapikey)
* - [__Sonic__](https://sonicscan.org/myapikey)
* Create or manage keys at https://etherscan.io/myapikey
*/
apiKey: string
/**
Expand All @@ -78,11 +16,13 @@ export type EtherscanConfig<chainId extends number> = {
*/
cacheDuration?: number | undefined
/**
* Chain id to use for fetching ABI.
* Chain ID to use for fetching ABI.
*
* If `address` is an object, `chainId` is used to select the address.
*
* View supported chains on the [Etherscan docs](https://docs.etherscan.io/etherscan-v2/getting-started/supported-chains).
*/
chainId: chainId
chainId: (chainId extends ChainId ? chainId : never) | (ChainId & {})
/**
* Contracts to fetch ABIs for.
*/
Expand All @@ -105,8 +45,9 @@ export function etherscan<chainId extends ChainId>(

return blockExplorer({
apiKey,
baseUrl: apiUrls[chainId as ChainId],
baseUrl: 'https://api.etherscan.io/v2/api',
cacheDuration,
chainId,
contracts,
getAddress({ address }) {
if (!address) throw new Error('address is required')
Expand All @@ -121,3 +62,68 @@ export function etherscan<chainId extends ChainId>(
name: 'Etherscan',
})
}

// Supported chains
// https://docs.etherscan.io/etherscan-v2/getting-started/supported-chains
type ChainId =
| 1 // Ethereum Mainnet
| 11155111 // Sepolia Testnet
| 17000 // Holesky Testnet
| 56 // BNB Smart Chain Mainnet
| 97 // BNB Smart Chain Testnet
| 137 // Polygon Mainnet
| 80002 // Polygon Amoy Testnet
| 1101 // Polygon zkEVM Mainnet
| 2442 // Polygon zkEVM Cardona Testnet
| 8453 // Base Mainnet
| 84532 // Base Sepolia Testnet
| 42161 // Arbitrum One Mainnet
| 42170 // Arbitrum Nova Mainnet
| 421614 // Arbitrum Sepolia Testnet
| 59144 // Linea Mainnet
| 59141 // Linea Sepolia Testnet
| 250 // Fantom Opera Mainnet
| 4002 // Fantom Testnet
| 81457 // Blast Mainnet
| 168587773 // Blast Sepolia Testnet
| 10 // OP Mainnet
| 11155420 // OP Sepolia Testnet
| 43114 // Avalanche C-Chain
| 43113 // Avalanche Fuji Testnet
| 199 // BitTorrent Chain Mainnet
| 1028 // BitTorrent Chain Testnet
| 42220 // Celo Mainnet
| 44787 // Celo Alfajores Testnet
| 25 // Cronos Mainnet
| 252 // Fraxtal Mainnet
| 2522 // Fraxtal Testnet
| 100 // Gnosis
| 255 // Kroma Mainnet
| 2358 // Kroma Sepolia Testnet
| 5000 // Mantle Mainnet
| 5003 // Mantle Sepolia Testnet
| 1284 // Moonbeam Mainnet
| 1285 // Moonriver Mainnet
| 1287 // Moonbase Alpha Testnet
| 204 // opBNB Mainnet
| 5611 // opBNB Testnet
| 534352 // Scroll Mainnet
| 534351 // Scroll Sepolia Testnet
| 167000 // Taiko Mainnet
| 167009 // Taiko Hekla L2 Testnet
| 1111 // WEMIX3.0 Mainnet
| 1112 // WEMIX3.0 Testnet
| 324 // zkSync Mainnet
| 300 // zkSync Sepolia Testnet
| 660279 // Xai Mainnet
| 37714555429 // Xai Sepolia Testnet
| 50 // XDC Mainnet
| 51 // XDC Apothem Testnet
| 33139 // ApeChain Mainnet
| 33111 // ApeChain Curtis Testnet
| 480 // World Mainnet
| 4801 // World Sepolia Testnet
| 50104 // Sophon Mainnet
| 531050104 // Sophon Sepolia Testnet
| 146 // Sonic Mainnet
| 57054 // Sonic Blaze Testnet
Loading

0 comments on commit 8fce8a6

Please sign in to comment.