diff --git a/hardhat.config.ts b/hardhat.config.ts index 1a37d073b..647f4e471 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -108,7 +108,7 @@ const config: HardhatUserConfig = { }, outputSelection: { '*': { - '*': ['storageLayout'], + '*': ['storageLayout', 'metadata'], }, }, }, diff --git a/tasks/verify/verify.ts b/tasks/verify/verify.ts index 6139aadda..f3639d3c4 100644 --- a/tasks/verify/verify.ts +++ b/tasks/verify/verify.ts @@ -3,7 +3,10 @@ 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 { cliOpts } from '../../cli/defaults' import fs from 'fs' +import path from 'path' task('sourcify', 'Verifies contract on sourcify') .addPositionalParam('address', 'Address of the smart contract to verify', undefined, types.string) @@ -27,3 +30,60 @@ task('sourcify', 'Verifies contract on sourcify') fqn: args.contract, }) }) + +task('sourcifyAll', 'Verifies all contracts on sourcify') + .addParam('addressBook', cliOpts.addressBook.description, cliOpts.addressBook.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(cliOpts.addressBook.default, chainId.toString()) + + for (const contractName of addressBook.listEntries()) { + console.log(`\n> Verifying contract ${contractName}...`) + + const contractPath = getContractPath(contractName) + if (contractPath) { + const contract = addressBook.getEntry(contractName) + if (contract.implementation) { + console.log('Contract is upgradeable, verifying proxy...') + + await hre.run('sourcify', { + address: contract.address, + contract: 'contracts/upgrades/GraphProxy.sol:GraphProxy', + }) + } + + // Verify implementation + await hre.run('sourcify', { + address: contract.implementation?.address ?? contract.address, + contract: `${contractPath}:${contractName}`, + }) + } else { + console.log(`Contract ${contractName} not found.`) + } + } + }) + +function getContractPath(contract: string): string | undefined { + const files = readDirRecursive('contracts/') + return files.find((f) => path.basename(f) === `${contract}.sol`) +} + +function readDirRecursive(dir: string, allFiles: string[] = []) { + const files = fs.readdirSync(dir) + + for (const file of files) { + if (fs.statSync(path.join(dir, file)).isDirectory()) { + allFiles = readDirRecursive(path.join(dir, file), allFiles) + } else { + allFiles.push(path.join(dir, file)) + } + } + + return allFiles +}