|
16 | 16 | <a href="https://www.npmjs.com/package/@layerzerolabs/verify-contract"><img alt="NPM License" src="https://img.shields.io/npm/l/@layerzerolabs/verify-contract"/></a> |
17 | 17 | </p> |
18 | 18 |
|
| 19 | +## Overview |
| 20 | + |
| 21 | +A comprehensive tool for verifying smart contracts on block explorers. Supports both CLI and programmatic usage, with built-in support for Etherscan API v2 and 60+ EVM networks. |
| 22 | + |
| 23 | +### Etherscan API v2 Support |
| 24 | + |
| 25 | +This package supports **Etherscan API v2**, providing a unified multichain experience: |
| 26 | + |
| 27 | +- **Unified API URL**: All Etherscan-compatible chains use `https://api.etherscan.io/v2/api` |
| 28 | +- **Single API Key**: One Etherscan API key works across all supported chains |
| 29 | +- **Automatic Chain ID**: Chain IDs are automatically set for well-known networks |
| 30 | + |
19 | 31 | ## Installation |
20 | 32 |
|
21 | 33 | ```bash |
| 34 | +npm install @layerzerolabs/verify-contract |
| 35 | +# or |
22 | 36 | yarn add @layerzerolabs/verify-contract |
23 | | - |
| 37 | +# or |
24 | 38 | pnpm add @layerzerolabs/verify-contract |
25 | | - |
26 | | -npm install @layerzerolabs/verify-contract |
27 | 39 | ``` |
28 | 40 |
|
29 | | -## Usage |
| 41 | +## Quick Start |
30 | 42 |
|
31 | 43 | ### CLI |
32 | 44 |
|
33 | | -This package comes with a CLI interface: |
| 45 | +```bash |
| 46 | +# Verify all contracts on Ethereum |
| 47 | +npx @layerzerolabs/verify-contract target \ |
| 48 | + --network ethereum \ |
| 49 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 50 | + --deployments ./deployments |
| 51 | +``` |
| 52 | + |
| 53 | +### Programmatic |
| 54 | + |
| 55 | +```typescript |
| 56 | +import { verifyHardhatDeployTarget } from "@layerzerolabs/verify-contract"; |
| 57 | + |
| 58 | +verifyHardhatDeployTarget({ |
| 59 | + paths: { deployments: "./deployments" }, |
| 60 | + networks: { |
| 61 | + ethereum: { |
| 62 | + apiUrl: "https://api.etherscan.io/v2/api", |
| 63 | + apiKey: "your-etherscan-api-key", |
| 64 | + }, |
| 65 | + }, |
| 66 | +}); |
| 67 | +``` |
| 68 | + |
| 69 | +## CLI Usage |
| 70 | + |
| 71 | +The CLI provides two verification modes: `target` (default) and `non-target`. |
| 72 | + |
| 73 | +### Target Verification |
| 74 | + |
| 75 | +Verifies contracts that have their own deployment files (most common case). |
| 76 | + |
| 77 | +#### Basic Usage |
| 78 | + |
| 79 | +```bash |
| 80 | +# Verify all contracts in a network |
| 81 | +npx @layerzerolabs/verify-contract target \ |
| 82 | + --network ethereum \ |
| 83 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 84 | + --deployments ./deployments |
| 85 | +``` |
| 86 | + |
| 87 | +#### Options |
| 88 | + |
| 89 | +**Common Options:** |
| 90 | +- `-n, --network <network>` - Network name (required) - e.g., `ethereum`, `polygon`, `arbitrum` |
| 91 | +- `-k, --api-key <key>` - Scan API Key (or use environment variable) |
| 92 | +- `-u, --api-url <url>` - Custom scan API URL (auto-detected for known networks) |
| 93 | +- `--chain-id <id>` - Chain ID for Etherscan API v2 (auto-detected for known networks) |
| 94 | +- `-d, --deployments <path>` - Path to deployments folder |
| 95 | +- `--dry-run` - Preview verification without executing |
| 96 | +- `-l, --log-level <level>` - Log level: `error`, `warn`, `info`, `verbose`, `debug` (default: `info`) |
| 97 | + |
| 98 | +**Target-Specific Options:** |
| 99 | +- `-c, --contracts <names>` - Comma-separated list of contract names to verify |
| 100 | + |
| 101 | +#### Examples |
| 102 | + |
| 103 | +```bash |
| 104 | +# Verify specific contracts only |
| 105 | +npx @layerzerolabs/verify-contract target \ |
| 106 | + --network ethereum \ |
| 107 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 108 | + --deployments ./deployments \ |
| 109 | + --contracts FRNTAdapter,DefaultProxyAdmin |
| 110 | + |
| 111 | +# Dry run (preview without actually verifying) |
| 112 | +npx @layerzerolabs/verify-contract target \ |
| 113 | + --network ethereum \ |
| 114 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 115 | + --deployments ./deployments \ |
| 116 | + --dry-run |
| 117 | + |
| 118 | +# Custom explorer (non-Etherscan networks) |
| 119 | +npx @layerzerolabs/verify-contract target \ |
| 120 | + --network aurora \ |
| 121 | + --api-url https://explorer.mainnet.aurora.dev/api \ |
| 122 | + --api-key YOUR_AURORA_API_KEY \ |
| 123 | + --deployments ./deployments |
| 124 | +``` |
| 125 | + |
| 126 | +### Non-Target Verification |
| 127 | + |
| 128 | +Verifies contracts without deployment files (e.g., deployed dynamically by factory contracts). |
| 129 | + |
| 130 | +#### Basic Usage |
34 | 131 |
|
35 | 132 | ```bash |
36 | | -npx @layerzerolabs/verify-contract --help |
| 133 | +npx @layerzerolabs/verify-contract non-target \ |
| 134 | + --network ethereum \ |
| 135 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 136 | + --deployments ./deployments \ |
| 137 | + --address 0x123... \ |
| 138 | + --name "contracts/MyContract.sol:MyContract" \ |
| 139 | + --deployment MyFactory.json \ |
| 140 | + --arguments '[1000, "0x456..."]' |
37 | 141 | ``` |
38 | 142 |
|
39 | | -Using the CLI, contracts can be verified one network at a time. |
| 143 | +#### Options |
| 144 | + |
| 145 | +**Non-Target-Specific Options:** |
| 146 | +- `--address <address>` - Contract address to verify (required) |
| 147 | +- `--name <contract name>` - Fully qualified contract name (required) |
| 148 | +- `--deployment <file>` - Deployment file name to use as source (required) |
| 149 | +- `--arguments <args>` - Constructor arguments as JSON array or encoded hex |
40 | 150 |
|
41 | | -### Programmatic usage |
| 151 | +#### Examples |
42 | 152 |
|
43 | | -The package provides two types of verification for hardhat deploy: _target_ and _non-target_. |
| 153 | +```bash |
| 154 | +# With JSON constructor arguments |
| 155 | +npx @layerzerolabs/verify-contract non-target \ |
| 156 | + --network ethereum \ |
| 157 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 158 | + --deployments ./deployments \ |
| 159 | + --address 0x123... \ |
| 160 | + --name "contracts/MyContract.sol:MyContract" \ |
| 161 | + --deployment MyFactory.json \ |
| 162 | + --arguments '[1000, "0x456..."]' |
| 163 | + |
| 164 | +# With encoded constructor arguments |
| 165 | +npx @layerzerolabs/verify-contract non-target \ |
| 166 | + --network ethereum \ |
| 167 | + --api-key YOUR_ETHERSCAN_API_KEY \ |
| 168 | + --deployments ./deployments \ |
| 169 | + --address 0x123... \ |
| 170 | + --name "contracts/MyContract.sol:MyContract" \ |
| 171 | + --deployment MyFactory.json \ |
| 172 | + --arguments 0x000000000000000000000000... |
| 173 | +``` |
44 | 174 |
|
45 | | -#### Target verification |
| 175 | +### Environment Variables |
46 | 176 |
|
47 | | -This is suitable for verifying contracts that have been the compilation targets for a deployment, i.e. they have their own deployment file. |
48 | | -This is the default and easiest case for which we know all the information we need from the deployment file. |
| 177 | +Instead of passing API keys on the command line, use environment variables: |
| 178 | + |
| 179 | +```bash |
| 180 | +# Set environment variables |
| 181 | +export SCAN_API_KEY_ethereum="your-etherscan-api-key" |
| 182 | +export SCAN_API_KEY_polygon="your-etherscan-api-key" |
| 183 | + |
| 184 | +# Then just specify the network |
| 185 | +npx @layerzerolabs/verify-contract target \ |
| 186 | + --network ethereum \ |
| 187 | + --deployments ./deployments |
| 188 | +``` |
| 189 | + |
| 190 | +The CLI automatically: |
| 191 | +- Uses the correct API URL for known networks |
| 192 | +- Sets the correct chain ID for Etherscan API v2 |
| 193 | +- Pulls API keys from environment variables if not specified |
| 194 | + |
| 195 | +## Programmatic Usage |
| 196 | + |
| 197 | +The package provides two verification functions: `verifyHardhatDeployTarget` and `verifyHardhatDeployNonTarget`. |
| 198 | + |
| 199 | +### Target Verification |
| 200 | + |
| 201 | +Verifies contracts that have their own deployment files. This is the default and easiest case. |
49 | 202 |
|
50 | 203 | ```typescript |
51 | 204 | import { verifyHardhatDeployTarget } from "@layerzerolabs/verify-contract"; |
52 | 205 |
|
53 | | -// Programmatic usage allows for more fine-grained and multi-network verification |
54 | 206 | verifyHardhatDeployTarget({ |
55 | 207 | paths: { |
56 | 208 | deployments: "./my/little/deployments/folder", |
57 | 209 | }, |
58 | 210 | networks: { |
| 211 | + // Using Etherscan API v2 (recommended) |
| 212 | + ethereum: { |
| 213 | + // The v2 base URL is used by default for Etherscan-compatible chains |
| 214 | + apiUrl: "https://api.etherscan.io/v2/api", |
| 215 | + apiKey: "your-etherscan-api-key", |
| 216 | + // Chain ID is automatically set for well-known networks |
| 217 | + // For Ethereum mainnet, chainId: 1 is set automatically |
| 218 | + }, |
| 219 | + polygon: { |
| 220 | + // For Etherscan v2, you can use the same API key and URL for all chains |
| 221 | + apiUrl: "https://api.etherscan.io/v2/api", |
| 222 | + apiKey: "your-etherscan-api-key", |
| 223 | + // Chain ID is automatically set for well-known networks |
| 224 | + // For Polygon, chainId: 137 is set automatically |
| 225 | + }, |
| 226 | + // Custom network example |
59 | 227 | whatachain: { |
60 | 228 | apiUrl: "https://api.whatachain.io/api", |
61 | 229 | apiKey: "david.hasselhoff.1234", |
| 230 | + // For custom networks, specify the chain ID explicitly |
| 231 | + chainId: 12345, |
62 | 232 | }, |
63 | 233 | }, |
64 | | - // The filter option allows you to limit the scope of verification to |
65 | | - // specific contracts |
66 | | - // |
67 | | - // It supports several ways of scoping the verification: |
68 | | - // |
| 234 | + // Filter option allows you to limit verification scope |
| 235 | + // Supports multiple formats: |
| 236 | + |
69 | 237 | // A list of case-sensitive contract names |
70 | 238 | filter: ["Factory", "Router"], |
| 239 | + |
71 | 240 | // A single contract name |
72 | 241 | filter: "ONFT1155", |
73 | | - // Boolean to toggle the verification as a whole |
| 242 | + |
| 243 | + // Boolean to toggle verification |
74 | 244 | filter: false, |
75 | | - // A function that gets passed the contract name and an relative contract path and returns a boolean to signify the contract needs to be verified |
| 245 | + |
| 246 | + // A function that receives contract name and path, returns boolean |
76 | 247 | filter: (name, path) => name.startsWith("Potato721"), |
77 | 248 | }); |
78 | 249 | ``` |
79 | 250 |
|
80 | | -#### Non-target verification |
| 251 | +### Non-Target Verification |
81 | 252 |
|
82 | | -This is suitable for verifying contracts that have been e.g. deployed dynamically from other contracts within the deployment. |
83 | | - |
84 | | -In this case we need to know more information - the specific deployment file to use, the address of the contract and also its constructor arguments. |
| 253 | +Verifies contracts deployed dynamically (e.g., by factory contracts) that don't have their own deployment files. |
85 | 254 |
|
86 | 255 | ```typescript |
87 | 256 | import { verifyHardhatDeployNonTarget } from "@layerzerolabs/verify-contract"; |
88 | 257 |
|
89 | | -// Programmatic usage allows for more fine-grained and multi-network verification |
90 | 258 | verifyHardhatDeployNonTarget({ |
91 | 259 | paths: { |
92 | 260 | deployments: "./my/little/deployments/folder", |
93 | 261 | }, |
94 | 262 | networks: { |
95 | 263 | whatachain: { |
96 | | - apiUrl: "https://api.whatachain.io/api", |
97 | | - apiKey: "david.hasselhoff.1234", |
| 264 | + // Using Etherscan API v2 |
| 265 | + apiUrl: "https://api.etherscan.io/v2/api", |
| 266 | + apiKey: "your-etherscan-api-key", |
| 267 | + chainId: 12345, // Specify chain ID for custom networks |
98 | 268 | }, |
99 | 269 | }, |
100 | | - // The contracts array is used to pass the contract details |
| 270 | + // The contracts array specifies which contracts to verify |
101 | 271 | contracts: [ |
102 | 272 | { |
103 | 273 | address: "0x0", |
104 | 274 | network: "whatachain", |
105 | | - // We'll need to pass the name of the deployment file to use (relative to the deployments path) |
| 275 | + // Deployment file name (relative to deployments path) |
106 | 276 | deployment: "OtherContract.json", |
| 277 | + // Constructor arguments |
107 | 278 | constructorArguments: [1000, "0x0"], |
108 | | - // In this case we'll need to pass a fully-qualified contract name |
| 279 | + // Fully-qualified contract name |
109 | 280 | contractName: "contracts/examples/Pool.sol", |
110 | 281 | }, |
111 | 282 | ], |
112 | 283 | }); |
113 | 284 | ``` |
114 | 285 |
|
115 | | -### Default configuration |
116 | | - |
117 | | -The package is preconfigured for scan API URLs for several well-known networks: |
118 | | - |
119 | | -| Network | API URL | |
120 | | -| -------------------------------------------------------------- | ------------------------------------------------ | |
121 | | -| `avalanche`, `avalanche-mainnet` | `https://api.snowtrace.io/api` | |
122 | | -| `fuji`, `avalanche-testnet` | `https://api-testnet.snowtrace.io/api` | |
123 | | -| `bsc` | `https://api.bscscan.com/api` | |
124 | | -| `bsc-testnet` | `https://api-testnet.bscscan.com/api` | |
125 | | -| `ethereum` | `https://api.etherscan.io/api` | |
126 | | -| `ethereum-goerli` | `https://api-goerli.etherscan.io/api` | |
127 | | -| `goerli` | `https://api-goerli.etherscan.io/api` | |
128 | | -| `fantom` | `https://api.ftmscan.com/api` | |
129 | | -| `fantom-testnet` | `https://api-testnet.ftmscan.com/api` | |
130 | | -| `arbitrum` | `https://api.arbiscan.io/api` | |
131 | | -| `arbitrum-goerli` | `https://api-goerli.arbiscan.io/api` | |
132 | | -| `polygon` | `https://api.polygonscan.com/api` | |
133 | | -| `mumbai` | `https://api-testnet.polygonscan.com/api` | |
134 | | -| `optimism` | `https://api-optimistic.etherscan.io/api` | |
135 | | -| `optimism-goerli` | `https://api-goerli-optimistic.etherscan.io/api` | |
136 | | -| `gnosis` | `https://api.gnosisscan.io/api` | |
137 | | -| `zkpolygon`, `zkpolygon-mainnet` | `https://api-zkevm.polygonscan.com/api` | |
138 | | -| `base`, `base-mainnet` | `https://api.basescan.org/api` | |
139 | | -| `base-goerli` | `https://api-goerli.basescan.org/api` | |
140 | | -| `zkconsensys`, `zkconsensys-mainnet`, `linea`, `linea-mainnet` | `https://api.lineascan.build/api` | |
141 | | -| `moonbeam` | `https://api-moonbeam.moonscan.io/api` | |
142 | | -| `moonbeam-testnet` | `https://api-moonbase.moonscan.io/api` | |
143 | | -| `kava`, `kava-mainnet` | `https://kavascan.com/api` | |
144 | | -| `kava-testnet` | `https://testnet.kavascan.com/api` | |
| 286 | +## Configuration |
| 287 | + |
| 288 | +### Environment Variables |
| 289 | + |
| 290 | +Configure API keys, URLs, browser URLs, and chain IDs using environment variables: |
| 291 | + |
| 292 | +```bash |
| 293 | +# API Key - same key works for all Etherscan v2 compatible chains |
| 294 | +SCAN_API_KEY_ethereum=your-etherscan-api-key |
| 295 | +SCAN_API_KEY_polygon=your-etherscan-api-key |
| 296 | + |
| 297 | +# API URL - uses v2 base URL by default for Etherscan chains |
| 298 | +SCAN_API_URL_ethereum=https://api.etherscan.io/v2/api |
| 299 | +SCAN_API_URL_polygon=https://api.etherscan.io/v2/api |
| 300 | + |
| 301 | +# Chain ID - automatically set for well-known networks, but can be overridden |
| 302 | +SCAN_CHAIN_ID_ethereum=1 |
| 303 | +SCAN_CHAIN_ID_polygon=137 |
| 304 | + |
| 305 | +# Browser URL for displaying verified contract links |
| 306 | +SCAN_BROWSER_URL_ethereum=https://etherscan.io |
| 307 | +SCAN_BROWSER_URL_polygon=https://polygonscan.com |
| 308 | +``` |
| 309 | + |
| 310 | +> **Note:** |
| 311 | +> Environment variable names for network configuration are **not case-sensitive** and support both hyphens (`-`) and underscores (`_`) in network names. For maximum compatibility across systems and shells, it is recommended to define variables using uppercase characters, underscores, and the canonical network name, e.g.: |
| 312 | +> |
| 313 | +> - `SCAN_API_KEY_ETHEREUM` |
| 314 | +> - `SCAN_API_KEY_BASE_SEPOLIA` |
| 315 | +
|
| 316 | +### Default Network Configuration |
| 317 | + |
| 318 | +The package is preconfigured with scan API URLs and chain IDs for well-known networks. |
| 319 | + |
| 320 | +#### Supported Networks |
| 321 | + |
| 322 | +The package supports 60+ EVM networks with preconfigured scan API URLs and chain IDs. Most major EVM networks use the Etherscan API v2 unified endpoint (`https://api.etherscan.io/v2/api`) and can share a single API key. |
| 323 | + |
| 324 | +**Examples:** |
| 325 | + |
| 326 | +| Network | Chain ID | API URL (v2) | |
| 327 | +| -------------------- | -------- | --------------------------------- | |
| 328 | +| `ethereum` | 1 | `https://api.etherscan.io/v2/api` | |
| 329 | +| `polygon` | 137 | `https://api.etherscan.io/v2/api` | |
| 330 | +| `aurora` | 1313161554 | `https://explorer.mainnet.aurora.dev/api` | |
| 331 | + |
| 332 | +For the complete list of supported networks, network aliases, and their configurations, see [`src/common/networks.ts`](src/common/networks.ts). |
0 commit comments