Skip to content

Commit 47764e8

Browse files
authored
chore: add hardhat task to verify all contracts with etherscan (#626)
Signed-off-by: Tomás Migone <[email protected]>
1 parent 49ef530 commit 47764e8

File tree

2 files changed

+102
-1
lines changed

2 files changed

+102
-1
lines changed

DEPLOYMENT.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,37 @@ Some contracts require the address from previously deployed contracts. For that
105105
4. Merge this update into master, branch off and save for whatever version of the testnet is going on, and then tag this on the github repo, pointing to your branch (ex. at `testnet-phase-1` branch). This way we can always get the contract code for testnet, while continuing to do work on mainnet.
106106
5. Pull the updated package into the subgraph, and other apps that depend on the package.json.
107107
6. Send tokens to the whole team using `./cli/cli.ts airdrop`
108+
109+
## Verifying the deployed smart contracts
110+
111+
Deployed smart contracts can be verified on etherscan and sourcify using built-in commands.
112+
113+
### Etherscan
114+
115+
[Etherscan](https://etherscan.io/) verification can be performed by using the [hardhat-etherscan](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-etherscan) plugin. __Note__: ensure you have set a valid `ETHERSCAN_API_KEY` in the `.env` file.
116+
117+
- To verify a single contract, run:
118+
119+
```bash
120+
npx hardhat verify --network {networkName} --contract {FullyQualifiedContractName} {contractAddress} {constructorInitParams}
121+
```
122+
123+
- To verify all contracts on the address book, run:
124+
```bash
125+
npx hardhat verifyAll --network {networkName} --graph-config {graphConfigFile}
126+
```
127+
128+
### Sourcify
129+
130+
Additionally you can verify contracts on [Sourcify](https://sourcify.dev/).
131+
132+
- To verify a single contract, run:
133+
134+
```bash
135+
npx hardhat sourcify --network {networkName} --contract {FullyQualifiedContractName} {contractAddress}
136+
```
137+
138+
- To verify all contracts on the address book, run:
139+
```bash
140+
npx hardhat sourcifyAll --network {networkName}
141+
```

tasks/verify/verify.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import * as types from 'hardhat/internal/core/params/argumentTypes'
33
import { submitSourcesToSourcify } from './sourcify'
44
import { isFullyQualifiedName, parseFullyQualifiedName } from 'hardhat/utils/contract-names'
55
import { TASK_COMPILE } from 'hardhat/builtin-tasks/task-names'
6-
import { getAddressBook } from '../../cli/address-book'
6+
import { loadEnv } from '../../cli/env'
77
import { cliOpts } from '../../cli/defaults'
8+
import { getAddressBook } from '../../cli/address-book'
9+
import { getContractConfig, readConfig } from '../../cli/config'
10+
import { Wallet } from 'ethers'
11+
import { NomicLabsHardhatPluginError } from 'hardhat/plugins'
812
import fs from 'fs'
913
import path from 'path'
14+
import { HardhatRuntimeEnvironment } from 'hardhat/types'
1015

1116
task('sourcify', 'Verifies contract on sourcify')
1217
.addPositionalParam('address', 'Address of the smart contract to verify', undefined, types.string)
@@ -69,6 +74,68 @@ task('sourcifyAll', 'Verifies all contracts on sourcify')
6974
}
7075
})
7176

77+
task('verifyAll', 'Verifies all contracts on etherscan')
78+
.addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default)
79+
.addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default)
80+
.setAction(async (args, hre) => {
81+
const chainId = hre.network.config.chainId
82+
const chainName = hre.network.name
83+
84+
if (!chainId || !chainName) {
85+
throw new Error('Cannot verify contracts without a network')
86+
}
87+
88+
console.log(`> Verifying all contracts on chain ${chainName}[${chainId}]...`)
89+
const addressBook = getAddressBook(args.addressBook, chainId.toString())
90+
const graphConfig = readConfig(args.graphConfig)
91+
92+
const accounts = await hre.ethers.getSigners()
93+
const env = await loadEnv(args, accounts[0] as unknown as Wallet)
94+
95+
for (const contractName of addressBook.listEntries()) {
96+
console.log(`\n> Verifying contract ${contractName}...`)
97+
98+
const contractConfig = getContractConfig(graphConfig, addressBook, contractName, env)
99+
const contractPath = getContractPath(contractName)
100+
const constructorParams = contractConfig.params.map((p) => p.value.toString())
101+
102+
if (contractPath) {
103+
const contract = addressBook.getEntry(contractName)
104+
105+
if (contract.implementation) {
106+
console.log('Contract is upgradeable, verifying proxy...')
107+
const proxyAdmin = addressBook.getEntry('GraphProxyAdmin')
108+
109+
// Verify proxy
110+
await safeVerify(hre, {
111+
address: contract.address,
112+
contract: 'contracts/upgrades/GraphProxy.sol:GraphProxy',
113+
constructorArgsParams: [contract.implementation.address, proxyAdmin.address],
114+
})
115+
}
116+
117+
// Verify implementation
118+
console.log('Verifying implementation...')
119+
await safeVerify(hre, {
120+
address: contract.implementation?.address ?? contract.address,
121+
contract: `${contractPath}:${contractName}`,
122+
constructorArgsParams: contract.implementation ? [] : constructorParams,
123+
})
124+
} else {
125+
console.log(`Contract ${contractName} not found.`)
126+
}
127+
}
128+
})
129+
130+
// etherscan API throws errors if the contract is already verified
131+
async function safeVerify(hre: HardhatRuntimeEnvironment, taskArguments: any): Promise<void> {
132+
try {
133+
await hre.run('verify', taskArguments)
134+
} catch (error) {
135+
console.log(error.message)
136+
}
137+
}
138+
72139
function getContractPath(contract: string): string | undefined {
73140
const files = readDirRecursive('contracts/')
74141
return files.find((f) => path.basename(f) === `${contract}.sol`)

0 commit comments

Comments
 (0)