diff --git a/tasks/etherscan-verify-deployment.ts b/tasks/etherscan-verify-deployment.ts index da7866ff..b24a92c9 100644 --- a/tasks/etherscan-verify-deployment.ts +++ b/tasks/etherscan-verify-deployment.ts @@ -1,34 +1,83 @@ +import {Address} from "hardhat-deploy/types" +import {Etherscan} from "@nomicfoundation/hardhat-verify/etherscan" import {task} from "hardhat/config" -import fs from "fs/promises" -import path from "path" +import https from "https" +import {HardhatRuntimeEnvironment} from "hardhat/types" task( "etherscan-verify-deployments", "Verifies all contracts in the deployments folder" ).setAction(async (taskArgs, hre) => { - const networkName = hre.network.name - const deploymentFolderPath = `./deployments/${networkName}` - console.log(`Reading deployments from ${deploymentFolderPath}`) + const etherscan = await etherscanClient(hre) + const deployments = Object.entries(await hre.deployments.all()) - const deploymentFiles = await fs.readdir(deploymentFolderPath) - const jsonFiles = deploymentFiles.filter(f => f.endsWith(".json")) + console.log(`Read ${deployments.length} deployments from environment`) - for (const contractFileName of jsonFiles) { - const contractFile = path.join(deploymentFolderPath, contractFileName) - const contractDataRaw = await fs.readFile(contractFile, "utf8") - const contractData = JSON.parse(contractDataRaw) + for (const [name, deployment] of deployments) { + console.log() // newline - const name = contractFileName.split(".")[0] - const address = contractData.address - const args = contractData.args.join(", ") + const address = deployment.address + const constructorArguments = deployment.args console.log( - `Verifying ${name} at ${address} constructed with (${args})` + `Verifying ${name} at ${address} constructed with (${constructorArguments})` ) + await hre.run("verify:verify", {address, constructorArguments}) - await hre.run("verify:verify", { - address: address, - constructorArguments: contractData.args - }) + if (name.endsWith("Proxy") && name !== "ManagerProxy") { + const targetName = name.replace("Proxy", "Target") + const target = await hre.deployments.get(targetName) + + console.log( + `Verifying as proxy to ${targetName} at ${target.address}` + ) + await verifyProxyContract(etherscan, address, target.address) + } } }) + +async function etherscanClient({config, network}: HardhatRuntimeEnvironment) { + const apiKey = config.etherscan.apiKey + const chainConfig = await Etherscan.getCurrentChainConfig( + network.name, + network.provider, + [] + ) + return Etherscan.fromChainConfig(apiKey, chainConfig) +} + +function verifyProxyContract( + etherscan: Etherscan, + proxyAddress: Address, + targetAddress: Address +) { + const url = new URL(etherscan.apiUrl) + if (url.protocol !== "https:") { + throw new Error("Etherscan API URL must use HTTPS") + } + + const options = { + hostname: url.hostname, + path: + url.pathname + + `?module=contract&action=verifyproxycontract&address=${proxyAddress}` + + `&expectedimplementation=${targetAddress}&apikey=${etherscan.apiKey}`, + method: "GET" + } + + return new Promise((resolve, reject) => { + const req = https.request(options, res => { + if (res.statusCode === 200) { + return resolve() + } + + reject( + new Error( + `Failed to verify proxy contract: ${res.statusCode} ${res.statusMessage}` + ) + ) + }) + req.on("error", reject) + req.end() + }) +} diff --git a/tsconfig.json b/tsconfig.json index 719c7e8e..22445483 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,6 @@ "outDir": "dist", "resolveJsonModule": true }, - "include": ["./scripts", "./test", "./deploy", "./utils"], + "include": ["./scripts", "./test", "./deploy", "./utils", "./tasks"], "files": ["./hardhat.config.ts"] }