Skip to content

Commit

Permalink
chore: add hardhat task to verify all contracts with etherscan (#626)
Browse files Browse the repository at this point in the history
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
  • Loading branch information
tmigone authored Jul 18, 2022
1 parent 49ef530 commit 47764e8
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
34 changes: 34 additions & 0 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,37 @@ Some contracts require the address from previously deployed contracts. For that
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.
5. Pull the updated package into the subgraph, and other apps that depend on the package.json.
6. Send tokens to the whole team using `./cli/cli.ts airdrop`

## Verifying the deployed smart contracts

Deployed smart contracts can be verified on etherscan and sourcify using built-in commands.

### Etherscan

[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.

- To verify a single contract, run:

```bash
npx hardhat verify --network {networkName} --contract {FullyQualifiedContractName} {contractAddress} {constructorInitParams}
```

- To verify all contracts on the address book, run:
```bash
npx hardhat verifyAll --network {networkName} --graph-config {graphConfigFile}
```

### Sourcify

Additionally you can verify contracts on [Sourcify](https://sourcify.dev/).

- To verify a single contract, run:

```bash
npx hardhat sourcify --network {networkName} --contract {FullyQualifiedContractName} {contractAddress}
```

- To verify all contracts on the address book, run:
```bash
npx hardhat sourcifyAll --network {networkName}
```
69 changes: 68 additions & 1 deletion tasks/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import * as types from 'hardhat/internal/core/params/argumentTypes'
import { submitSourcesToSourcify } from './sourcify'
import { isFullyQualifiedName, parseFullyQualifiedName } from 'hardhat/utils/contract-names'
import { TASK_COMPILE } from 'hardhat/builtin-tasks/task-names'
import { getAddressBook } from '../../cli/address-book'
import { loadEnv } from '../../cli/env'
import { cliOpts } from '../../cli/defaults'
import { getAddressBook } from '../../cli/address-book'
import { getContractConfig, readConfig } from '../../cli/config'
import { Wallet } from 'ethers'
import { NomicLabsHardhatPluginError } from 'hardhat/plugins'
import fs from 'fs'
import path from 'path'
import { HardhatRuntimeEnvironment } from 'hardhat/types'

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

task('verifyAll', 'Verifies all contracts on etherscan')
.addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.default)
.addParam('graphConfig', cliOpts.graphConfig.description, cliOpts.graphConfig.default)
.setAction(async (args, hre) => {
const chainId = hre.network.config.chainId
const chainName = hre.network.name

if (!chainId || !chainName) {
throw new Error('Cannot verify contracts without a network')
}

console.log(`> Verifying all contracts on chain ${chainName}[${chainId}]...`)
const addressBook = getAddressBook(args.addressBook, chainId.toString())
const graphConfig = readConfig(args.graphConfig)

const accounts = await hre.ethers.getSigners()
const env = await loadEnv(args, accounts[0] as unknown as Wallet)

for (const contractName of addressBook.listEntries()) {
console.log(`\n> Verifying contract ${contractName}...`)

const contractConfig = getContractConfig(graphConfig, addressBook, contractName, env)
const contractPath = getContractPath(contractName)
const constructorParams = contractConfig.params.map((p) => p.value.toString())

if (contractPath) {
const contract = addressBook.getEntry(contractName)

if (contract.implementation) {
console.log('Contract is upgradeable, verifying proxy...')
const proxyAdmin = addressBook.getEntry('GraphProxyAdmin')

// Verify proxy
await safeVerify(hre, {
address: contract.address,
contract: 'contracts/upgrades/GraphProxy.sol:GraphProxy',
constructorArgsParams: [contract.implementation.address, proxyAdmin.address],
})
}

// Verify implementation
console.log('Verifying implementation...')
await safeVerify(hre, {
address: contract.implementation?.address ?? contract.address,
contract: `${contractPath}:${contractName}`,
constructorArgsParams: contract.implementation ? [] : constructorParams,
})
} else {
console.log(`Contract ${contractName} not found.`)
}
}
})

// etherscan API throws errors if the contract is already verified
async function safeVerify(hre: HardhatRuntimeEnvironment, taskArguments: any): Promise<void> {
try {
await hre.run('verify', taskArguments)
} catch (error) {
console.log(error.message)
}
}

function getContractPath(contract: string): string | undefined {
const files = readDirRecursive('contracts/')
return files.find((f) => path.basename(f) === `${contract}.sol`)
Expand Down

0 comments on commit 47764e8

Please sign in to comment.