Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add hardhat task to verify all contracts with etherscan #626

Merged
merged 1 commit into from
Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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