UNPKG

@solarity/hardhat-migrate

Version:
215 lines 9.68 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Verifier = void 0; const ethers_1 = require("ethers"); const etherscan_1 = require("@nomicfoundation/hardhat-verify/etherscan"); const blockscout_1 = require("@nomicfoundation/hardhat-verify/blockscout"); const utils_1 = require("../utils"); const requests_1 = require("../tools/network/requests"); const NetworkManager_1 = require("../tools/network/NetworkManager"); const Reporter_1 = require("../tools/reporters/Reporter"); const etherscan_api_1 = require("../tools/network/etherscan-api"); class Verifier { _hre; _config; _standalone; _etherscanConfig; _blockscoutConfig; constructor(_hre, _config, _standalone = false) { this._hre = _hre; this._config = _config; this._standalone = _standalone; this._etherscanConfig = _hre.config.etherscan; this._blockscoutConfig = _hre.config.blockscout; } async verifyBatch(verifierBatchArgs) { const currentChainId = Number(await (0, utils_1.getChainId)()); const toVerify = verifierBatchArgs.filter((args) => args.chainId && currentChainId == args.chainId); if (!toVerify || toVerify.length === 0) { Reporter_1.Reporter.reportNothingToVerify(); return; } const verificationDelay = this._hre.config.migrate.verification.verificationDelay; if (verificationDelay > 0 && !this._standalone) { await Reporter_1.Reporter.startSpinner("verification-delay", () => "Waiting for the explorer to sync up"); await (0, utils_1.sleep)(verificationDelay); Reporter_1.Reporter.stopSpinner(); } Reporter_1.Reporter.reportVerificationBatchBegin(); const parallel = this._config.parallel; for (let i = 0; i < toVerify.length; i += parallel) { const batch = toVerify.slice(i, i + parallel); await Promise.all(batch.map((args) => this._verify(args))); } } async _verify(verifierArgs) { const { contractAddress, contractName, constructorArguments } = verifierArgs; let instance; try { instance = await this._getEtherscanInstance(this._hre); await this._validateExplorerConfiguration(instance, contractAddress); } catch { instance = await this._getBlockscoutInstance(this._hre); } for (let attempts = 0; attempts < this._config.attempts; attempts++) { try { await this._tryVerify(instance, contractAddress, contractName, constructorArguments); break; } catch (e) { this._handleVerificationError(contractAddress, contractName, e); if (e.message !== undefined && typeof e.message === "string" && (e.message.includes("HH303: Unrecognized task 'verify:verify'") || e.message.includes("already verified"))) { break; } } await (0, utils_1.sleep)(2500); } } async _tryVerify(instance, contractAddress, contractName, constructorArguments) { await this._tryRunVerificationTask(instance, contractAddress, contractName, constructorArguments); const isVerified = await instance.isVerified(contractAddress); if (isVerified) { Reporter_1.Reporter.reportSuccessfulVerification(contractAddress, contractName); return; } else { Reporter_1.Reporter.reportVerificationError(contractAddress, contractName, "Verification failed"); } } _handleVerificationError(contractAddress, contractName, error) { if (error.message.toLowerCase().includes("already verified")) { Reporter_1.Reporter.reportAlreadyVerified(contractAddress, contractName); return; } else { Reporter_1.Reporter.reportVerificationError(contractAddress, contractName, error.message); } } async _getEtherscanInstance(hre) { const chainConfig = await etherscan_1.Etherscan.getCurrentChainConfig(hre.network.name, hre.network.provider, this._etherscanConfig.customChains ?? []); return etherscan_1.Etherscan.fromChainConfig(this._etherscanConfig.apiKey, chainConfig); } async _getBlockscoutInstance(hre) { const chainConfig = await blockscout_1.Blockscout.getCurrentChainConfig(hre.network.name, hre.network.provider, this._blockscoutConfig.customChains ?? []); return blockscout_1.Blockscout.fromChainConfig(chainConfig); } async _tryRunVerificationTask(instance, contractAddress, contractName, args) { if (instance instanceof etherscan_1.Etherscan) { await this._hre.run("verify:verify", { address: contractAddress, constructorArguments: args, contract: contractName, force: true, }); await this._verifyProxy(instance, contractAddress); } if (instance instanceof blockscout_1.Blockscout) { await this._hre.run("verify:blockscout", { address: contractAddress, constructorArguments: args, contract: contractName, force: true, }); } } async _validateExplorerConfiguration(instance, contractAddress) { const parameters = new URLSearchParams({ apikey: instance.apiKey, module: "contract", action: "getsourcecode", address: contractAddress, }); const url = new URL(instance.apiUrl); url.search = parameters.toString(); const response = await (0, requests_1.sendGetRequest)(url.toString()); if (response.status !== 200) { console.warn(`The explorer responded with a status code of ${response.status} for the URL "${url.toString().split("?")[0]}".`); } } async _verifyProxy(instance, proxyAddress) { try { const implementationAddress = await (0, utils_1.getPossibleImplementationAddress)(proxyAddress); if (implementationAddress === ethers_1.ethers.ZeroAddress) { return; } await this._linkProxyWithImplementationAbi(instance, proxyAddress, implementationAddress); } catch (e) { /* empty */ } } /** * Calls the Etherscan API to link a proxy with its implementation ABI. * * Source: https://github.com/OpenZeppelin/openzeppelin-upgrades */ async _linkProxyWithImplementationAbi(instance, proxyAddress, implAddress) { const params = { module: "contract", action: "verifyproxycontract", address: proxyAddress, expectedimplementation: implAddress, }; let verifyProxyResponse = await (0, etherscan_api_1.callEtherscanApi)(instance, params); if (verifyProxyResponse.status === etherscan_api_1.RESPONSE_OK) { // initial call was OK, but need to send a status request using the // returned guid to get the actual verification status let responseBody = await this._checkProxyVerificationStatus(instance, verifyProxyResponse.result); while (responseBody.result === "Pending in queue") { await (0, utils_1.sleep)(5000); responseBody = await this._checkProxyVerificationStatus(instance, verifyProxyResponse.result); } } if (verifyProxyResponse.status === etherscan_api_1.RESPONSE_OK) { Reporter_1.Reporter.reportSuccessfulProxyLinking(proxyAddress, implAddress); } else { Reporter_1.Reporter.reportFailedProxyLinking(proxyAddress, implAddress, verifyProxyResponse.result); } } async _checkProxyVerificationStatus(instance, guid) { const checkProxyVerificationParams = { module: "contract", action: "checkproxyverification", apikey: instance.apiKey, guid: guid, }; return (0, etherscan_api_1.callEtherscanApi)(instance, checkProxyVerificationParams); } static async buildVerifierTaskDeps(hre) { (0, NetworkManager_1.buildNetworkDeps)(hre); await (0, Reporter_1.createAndInitReporter)(hre); } } exports.Verifier = Verifier; __decorate([ utils_1.catchError ], Verifier.prototype, "verifyBatch", null); __decorate([ utils_1.catchError ], Verifier.prototype, "_verify", null); __decorate([ utils_1.catchError ], Verifier.prototype, "_tryVerify", null); __decorate([ utils_1.catchError ], Verifier.prototype, "_handleVerificationError", null); __decorate([ utils_1.catchError ], Verifier.prototype, "_getEtherscanInstance", null); __decorate([ utils_1.catchError ], Verifier.prototype, "_getBlockscoutInstance", null); __decorate([ utils_1.suppressLogs ], Verifier.prototype, "_tryRunVerificationTask", null); //# sourceMappingURL=Verifier.js.map