diff --git a/hardhat.config.ts b/hardhat.config.ts index 07c6270f4..51fb887b6 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -222,6 +222,15 @@ const config: HardhatUserConfig = { count: 20, }, }, + zkevmDevnet: { + url: "http://123:123:123:123:123", + accounts: { + mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, + path: "m/44'/60'/0'/0", + initialIndex: 0, + count: 20, + }, + }, }, gasReporter: { enabled: !!process.env.REPORT_GAS, @@ -235,6 +244,7 @@ const config: HardhatUserConfig = { goerli: `${process.env.ETHERSCAN_API_KEY}`, sepolia: `${process.env.ETHERSCAN_API_KEY}`, mainnet: `${process.env.ETHERSCAN_API_KEY}`, + zkevmDevnet: `${process.env.ETHERSCAN_API_KEY}`, }, customChains: [ { @@ -253,6 +263,14 @@ const config: HardhatUserConfig = { browserURL: "https://testnet-zkevm.polygonscan.com/", }, }, + { + network: "zkevmDevnet", + chainId: 123, + urls: { + apiURL: "http://123:123:123:123:123/api", + browserURL: "http://123:123:123:123:123", + }, + }, ], }, }; diff --git a/package.json b/package.json index d2042275d..5f09cb661 100644 --- a/package.json +++ b/package.json @@ -96,8 +96,11 @@ "docker:v1ToV2:contracts": "./docker/scripts/v1ToV2/deploy-docker.sh", "dockerv2:v1ToV2:contracts": "sudo ./docker/scripts/v1ToV2/deploy-dockerv2.sh", "saveDeployment:sepolia": "mkdir -p deployments/sepolia_$(date +%s) && cp -r deployment/v2/deploy_*.json deployments/sepolia_$(date +%s) && cp .openzeppelin/sepolia.json deployments/sepolia_$(date +%s) && cp deployment/v2/genesis.json deployments/sepolia_$(date +%s) && cp deployment/v2/create_rollup_output.json deployments/sepolia_$(date +%s)", + "testnetPol:upgradeV2:sepolia": "npx hardhat run upgrade/upgradeToV2/testnet/deployTestnetPol.ts --network sepolia", "upgradev2:timelock:goerli": "npx hardhat run upgrade/upgradeToV2/upgradeToV2.ts --network goerli", - "upgradev2L2:timelock:goerli": "npx hardhat run upgrade/upgradeToV2/upgradeL2ToV2.ts --network zkevm" - + "upgradev2:timelock:sepolia": "npx hardhat run upgrade/upgradeToV2/upgradeToV2.ts --network sepolia", + "verify:upgradeV2:sepolia": "npx hardhat run upgrade/upgradeToV2/verifyContracts.ts --network sepolia", + "verify:upgradeV2:goerli": "npx hardhat run upgrade/upgradeToV2/verifyContracts.ts --network goerli", + "upgradev2L2:timelock:zkevmDevnet": "npx hardhat run upgrade/upgradeToV2/upgradeL2ToV2.ts --network zkevmDevnet" } } \ No newline at end of file diff --git a/upgrade/upgradeToV2/upgradeToV2.ts b/upgrade/upgradeToV2/upgradeToV2.ts index 5d9a5f5dc..f9dad8e47 100644 --- a/upgrade/upgradeToV2/upgradeToV2.ts +++ b/upgrade/upgradeToV2/upgradeToV2.ts @@ -14,18 +14,64 @@ const deployParameters = require("./deploy_parameters.json"); const deployOutputParameters = require("./deploy_output.json"); const upgradeParameters = require("./upgrade_parameters.json"); -const pathOZUpgradability = path.join(__dirname, `../../.openzeppelin/${process.env.HARDHAT_NETWORK}.json`); - async function main() { + /* + * Check deploy parameters + * Check that every necessary parameter is fullfilled + */ + const mandatoryDeploymentParameters = [ + "admin", + "trustedAggregator", + "trustedAggregatorTimeout", + "pendingStateTimeout", + "zkEVMOwner", + "chainID", + ]; + + for (const parameterName of mandatoryDeploymentParameters) { + if (deployParameters[parameterName] === undefined || deployParameters[parameterName] === "") { + throw new Error(`Missing parameter: ${parameterName}`); + } + } + const {admin, trustedAggregator, trustedAggregatorTimeout, pendingStateTimeout, zkEVMOwner, chainID} = deployParameters; const emergencyCouncilAddress = zkEVMOwner; + /* + * Check upgrade parameters + * Check that every necessary parameter is fullfilled + */ + const mandatoryUpgradeParameters = ["realVerifier", "newForkID", "timelockDelay", "polTokenAddress"]; + + for (const parameterName of mandatoryUpgradeParameters) { + if (upgradeParameters[parameterName] === undefined || upgradeParameters[parameterName] === "") { + throw new Error(`Missing parameter: ${parameterName}`); + } + } + const {realVerifier, newForkID, timelockDelay, polTokenAddress} = upgradeParameters; const salt = upgradeParameters.timelockSalt || ethers.ZeroHash; + /* + * Check output parameters + * Check that every necessary parameter is fullfilled + */ + const mandatoryOutputParameters = [ + "polygonZkEVMBridgeAddress", + "polygonZkEVMGlobalExitRootAddress", + "polygonZkEVMAddress", + "timelockContractAddress", + ]; + + for (const parameterName of mandatoryOutputParameters) { + if (deployOutputParameters[parameterName] === undefined || deployOutputParameters[parameterName] === "") { + throw new Error(`Missing parameter: ${parameterName}`); + } + } + const currentBridgeAddress = deployOutputParameters.polygonZkEVMBridgeAddress; const currentGlobalExitRootAddress = deployOutputParameters.polygonZkEVMGlobalExitRootAddress; const currentPolygonZkEVMAddress = deployOutputParameters.polygonZkEVMAddress; @@ -124,7 +170,7 @@ async function main() { ); // prepare upgrade global exit root - // Prepare Upgrade PolygonZkEVMBridge + // Prepare Upgrade PolygonZkEVMGlobalExitRootV2 const polygonGlobalExitRootV2 = await ethers.getContractFactory("PolygonZkEVMGlobalExitRootV2", deployer); const newGlobalExitRoortImpl = await upgrades.prepareUpgrade( @@ -158,7 +204,7 @@ async function main() { // Update current system to rollup manager - // deploy polygon + // deploy polygon zkEVM impl const PolygonZkEVMV2ExistentFactory = await ethers.getContractFactory("PolygonZkEVMExistentEtrog"); const polygonZkEVMEtrogImpl = await PolygonZkEVMV2ExistentFactory.deploy( currentGlobalExitRootAddress, @@ -182,6 +228,7 @@ async function main() { currentPolygonZkEVMAddress, ]); + // deploy polygon zkEVM proxy const PolygonTransparentProxy = await ethers.getContractFactory("PolygonTransparentProxy"); const newPolygonZkEVMContract = await PolygonTransparentProxy.deploy( polygonZkEVMEtrogImpl.target, diff --git a/upgrade/upgradeToV2/verifyContracts.ts b/upgrade/upgradeToV2/verifyContracts.ts new file mode 100644 index 000000000..631c65069 --- /dev/null +++ b/upgrade/upgradeToV2/verifyContracts.ts @@ -0,0 +1,108 @@ +/* eslint-disable no-await-in-loop, no-use-before-define, no-lonely-if */ +/* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved */ +import {expect} from "chai"; +import path = require("path"); +import fs = require("fs"); + +import * as dotenv from "dotenv"; +dotenv.config({path: path.resolve(__dirname, "../../.env")}); +import {ethers, upgrades, run} from "hardhat"; + +const outputJson = require("./upgrade_output.json"); + +const deployParameters = require("./deploy_parameters.json"); +const deployOutputParameters = require("./deploy_output.json"); +const upgradeParameters = require("./upgrade_parameters.json"); + +async function main() { + // load deployer account + if (typeof process.env.ETHERSCAN_API_KEY === "undefined") { + throw new Error("Etherscan API KEY has not been defined"); + } + + const {polTokenAddress} = upgradeParameters; + const currentBridgeAddress = deployOutputParameters.polygonZkEVMBridgeAddress; + const currentGlobalExitRootAddress = deployOutputParameters.polygonZkEVMGlobalExitRootAddress; + const currentPolygonZkEVMAddress = deployOutputParameters.polygonZkEVMAddress; + + try { + // verify verifier + await run("verify:verify", { + address: outputJson.verifierAddress, + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("already verified")).to.be.equal(true); + } + + // Verify bridge + try { + await run("verify:verify", { + address: currentBridgeAddress, + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("already verified")).to.be.equal(true); + } + + // verify global exit root + try { + await run("verify:verify", { + address: currentGlobalExitRootAddress, + constructorArguments: [currentPolygonZkEVMAddress, currentBridgeAddress], + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("already verified")).to.be.equal(true); + } + + // verify zkEVM implementation + const implNewZkEVM = await upgrades.erc1967.getImplementationAddress(outputJson.newPolygonZKEVM); + try { + await run("verify:verify", { + address: implNewZkEVM, + constructorArguments: [ + currentGlobalExitRootAddress, + polTokenAddress, + currentBridgeAddress, + currentPolygonZkEVMAddress, + ], + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("proxyadmin")).to.be.equal(true); + } + + // verify zkEVM proxy + try { + await run("verify:verify", { + address: outputJson.newPolygonZKEVM, + constructorArguments: [implNewZkEVM, currentPolygonZkEVMAddress, "0x"], + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("proxyadmin")).to.be.equal(true); + } + + // verify zkEVM proxy + try { + await run("verify:verify", { + address: outputJson.newPolygonZKEVM, + constructorArguments: [implNewZkEVM, currentPolygonZkEVMAddress, "0x"], + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("proxyadmin")).to.be.equal(true); + } + + // verify rollup manager + try { + await run("verify:verify", { + address: currentPolygonZkEVMAddress, + constructorArguments: [currentGlobalExitRootAddress, polTokenAddress, currentBridgeAddress], + }); + } catch (error: any) { + // expect(error.message.toLowerCase().includes("proxyadmin")).to.be.equal(true); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + });