From b8694810d5ab28b7bb1dfacd35411a1c74319f1e Mon Sep 17 00:00:00 2001 From: Ignasi Date: Tue, 5 Nov 2024 17:10:34 +0100 Subject: [PATCH 01/12] Script to create sovereign genesis with hardhat --- .gitignore | 2 + deployment/helpers/deployment-helpers.ts | 12 +- deployment/v2/utils/updateVanillaGenesis.ts | 5 +- .../createSovereignGenesisWithHardhat.ts | 467 ++++++++++++++++++ 4 files changed, 479 insertions(+), 7 deletions(-) create mode 100644 tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts diff --git a/.gitignore b/.gitignore index 0fdae8914..7f6fd160b 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ create_rollup_parameters.json docker/deploymentOutput .DS_Store + +tools/createSovereignGenesisWithHardhat/genesis-sovereign_hardhat.json diff --git a/deployment/helpers/deployment-helpers.ts b/deployment/helpers/deployment-helpers.ts index 97318a213..189ddefa7 100644 --- a/deployment/helpers/deployment-helpers.ts +++ b/deployment/helpers/deployment-helpers.ts @@ -78,7 +78,7 @@ export async function deployPolygonZkEVMDeployer( } export async function create2Deployment( - polgonZKEVMDeployerContract: PolygonZkEVMDeployer, + polygonZKEVMDeployerContract: PolygonZkEVMDeployer, salt: string, deployTransaction: string, dataCall: string | null, @@ -90,7 +90,7 @@ export async function create2Deployment( // Precalculate create2 address const precalculatedAddressDeployed = ethers.getCreate2Address( - polgonZKEVMDeployerContract.target as string, + polygonZKEVMDeployerContract.target as string, salt, hashInitCode ); @@ -104,7 +104,7 @@ export async function create2Deployment( // Deploy using create2 and call if (hardcodedGasLimit) { const populatedTransaction = - await polgonZKEVMDeployerContract.deployDeterministicAndCall.populateTransaction( + await polygonZKEVMDeployerContract.deployDeterministicAndCall.populateTransaction( amount, salt, deployTransaction, @@ -114,13 +114,13 @@ export async function create2Deployment( await (await deployer.sendTransaction(populatedTransaction)).wait(); } else { await ( - await polgonZKEVMDeployerContract.deployDeterministicAndCall(amount, salt, deployTransaction, dataCall) + await polygonZKEVMDeployerContract.deployDeterministicAndCall(amount, salt, deployTransaction, dataCall) ).wait(); } } else { // Deploy using create2 if (hardcodedGasLimit) { - const populatedTransaction = await polgonZKEVMDeployerContract.deployDeterministic.populateTransaction( + const populatedTransaction = await polygonZKEVMDeployerContract.deployDeterministic.populateTransaction( amount, salt, deployTransaction @@ -128,7 +128,7 @@ export async function create2Deployment( populatedTransaction.gasLimit = hardcodedGasLimit; await (await deployer.sendTransaction(populatedTransaction)).wait(); } else { - await (await polgonZKEVMDeployerContract.deployDeterministic(amount, salt, deployTransaction)).wait(); + await (await polygonZKEVMDeployerContract.deployDeterministic(amount, salt, deployTransaction)).wait(); } } return [precalculatedAddressDeployed, true]; diff --git a/deployment/v2/utils/updateVanillaGenesis.ts b/deployment/v2/utils/updateVanillaGenesis.ts index 6fb67b267..d4b842b3c 100644 --- a/deployment/v2/utils/updateVanillaGenesis.ts +++ b/deployment/v2/utils/updateVanillaGenesis.ts @@ -174,9 +174,12 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) { await batch2.executeTxs(); await zkEVMDB2.consolidate(batch2); - // Update bridgeProxy storage + // Update bridgeProxy storage and nonce bridgeProxy.contractName = bridgeContractName + " proxy"; bridgeProxy.storage = await zkEVMDB2.dumpStorage(bridgeProxy.address); + // Update nonce, in case weth is deployed at initialize, it is increased + const bridgeProxyState = await zkEVMDB2.getCurrentAccountState(bridgeProxy.address) + bridgeProxy.nonce = String(Number(bridgeProxyState.nonce)); // If bridge initialized with a zero sovereign weth address and a non zero gas token, we should add created erc20 weth contract to the genesis let wethAddress; if ( diff --git a/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts b/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts new file mode 100644 index 000000000..865047c30 --- /dev/null +++ b/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts @@ -0,0 +1,467 @@ +/* eslint-disable no-await-in-loop, no-use-before-define, no-lonely-if, import/no-dynamic-require */ +/* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved, no-restricted-syntax */ +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 yargs from "yargs/yargs"; +import {getStorageAt, setCode, setNonce, setStorageAt} from "@nomicfoundation/hardhat-network-helpers"; + +const argv = yargs(process.argv.slice(2)) + .options({ + test: {type: "boolean", default: false}, + input: {type: "string", default: "../../deployment/v2/deploy_parameters.json"}, + out: {type: "string", default: "./genesis-sovereign_hardhat.json"}, + }) + .parse() as any; + +const DEFAULT_MNEMONIC = "test test test test test test test test test test test junk"; +process.env.HARDHAT_NETWORK = "hardhat"; +process.env.MNEMONIC = argv.test ? DEFAULT_MNEMONIC : process.env.MNEMONIC; +import {ethers, upgrades} from "hardhat"; +import {MemDB, ZkEVMDB, getPoseidon, smtUtils} from "@0xpolygonhermez/zkevm-commonjs"; + +import {deployPolygonZkEVMDeployer, create2Deployment} from "../../deployment/helpers/deployment-helpers"; +import {ProxyAdmin, BridgeL2SovereignChain} from "../../typechain-types"; +import {Addressable} from "ethers"; + +import "../../deployment/helpers/utils"; + +const deployParameters = require(argv.input); +const pathOutputJson = path.join(__dirname, argv.out); +const genesisSovereign = require("../../docker/deploymentOutput/genesis_sovereign.json"); +const createRollupParameters = require("../../deployment/v2/create_rollup_parameters.json"); + +/* + * bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + */ +const _ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103" as any; +const _IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" as any; + +const zkevmAddressL2 = ethers.ZeroAddress; + +async function main() { + // Constant variables + const balanceBridge = BigInt("0xffffffffffffffffffffffffffffffff"); // 128 bits + const genesis = []; + + // load deploy parameters + const mandatoryDeploymentParameters = [ + "timelockAdminAddress", + "minDelayTimelock", + "salt", + "initialZkEVMDeployerOwner", + ]; + + for (const parameterName of mandatoryDeploymentParameters) { + if (deployParameters[parameterName] === undefined || deployParameters[parameterName] === "") { + throw new Error(`Missing parameter: ${parameterName}`); + } + } + let {timelockAdminAddress, minDelayTimelock, salt, initialZkEVMDeployerOwner} = deployParameters; + + // Load deployer + await ethers.provider.send("hardhat_impersonateAccount", [initialZkEVMDeployerOwner]); + await ethers.provider.send("hardhat_setBalance", [initialZkEVMDeployerOwner, "0xffffffffffffffff"]); // 18 ethers aprox + const deployer = await ethers.getSigner(initialZkEVMDeployerOwner); + + // Deploy PolygonZkEVMDeployer if is not deployed already + const [zkEVMDeployerContract, keylessDeployer] = await deployPolygonZkEVMDeployer( + initialZkEVMDeployerOwner, + deployer + ); + const finalDeployer = deployer.address; + const finalKeylessDeployer = keylessDeployer; + const finalZkEVMDeployerAddress = zkEVMDeployerContract.target; + /* + * Deploy Bridge + * Deploy admin --> implementation --> proxy + */ + + // Deploy proxy admin: + const proxyAdminFactory = await ethers.getContractFactory( + "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol:ProxyAdmin", + deployer + ); + const deployTransactionAdmin = (await proxyAdminFactory.getDeployTransaction()).data; + const dataCallAdmin = proxyAdminFactory.interface.encodeFunctionData("transferOwnership", [deployer.address]); + const [proxyAdminAddress] = await create2Deployment( + zkEVMDeployerContract, + salt, + deployTransactionAdmin, + dataCallAdmin, + deployer, + null + ); + + // Deploy implementation SovereignBridge + const bridgeContractName = "BridgeL2SovereignChain"; + const sovereignBridgeFactory = await ethers.getContractFactory(bridgeContractName, deployer); + const deployTransactionBridge = (await sovereignBridgeFactory.getDeployTransaction()).data; + // Mandatory to override the gasLimit since the estimation with create are mess up D: + const overrideGasLimit = BigInt(5500000); + let [bridgeImplementationAddress] = await create2Deployment( + zkEVMDeployerContract, + salt, + deployTransactionBridge, + null, + deployer, + overrideGasLimit + ); + // Get genesis params + const sovereignGenesisBridgeProxy = genesisSovereign.genesis.find(function (obj) { + return obj.contractName == "BridgeL2SovereignChain proxy"; + }); + const sovereignGenesisBridgeImplementation = genesisSovereign.genesis.find(function (obj) { + return obj.contractName == "BridgeL2SovereignChain"; + }); + const sovereignGenesisGERProxy = genesisSovereign.genesis.find(function (obj) { + return obj.contractName == "GlobalExitRootManagerL2SovereignChain proxy"; + }); + const sovereignGenesisGERImplementation = genesisSovereign.genesis.find(function (obj) { + return obj.contractName == "GlobalExitRootManagerL2SovereignChain"; + }); + // Change bridge implementation address to the one set at original sovereign genesis + const deployedBytecode = await ethers.provider.getCode(bridgeImplementationAddress as string); + bridgeImplementationAddress = sovereignGenesisBridgeImplementation.address; + await setCode(bridgeImplementationAddress as string, deployedBytecode); + await setNonce(bridgeImplementationAddress as string, 1); + /* + * deploy bridge proxy and initialize + */ + const transparentProxyFactory = await ethers.getContractFactory( + "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", + deployer + ); + const initializeEmptyDataProxy = "0x"; + const deployTransactionProxy = ( + await transparentProxyFactory.getDeployTransaction( + bridgeImplementationAddress as string, // must have bytecode + proxyAdminAddress as string, + initializeEmptyDataProxy + ) + ).data; + + let [proxyBridgeAddress] = await create2Deployment( + zkEVMDeployerContract, + salt, + deployTransactionProxy, + null, + deployer, + null + ); + + // Initialize bridge + const {sovereignParams} = createRollupParameters; + const sovereignBridgeContract = sovereignBridgeFactory.attach( + bridgeImplementationAddress as string + ) as BridgeL2SovereignChain; + let gasTokenMetadata, gasTokenAddress; + if ( + deployParameters.gasTokenAddress && + deployParameters.gasTokenAddress !== "" && + deployParameters.gasTokenAddress !== ethers.ZeroAddress + ) { + gasTokenMetadata = await sovereignBridgeContract.getTokenMetadata(deployParameters.gasTokenAddress); + gasTokenAddress = deployParameters.gasTokenAddress; + } else { + gasTokenMetadata = "0x"; + gasTokenAddress = ethers.ZeroAddress; + } + const initializeData = sovereignBridgeFactory.interface.encodeFunctionData( + "initialize(uint32,address,uint32,address,address,bytes,address,address,bool)", + [ + 1, //rollupID + gasTokenAddress, + deployParameters.gasTokenNetwork, //gasTokenNetwork, + sovereignGenesisGERProxy.address, // GlobalExitRootManager address + ethers.ZeroAddress, //polygonRollupManager + gasTokenMetadata, //gasTokenMetadata, + sovereignParams.bridgeManager, + sovereignParams.sovereignWETHAddress, + sovereignParams.sovereignWETHAddressIsNotMintable, + ] + ); + await deployer.sendTransaction({ + to: proxyBridgeAddress as string, + data: initializeData, + }); + // Check bytecode + expect(sovereignGenesisBridgeProxy.bytecode).to.be.equal(await ethers.provider.getCode(proxyBridgeAddress as string)); + // Check storage + for (const key in sovereignGenesisBridgeProxy.storage) { + expect(sovereignGenesisBridgeProxy.storage[key]).to.be.equal(await getStorageAt(proxyBridgeAddress as string, key)); + } + + // Import OZ manifest the deployed contracts, its enough to import just the proxy, the rest are imported automatically ( admin/impl) + await upgrades.forceImport(proxyBridgeAddress as string, sovereignBridgeFactory, "transparent" as any); + + /* + *Deployment Global exit root manager implementation, proxy and initialize + */ + const globalExitRootContractName = "GlobalExitRootManagerL2SovereignChain"; + const GERSovereignFactory = await ethers.getContractFactory(globalExitRootContractName, deployer); + const proxyGERContract = await upgrades.deployProxy(GERSovereignFactory, [sovereignParams.globalExitRootUpdater], { + constructorArgs: [proxyBridgeAddress as string], + unsafeAllow: ["constructor", "state-variable-immutable"], + }); + const proxyGERAddress = proxyGERContract.target; + let GERImplementationAddress = await upgrades.erc1967.getImplementationAddress(proxyGERAddress as string); + // Change GER implementation address to the one set at original sovereign genesis + const deployedGERBytecode = await ethers.provider.getCode(GERImplementationAddress as string); + GERImplementationAddress = sovereignGenesisGERImplementation.address; + await setCode(GERImplementationAddress as string, deployedGERBytecode); + await setNonce(GERImplementationAddress as string, 1); + await setStorageAt(proxyGERAddress as string, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", `0x000000000000000000000000${GERImplementationAddress.slice(2)}`); + expect(sovereignGenesisGERImplementation.bytecode).to.be.equal( + await ethers.provider.getCode(GERImplementationAddress) + ); + // Compare storage + for (const key in sovereignGenesisGERProxy.storage) { + const as = await getStorageAt(proxyGERAddress as string, key) + expect(sovereignGenesisGERProxy.storage[key]).to.be.equal( + await getStorageAt(proxyGERAddress as string, key) + ); + } + // Assert admin address + expect(await upgrades.erc1967.getAdminAddress(proxyGERAddress as string)).to.be.equal( + proxyAdminAddress + ); + expect(await upgrades.erc1967.getAdminAddress(proxyBridgeAddress as string)).to.be.equal(proxyAdminAddress); + + const timelockContractFactory = await ethers.getContractFactory("PolygonZkEVMTimelock", deployer); + const timelockContract = await timelockContractFactory.deploy( + minDelayTimelock, + [timelockAdminAddress], + [timelockAdminAddress], + timelockAdminAddress, + zkevmAddressL2 + ); + await timelockContract.waitForDeployment(); + const finalTimelockContractAddress = timelockContract.target; + + // Transfer ownership of the proxyAdmin to timelock + const proxyAdminInstance = proxyAdminFactory.attach(proxyAdminAddress as string) as ProxyAdmin; + await (await proxyAdminInstance.connect(deployer).transferOwnership(finalTimelockContractAddress as string)).wait(); + + // Recreate genesis with the current information: + + // ZKEVMDeployer + const zkEVMDeployerInfo = await getAddressInfo(zkEVMDeployerContract.target); + genesis.push({ + contractName: "PolygonZkEVMDeployer", + balance: "0", + nonce: zkEVMDeployerInfo.nonce.toString(), + address: finalZkEVMDeployerAddress, + bytecode: zkEVMDeployerInfo.bytecode, + storage: zkEVMDeployerInfo.storage, + }); + + // Proxy Admin + const proxyAdminInfo = await getAddressInfo(proxyAdminAddress as string); + genesis.push({ + contractName: "ProxyAdmin", + balance: "0", + nonce: proxyAdminInfo.nonce.toString(), + address: proxyAdminAddress, + bytecode: proxyAdminInfo.bytecode, + storage: proxyAdminInfo.storage, + }); + + // Bridge implementation + const bridgeImplementationInfo = await getAddressInfo(bridgeImplementationAddress as string); + genesis.push({ + contractName: `${bridgeContractName}`, + balance: "0", + nonce: bridgeImplementationInfo.nonce.toString(), + address: bridgeImplementationAddress, + bytecode: bridgeImplementationInfo.bytecode, + // storage: bridgeImplementationInfo.storage, implementation do not have storage + }); + + // Bridge proxy + const bridgeProxyInfo = await getAddressInfo(proxyBridgeAddress as string); + // Override admin and implementation slots: + bridgeProxyInfo.storage[_ADMIN_SLOT] = ethers.zeroPadValue(proxyAdminAddress as string, 32); + bridgeProxyInfo.storage[_IMPLEMENTATION_SLOT] = ethers.zeroPadValue(bridgeImplementationAddress as string, 32); + + genesis.push({ + contractName: `${bridgeContractName} proxy`, + balance: balanceBridge, + nonce: bridgeProxyInfo.nonce.toString(), + address: proxyBridgeAddress, + bytecode: bridgeProxyInfo.bytecode, + storage: bridgeProxyInfo.storage, + }); + + // GER Manager implementation + const implGlobalExitRootL2Info = await getAddressInfo(GERImplementationAddress as string); + + genesis.push({ + contractName: `${globalExitRootContractName}`, + balance: "0", + nonce: implGlobalExitRootL2Info.nonce.toString(), + address: GERImplementationAddress, + bytecode: implGlobalExitRootL2Info.bytecode, + }); + + // polygonZkEVMGlobalExitRootL2 proxy + const proxyGlobalExitRootL2Info = await getAddressInfo(proxyGERAddress as string); + + proxyGlobalExitRootL2Info.storage[_ADMIN_SLOT] = ethers.zeroPadValue(proxyAdminAddress as string, 32); + proxyGlobalExitRootL2Info.storage[_IMPLEMENTATION_SLOT] = ethers.zeroPadValue( + GERImplementationAddress as string, + 32 + ); + + genesis.push({ + contractName: `${globalExitRootContractName} proxy`, + balance: "0", + nonce: proxyGlobalExitRootL2Info.nonce.toString(), + address: proxyGERAddress, + bytecode: proxyGlobalExitRootL2Info.bytecode, + storage: proxyGlobalExitRootL2Info.storage, + }); + + // Timelock + const timelockInfo = await getAddressInfo(timelockContract.target); + + /* + * Since roles are used, most storage is written in pseudoRandom storage slots + * bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE"); + * bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); + * bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + * bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); + */ + const timelockRolesHash = [ + ethers.id("TIMELOCK_ADMIN_ROLE"), + ethers.id("PROPOSER_ROLE"), + ethers.id("EXECUTOR_ROLE"), + ethers.id("CANCELLER_ROLE"), + ]; + + for (let i = 0; i < timelockRolesHash.length; i++) { + const rolesMappingStoragePositionStruct = 0; + const storagePosition = ethers.solidityPackedKeccak256( + ["uint256", "uint256"], + [timelockRolesHash[i], rolesMappingStoragePositionStruct] + ); + + // check timelock address manager, and timelock address itself + const addressArray = [timelockAdminAddress, timelockContract.target]; + for (let j = 0; j < addressArray.length; j++) { + const storagePositionRole = ethers.solidityPackedKeccak256( + ["uint256", "uint256"], + [addressArray[j], storagePosition] + ); + const valueRole = await ethers.provider.getStorage(timelockContract.target, storagePositionRole); + if (valueRole !== "0x0000000000000000000000000000000000000000000000000000000000000000") { + timelockInfo.storage[storagePositionRole] = valueRole; + } + } + const roleAdminSlot = ethers.zeroPadValue(ethers.toQuantity(ethers.toBigInt(storagePosition) + 1n), 32); + const valueRoleAdminSlot = await ethers.provider.getStorage(timelockContract.target, roleAdminSlot); + if (valueRoleAdminSlot !== "0x0000000000000000000000000000000000000000000000000000000000000000") { + timelockInfo.storage[roleAdminSlot] = valueRoleAdminSlot; + } + } + + genesis.push({ + contractName: "PolygonZkEVMTimelock", + balance: "0", + nonce: timelockInfo.nonce.toString(), + address: finalTimelockContractAddress, + bytecode: timelockInfo.bytecode, + storage: timelockInfo.storage, + }); + + // Put nonces on deployers + + // Keyless deployer + genesis.push({ + accountName: "keyless Deployer", + balance: "0", + nonce: "1", + address: finalKeylessDeployer, + }); + + // deployer + const deployerInfo = await getAddressInfo(deployer.address); + genesis.push({ + accountName: "deployer", + balance: "0", + nonce: deployerInfo.nonce.toString(), + address: finalDeployer, + }); + + if (deployParameters.test) { + // Add tester account with ether + genesis[genesis.length - 1].balance = "100000000000000000000000"; + } + + // calculate root + const poseidon = await getPoseidon(); + const {F} = poseidon; + const db = new MemDB(F); + const genesisRoot = [F.zero, F.zero, F.zero, F.zero]; + const accHashInput = [F.zero, F.zero, F.zero, F.zero]; + const defaultChainId = 1000; + + const zkEVMDB = await ZkEVMDB.newZkEVM( + db, + poseidon, + genesisRoot, + accHashInput, + genesis, + null, + null, + defaultChainId + ); + + fs.writeFileSync( + pathOutputJson, + JSON.stringify( + { + root: smtUtils.h4toString(zkEVMDB.stateRoot), + genesis: genesis, + }, + null, + 1 + ) + ); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); + +async function getAddressInfo(address: string | Addressable) { + const nonce = await ethers.provider.getTransactionCount(address); + const bytecode = await ethers.provider.getCode(address); + + const storage = {} as { + [key: string]: number | string; + }; + + for (let i = 0; i < 200; i++) { + const storageValue = await ethers.provider.getStorage(address, i); + if (storageValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") { + storage[ethers.toBeHex(i, 32)] = storageValue; + } + } + + const valueAdminSlot = await ethers.provider.getStorage(address, _ADMIN_SLOT); + if (valueAdminSlot !== "0x0000000000000000000000000000000000000000000000000000000000000000") { + storage[_ADMIN_SLOT] = valueAdminSlot; + } + const valueImplementationSlot = await ethers.provider.getStorage(address, _IMPLEMENTATION_SLOT); + if (valueImplementationSlot !== "0x0000000000000000000000000000000000000000000000000000000000000000") { + storage[_IMPLEMENTATION_SLOT] = valueImplementationSlot; + } + + return {nonce, bytecode, storage}; +} From 43b0f16504f0eb02e7ed7cfee7632da2431c1616 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 7 Nov 2024 13:43:11 +0100 Subject: [PATCH 02/12] Change comment about token address --- contracts/PolygonZkEVMBridge.sol | 8 +- contracts/mocks/DepositContractMock.sol | 2 +- contracts/mocks/PolygonZkEVMBridgeMock.sol | 2 +- contracts/v2/PolygonZkEVMBridgeV2.sol | 8 +- contracts/v2/lib/DepositContractV2.sol | 2 +- contracts/v2/mocks/BridgeReceiverMock.sol | 2 +- .../BridgeL2SovereignChain.sol | 2 +- docs/L2/PolygonZkEVMBridgeL2.md | 264 +++++++------- docs/PolygonZkEVMBridge.md | 8 +- docs/lib/DepositContract.md | 53 +-- docs/v2/PolygonZkEVMBridgeV2.md | 325 ++++++++++-------- docs/v2/lib/DepositContractV2.md | 23 +- docs/v2/mocks/BridgeReceiverMock.md | 53 +-- 13 files changed, 418 insertions(+), 334 deletions(-) diff --git a/contracts/PolygonZkEVMBridge.sol b/contracts/PolygonZkEVMBridge.sol index 1892f6b26..dadf50f12 100644 --- a/contracts/PolygonZkEVMBridge.sol +++ b/contracts/PolygonZkEVMBridge.sol @@ -139,7 +139,7 @@ contract PolygonZkEVMBridge is * @param destinationNetwork Network destination * @param destinationAddress Address destination * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether + * @param token Token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not * @param permitData Raw data of the call `permit` of the token */ @@ -306,7 +306,7 @@ contract PolygonZkEVMBridge is * @param mainnetExitRoot Mainnet exit root * @param rollupExitRoot Rollup exit root * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param destinationNetwork Network destination * @param destinationAddress Address destination * @param amount Amount of tokens @@ -483,7 +483,7 @@ contract PolygonZkEVMBridge is * Since the metadata has relevance in the address deployed, this function will not return a valid * wrapped address if the metadata provided is not the original one. * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param name Name of the token * @param symbol Symbol of the token * @param decimals Decimals of the token @@ -520,7 +520,7 @@ contract PolygonZkEVMBridge is /** * @notice Returns the address of a wrapper using the token information if already exist * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token */ function getTokenWrappedAddress( uint32 originNetwork, diff --git a/contracts/mocks/DepositContractMock.sol b/contracts/mocks/DepositContractMock.sol index ff2ebfad2..404731b04 100644 --- a/contracts/mocks/DepositContractMock.sol +++ b/contracts/mocks/DepositContractMock.sol @@ -18,7 +18,7 @@ contract DepositContractMock is DepositContract { * @notice Given the leaf data returns the leaf value * @param leafType Leaf type * @param originNetwork Origin Network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param destinationNetwork Destination network * @param destinationAddress Destination address * @param amount Amount of tokens diff --git a/contracts/mocks/PolygonZkEVMBridgeMock.sol b/contracts/mocks/PolygonZkEVMBridgeMock.sol index 8a59ef889..fcb00505e 100644 --- a/contracts/mocks/PolygonZkEVMBridgeMock.sol +++ b/contracts/mocks/PolygonZkEVMBridgeMock.sol @@ -42,7 +42,7 @@ contract PolygonZkEVMBridgeMock is PolygonZkEVMBridge, OwnableUpgradeable { * @param destinationNetwork Network destination * @param destinationAddress Address destination * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether + * @param token Token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param permitData Raw data of the call `permit` of the token */ function bridgeAsset( diff --git a/contracts/v2/PolygonZkEVMBridgeV2.sol b/contracts/v2/PolygonZkEVMBridgeV2.sol index 073e4f6a0..3045b642d 100644 --- a/contracts/v2/PolygonZkEVMBridgeV2.sol +++ b/contracts/v2/PolygonZkEVMBridgeV2.sol @@ -205,7 +205,7 @@ contract PolygonZkEVMBridgeV2 is * @param destinationNetwork Network destination * @param destinationAddress Address destination * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether + * @param token Token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not * @param permitData Raw data of the call `permit` of the token */ @@ -689,7 +689,7 @@ contract PolygonZkEVMBridgeV2 is * Since the metadata has relevance in the address deployed, this function will not return a valid * wrapped address if the metadata provided is not the original one. * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param name Name of the token * @param symbol Symbol of the token * @param decimals Decimals of the token @@ -726,7 +726,7 @@ contract PolygonZkEVMBridgeV2 is /** * @notice Returns the address of a wrapper using the token information if already exist * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token */ function getTokenWrappedAddress( uint32 originNetwork, @@ -1182,7 +1182,7 @@ contract PolygonZkEVMBridgeV2 is * Since the metadata has relevance in the address deployed, this function will not return a valid * wrapped address if the metadata provided is not the original one. * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param token Address of the token to calculate the wrapper address */ function calculateTokenWrapperAddress( diff --git a/contracts/v2/lib/DepositContractV2.sol b/contracts/v2/lib/DepositContractV2.sol index 2a2313fec..2606578d2 100644 --- a/contracts/v2/lib/DepositContractV2.sol +++ b/contracts/v2/lib/DepositContractV2.sol @@ -13,7 +13,7 @@ contract DepositContractV2 is ReentrancyGuardUpgradeable, DepositContractBase { * @notice Given the leaf data returns the leaf value * @param leafType Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message * @param originNetwork Origin Network - * @param originAddress [0] Origin token address, 0 address is reserved for ether, [1] msg.sender of the message + * @param originAddress [0] Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token, [1] msg.sender of the message * @param destinationNetwork Destination network * @param destinationAddress Destination address * @param amount [0] Amount of tokens/ether, [1] Amount of ether diff --git a/contracts/v2/mocks/BridgeReceiverMock.sol b/contracts/v2/mocks/BridgeReceiverMock.sol index 11364419b..46beea8dc 100644 --- a/contracts/v2/mocks/BridgeReceiverMock.sol +++ b/contracts/v2/mocks/BridgeReceiverMock.sol @@ -59,7 +59,7 @@ contract BridgeReceiverMock { * @param mainnetExitRoot Mainnet exit root * @param rollupExitRoot Rollup exit root * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param destinationNetwork Network destination * @param destinationAddress Address destination * @param amount Amount of tokens diff --git a/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol b/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol index 590ed7d84..a83152bd8 100644 --- a/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol +++ b/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol @@ -212,7 +212,7 @@ contract BridgeL2SovereignChain is * @notice The tokenInfoToWrappedToken mapping value is replaced by the new sovereign address but it's not the case for the wrappedTokenToTokenInfo map where the value is added, this way user will always be able to withdraw their tokens * @notice The number of decimals between sovereign token and origin token is not checked, it doesn't affect the bridge functionality but the UI. * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token * @param sovereignTokenAddress Address of the sovereign wrapped token * @param isNotMintable Flag to indicate if the wrapped token is not mintable */ diff --git a/docs/L2/PolygonZkEVMBridgeL2.md b/docs/L2/PolygonZkEVMBridgeL2.md index 435aca286..27a76a672 100644 --- a/docs/L2/PolygonZkEVMBridgeL2.md +++ b/docs/L2/PolygonZkEVMBridgeL2.md @@ -1,9 +1,10 @@ PolygonZkEVMBridge that will be deployed on both networks Ethereum and Polygon zkEVM Contract responsible to manage the token interactions with other networks - ## Functions + ### initialize + ```solidity function initialize( uint32 _networkID, @@ -11,18 +12,20 @@ Contract responsible to manage the token interactions with other networks address _polygonZkEVMaddress ) external ``` + The value of `_polygonZkEVMaddress` on the L2 deployment of the contract will be address(0), so emergency state is not possible for the L2 deployment of the bridge, intentionally #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`_networkID` | uint32 | networkID -|`_globalExitRootManager` | contract IBasePolygonZkEVMGlobalExitRoot | global exit root manager address -|`_polygonZkEVMaddress` | address | polygonZkEVM address +| Name | Type | Description | +| :----------------------- | :--------------------------------------- | :------------------------------- | +| `_networkID` | uint32 | networkID | +| `_globalExitRootManager` | contract IBasePolygonZkEVMGlobalExitRoot | global exit root manager address | +| `_polygonZkEVMaddress` | address | polygonZkEVM address | ### bridgeAsset + ```solidity function bridgeAsset( uint32 destinationNetwork, @@ -33,20 +36,22 @@ emergency state is not possible for the L2 deployment of the bridge, intentional bytes permitData ) public ``` -Deposit add a new leaf to the merkle tree +Deposit add a new leaf to the merkle tree #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amount` | uint256 | Amount of tokens -|`token` | address | Token address, 0 address is reserved for ether -|`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not -|`permitData` | bytes | Raw data of the call `permit` of the token + +| Name | Type | Description | +| :-------------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amount` | uint256 | Amount of tokens | +| `token` | address | token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | +| `forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not | +| `permitData` | bytes | Raw data of the call `permit` of the token | ### bridgeMessage + ```solidity function bridgeMessage( uint32 destinationNetwork, @@ -56,19 +61,21 @@ Deposit add a new leaf to the merkle tree bytes metadata ) external ``` -Bridge message and send ETH value +Bridge message and send ETH value #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amountWETH` | uint256 | Amount of WETH tokens -|`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not -|`metadata` | bytes | Message metadata + +| Name | Type | Description | +| :-------------------------- | :------ | :------------------------------------------------------ | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amountWETH` | uint256 | Amount of WETH tokens | +| `forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not | +| `metadata` | bytes | Message metadata | ### claimAsset + ```solidity function claimAsset( bytes32[32] smtProof, @@ -83,24 +90,26 @@ Bridge message and send ETH value bytes metadata ) external ``` -Verify merkle proof and withdraw tokens/ether +Verify merkle proof and withdraw tokens/ether #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProof` | bytes32[32] | Smt proof -|`index` | uint32 | Index of the leaf -|`mainnetExitRoot` | bytes32 | Mainnet exit root -|`rollupExitRoot` | bytes32 | Rollup exit root -|`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amount` | uint256 | Amount of tokens -|`metadata` | bytes | Abi encoded metadata if any, empty otherwise + +| Name | Type | Description | +| :------------------- | :---------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `smtProof` | bytes32[32] | Smt proof | +| `index` | uint32 | Index of the leaf | +| `mainnetExitRoot` | bytes32 | Mainnet exit root | +| `rollupExitRoot` | bytes32 | Rollup exit root | +| `originNetwork` | uint32 | Origin network | +| `originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amount` | uint256 | Amount of tokens | +| `metadata` | bytes | Abi encoded metadata if any, empty otherwise | ### claimMessage + ```solidity function claimMessage( bytes32[32] smtProof, @@ -115,27 +124,29 @@ Verify merkle proof and withdraw tokens/ether bytes metadata ) external ``` + Verify merkle proof and execute message If the receiving address is an EOA, the call will result as a success Which means that the amount of ether will be transferred correctly, but the message will not trigger any execution - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProof` | bytes32[32] | Smt proof -|`index` | uint32 | Index of the leaf -|`mainnetExitRoot` | bytes32 | Mainnet exit root -|`rollupExitRoot` | bytes32 | Rollup exit root -|`originNetwork` | uint32 | Origin network -|`originAddress` | address | Origin address -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amount` | uint256 | message value -|`metadata` | bytes | Abi encoded metadata if any, empty otherwise + +| Name | Type | Description | +| :------------------- | :---------- | :------------------------------------------- | +| `smtProof` | bytes32[32] | Smt proof | +| `index` | uint32 | Index of the leaf | +| `mainnetExitRoot` | bytes32 | Mainnet exit root | +| `rollupExitRoot` | bytes32 | Rollup exit root | +| `originNetwork` | uint32 | Origin network | +| `originAddress` | address | Origin address | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amount` | uint256 | message value | +| `metadata` | bytes | Abi encoded metadata if any, empty otherwise | ### precalculatedWrapperAddress + ```solidity function precalculatedWrapperAddress( uint32 originNetwork, @@ -145,58 +156,62 @@ will not trigger any execution uint8 decimals ) external returns (address) ``` + Returns the precalculated address of a wrapper using the token information Note Updating the metadata of a token is not supported. Since the metadata has relevance in the address deployed, this function will not return a valid wrapped address if the metadata provided is not the original one. - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether -|`name` | string | Name of the token -|`symbol` | string | Symbol of the token -|`decimals` | uint8 | Decimals of the token + +| Name | Type | Description | +| :------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `originNetwork` | uint32 | Origin network | +| `originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | +| `name` | string | Name of the token | +| `symbol` | string | Symbol of the token | +| `decimals` | uint8 | Decimals of the token | ### getTokenWrappedAddress + ```solidity function getTokenWrappedAddress( uint32 originNetwork, address originTokenAddress ) external returns (address) ``` -Returns the address of a wrapper using the token information if already exist +Returns the address of a wrapper using the token information if already exist #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether + +| Name | Type | Description | +| :------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `originNetwork` | uint32 | Origin network | +| `originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | ### activateEmergencyState + ```solidity function activateEmergencyState( ) external ``` -Function to activate the emergency state - " Only can be called by the Polygon ZK-EVM in extreme situations - +Function to activate the emergency state +" Only can be called by the Polygon ZK-EVM in extreme situations ### deactivateEmergencyState + ```solidity function deactivateEmergencyState( ) external ``` -Function to deactivate the emergency state - " Only can be called by the Polygon ZK-EVM +Function to deactivate the emergency state +" Only can be called by the Polygon ZK-EVM +### \_verifyLeaf -### _verifyLeaf ```solidity function _verifyLeaf( bytes32[32] smtProof, @@ -212,133 +227,147 @@ Function to deactivate the emergency state uint8 leafType ) internal ``` -Verify leaf and checks that it has not been claimed +Verify leaf and checks that it has not been claimed #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProof` | bytes32[32] | Smt proof -|`index` | uint32 | Index of the leaf -|`mainnetExitRoot` | bytes32 | Mainnet exit root -|`rollupExitRoot` | bytes32 | Rollup exit root -|`originNetwork` | uint32 | Origin network -|`originAddress` | address | Origin address -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amount` | uint256 | Amount of tokens -|`metadata` | bytes | Abi encoded metadata if any, empty otherwise -|`leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message + +| Name | Type | Description | +| :------------------- | :---------- | :----------------------------------------------------------- | +| `smtProof` | bytes32[32] | Smt proof | +| `index` | uint32 | Index of the leaf | +| `mainnetExitRoot` | bytes32 | Mainnet exit root | +| `rollupExitRoot` | bytes32 | Rollup exit root | +| `originNetwork` | uint32 | Origin network | +| `originAddress` | address | Origin address | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amount` | uint256 | Amount of tokens | +| `metadata` | bytes | Abi encoded metadata if any, empty otherwise | +| `leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message | ### isClaimed + ```solidity function isClaimed( uint256 index ) external returns (bool) ``` -Function to check if an index is claimed or not +Function to check if an index is claimed or not #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`index` | uint256 | Index + +| Name | Type | Description | +| :------ | :------ | :---------- | +| `index` | uint256 | Index | ### updateGlobalExitRoot + ```solidity function updateGlobalExitRoot( ) external ``` -Function to update the globalExitRoot if the last deposit is not submitted +Function to update the globalExitRoot if the last deposit is not submitted +### \_updateGlobalExitRoot -### _updateGlobalExitRoot ```solidity function _updateGlobalExitRoot( ) internal ``` -Function to update the globalExitRoot +Function to update the globalExitRoot +### \_permit -### _permit ```solidity function _permit( address amount, uint256 permitData ) internal ``` -Function to call token permit method of extended ERC20 - + @param token ERC20 token address +Function to call token permit method of extended ERC20 + @param token ERC20 token address #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`amount` | address | Quantity that is expected to be allowed -|`permitData` | uint256 | Raw data of the call `permit` of the token -### _safeSymbol +| Name | Type | Description | +| :----------- | :------ | :----------------------------------------- | +| `amount` | address | Quantity that is expected to be allowed | +| `permitData` | uint256 | Raw data of the call `permit` of the token | + +### \_safeSymbol + ```solidity function _safeSymbol( address token ) internal returns (string) ``` -Provides a safe ERC20.symbol version which returns 'NO_SYMBOL' as fallback string +Provides a safe ERC20.symbol version which returns 'NO_SYMBOL' as fallback string #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | The address of the ERC-20 token contract -### _safeName +| Name | Type | Description | +| :------ | :------ | :--------------------------------------- | +| `token` | address | The address of the ERC-20 token contract | + +### \_safeName + ```solidity function _safeName( address token ) internal returns (string) ``` - Provides a safe ERC20.name version which returns 'NO_NAME' as fallback string. +Provides a safe ERC20.name version which returns 'NO_NAME' as fallback string. #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | The address of the ERC-20 token contract. -### _safeDecimals +| Name | Type | Description | +| :------ | :------ | :---------------------------------------- | +| `token` | address | The address of the ERC-20 token contract. | + +### \_safeDecimals + ```solidity function _safeDecimals( address token ) internal returns (uint8) ``` + Provides a safe ERC20.decimals version which returns '18' as fallback value. Note Tokens with (decimals > 255) are not supported - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | The address of the ERC-20 token contract -### _returnDataToString +| Name | Type | Description | +| :------ | :------ | :--------------------------------------- | +| `token` | address | The address of the ERC-20 token contract | + +### \_returnDataToString + ```solidity function _returnDataToString( bytes data ) internal returns (string) ``` + Function to convert returned data to string returns 'NOT_VALID_ENCODING' as fallback value. - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`data` | bytes | returned data + +| Name | Type | Description | +| :----- | :---- | :------------ | +| `data` | bytes | returned data | ## Events + ### BridgeEvent + ```solidity event BridgeEvent( ) @@ -347,6 +376,7 @@ returns 'NOT_VALID_ENCODING' as fallback value. Emitted when bridge assets or messages to another network ### ClaimEvent + ```solidity event ClaimEvent( ) @@ -355,10 +385,10 @@ Emitted when bridge assets or messages to another network Emitted when a claim is done from another network ### NewWrappedToken + ```solidity event NewWrappedToken( ) ``` Emitted when a new wrapped token is created - diff --git a/docs/PolygonZkEVMBridge.md b/docs/PolygonZkEVMBridge.md index 5a94edf48..a0d9bc9ce 100644 --- a/docs/PolygonZkEVMBridge.md +++ b/docs/PolygonZkEVMBridge.md @@ -46,7 +46,7 @@ do not call any external address in that case |`destinationNetwork` | uint32 | Network destination |`destinationAddress` | address | Address destination |`amount` | uint256 | Amount of tokens -|`token` | address | Token address, 0 address is reserved for ether +|`token` | address | Token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token |`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not |`permitData` | bytes | Raw data of the call `permit` of the token @@ -96,7 +96,7 @@ Verify merkle proof and withdraw tokens/ether |`mainnetExitRoot` | bytes32 | Mainnet exit root |`rollupExitRoot` | bytes32 | Rollup exit root |`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether +|`originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token |`destinationNetwork` | uint32 | Network destination |`destinationAddress` | address | Address destination |`amount` | uint256 | Amount of tokens @@ -157,7 +157,7 @@ wrapped address if the metadata provided is not the original one. | Name | Type | Description | | :--- | :--- | :------------------------------------------------------------------- | |`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether +|`originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token |`name` | string | Name of the token |`symbol` | string | Symbol of the token |`decimals` | uint8 | Decimals of the token @@ -176,7 +176,7 @@ Returns the address of a wrapper using the token information if already exist | Name | Type | Description | | :--- | :--- | :------------------------------------------------------------------- | |`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether +|`originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token ### activateEmergencyState ```solidity diff --git a/docs/lib/DepositContract.md b/docs/lib/DepositContract.md index 09007366e..ade0c9e44 100644 --- a/docs/lib/DepositContract.md +++ b/docs/lib/DepositContract.md @@ -1,32 +1,35 @@ This contract will be used as a helper for all the sparse merkle tree related functions Based on the implementation of the deposit eth2.0 contract https://github.com/ethereum/consensus-specs/blob/dev/solidity_deposit_contract/deposit_contract.sol - ## Functions + ### getDepositRoot + ```solidity function getDepositRoot( ) public returns (bytes32) ``` -Computes and returns the merkle root +Computes and returns the merkle root +### \_deposit -### _deposit ```solidity function _deposit( bytes32 leafHash ) internal ``` -Add a new leaf to the merkle tree +Add a new leaf to the merkle tree #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`leafHash` | bytes32 | Leaf hash + +| Name | Type | Description | +| :--------- | :------ | :---------- | +| `leafHash` | bytes32 | Leaf hash | ### verifyMerkleProof + ```solidity function verifyMerkleProof( bytes32 leafHash, @@ -35,18 +38,20 @@ Add a new leaf to the merkle tree bytes32 root ) public returns (bool) ``` -Verify merkle proof +Verify merkle proof #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`leafHash` | bytes32 | Leaf hash -|`smtProof` | bytes32[32] | Smt proof -|`index` | uint32 | Index of the leaf -|`root` | bytes32 | Merkle root + +| Name | Type | Description | +| :--------- | :---------- | :---------------- | +| `leafHash` | bytes32 | Leaf hash | +| `smtProof` | bytes32[32] | Smt proof | +| `index` | uint32 | Index of the leaf | +| `root` | bytes32 | Merkle root | ### getLeafValue + ```solidity function getLeafValue( uint8 leafType, @@ -58,17 +63,17 @@ Verify merkle proof bytes32 metadataHash ) public returns (bytes32) ``` -Given the leaf data returns the leaf value +Given the leaf data returns the leaf value #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message -|`originNetwork` | uint32 | Origin Network -|`originAddress` | address | [0] Origin token address, 0 address is reserved for ether, [1] msg.sender of the message -|`destinationNetwork` | uint32 | Destination network -|`destinationAddress` | address | Destination address -|`amount` | uint256 | [0] Amount of tokens/ether, [1] Amount of ether -|`metadataHash` | bytes32 | Hash of the metadata +| Name | Type | Description | +| :------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message | +| `originNetwork` | uint32 | Origin Network | +| `originAddress` | address | [0] Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token, [1] msg.sender of the message | +| `destinationNetwork` | uint32 | Destination network | +| `destinationAddress` | address | Destination address | +| `amount` | uint256 | [0] Amount of tokens/ether, [1] Amount of ether | +| `metadataHash` | bytes32 | Hash of the metadata | diff --git a/docs/v2/PolygonZkEVMBridgeV2.md b/docs/v2/PolygonZkEVMBridgeV2.md index c42e14a56..d05605fbd 100644 --- a/docs/v2/PolygonZkEVMBridgeV2.md +++ b/docs/v2/PolygonZkEVMBridgeV2.md @@ -1,18 +1,19 @@ PolygonZkEVMBridge that will be deployed on Ethereum and all Polygon rollups Contract responsible to manage the token interactions with other networks - ## Functions + ### constructor + ```solidity function constructor( ) public ``` -Disable initalizers on the implementation following the best practices - +Disable initalizers on the implementation following the best practices ### initialize + ```solidity function initialize( uint32 _networkID, @@ -23,21 +24,23 @@ Disable initalizers on the implementation following the best practices bytes _gasTokenMetadata ) external ``` + The value of `_polygonRollupManager` on the L2 deployment of the contract will be address(0), so emergency state is not possible for the L2 deployment of the bridge, intentionally - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`_networkID` | uint32 | networkID -|`_gasTokenAddress` | address | gas token address -|`_gasTokenNetwork` | uint32 | gas token network -|`_globalExitRootManager` | contract IBasePolygonZkEVMGlobalExitRoot | global exit root manager address -|`_polygonRollupManager` | address | polygonZkEVM address -|`_gasTokenMetadata` | bytes | Abi encoded gas token metadata + +| Name | Type | Description | +| :----------------------- | :--------------------------------------- | :------------------------------- | +| `_networkID` | uint32 | networkID | +| `_gasTokenAddress` | address | gas token address | +| `_gasTokenNetwork` | uint32 | gas token network | +| `_globalExitRootManager` | contract IBasePolygonZkEVMGlobalExitRoot | global exit root manager address | +| `_polygonRollupManager` | address | polygonZkEVM address | +| `_gasTokenMetadata` | bytes | Abi encoded gas token metadata | ### bridgeAsset + ```solidity function bridgeAsset( uint32 destinationNetwork, @@ -48,6 +51,7 @@ emergency state is not possible for the L2 deployment of the bridge, intentional bytes permitData ) public ``` + Deposit add a new leaf to the merkle tree note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call Reducing the supply of tokens on this contract, and actually locking tokens in the contract. @@ -55,18 +59,19 @@ Therefore we recommend to third parties bridges that if they do implement reentr do not call any external address in that case note User/UI must be aware of the existing/available networks when choosing the destination network - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amount` | uint256 | Amount of tokens -|`token` | address | Token address, 0 address is reserved for ether -|`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not -|`permitData` | bytes | Raw data of the call `permit` of the token + +| Name | Type | Description | +| :-------------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amount` | uint256 | Amount of tokens | +| `token` | address | token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | +| `forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not | +| `permitData` | bytes | Raw data of the call `permit` of the token | ### bridgeMessage + ```solidity function bridgeMessage( uint32 destinationNetwork, @@ -75,19 +80,21 @@ note User/UI must be aware of the existing/available networks when choosing the bytes metadata ) external ``` + Bridge message and send ETH value note User/UI must be aware of the existing/available networks when choosing the destination network - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not -|`metadata` | bytes | Message metadata + +| Name | Type | Description | +| :-------------------------- | :------ | :------------------------------------------------------ | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not | +| `metadata` | bytes | Message metadata | ### bridgeMessageWETH + ```solidity function bridgeMessageWETH( uint32 destinationNetwork, @@ -97,20 +104,22 @@ note User/UI must be aware of the existing/available networks when choosing the bytes metadata ) external ``` + Bridge message and send ETH value note User/UI must be aware of the existing/available networks when choosing the destination network - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amountWETH` | uint256 | Amount of WETH tokens -|`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not -|`metadata` | bytes | Message metadata -### _bridgeMessage +| Name | Type | Description | +| :-------------------------- | :------ | :------------------------------------------------------ | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amountWETH` | uint256 | Amount of WETH tokens | +| `forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not | +| `metadata` | bytes | Message metadata | + +### \_bridgeMessage + ```solidity function _bridgeMessage( uint32 destinationNetwork, @@ -120,19 +129,21 @@ note User/UI must be aware of the existing/available networks when choosing the bytes metadata ) internal ``` -Bridge message and send ETH value +Bridge message and send ETH value #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`destinationNetwork` | uint32 | Network destination -|`destinationAddress` | address | Address destination -|`amountEther` | uint256 | Amount of ether along with the message -|`forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not -|`metadata` | bytes | Message metadata + +| Name | Type | Description | +| :-------------------------- | :------ | :------------------------------------------------------ | +| `destinationNetwork` | uint32 | Network destination | +| `destinationAddress` | address | Address destination | +| `amountEther` | uint256 | Amount of ether along with the message | +| `forceUpdateGlobalExitRoot` | bool | Indicates if the new global exit root is updated or not | +| `metadata` | bytes | Message metadata | ### claimAsset + ```solidity function claimAsset( bytes32[32] smtProofLocalExitRoot, @@ -148,17 +159,19 @@ Bridge message and send ETH value bytes metadata ) external ``` -Verify merkle proof and withdraw tokens/ether +Verify merkle proof and withdraw tokens/ether #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the network exit root -|`smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root -|`globalIndex` | uint256 | Global index is defined as: -| 191 bits | 1 bit | 32 bits | 32 bits | -| 0 | mainnetFlag | rollupIndex | localRootIndex | + +| Name | Type | Description | +| :----------------------- | :---------- | :----------------------------------------------------------------------- | -------------- | +| `smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the network exit root | +| `smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root | +| `globalIndex` | uint256 | Global index is defined as: | +| 191 bits | 1 bit | 32 bits | 32 bits | +| 0 | mainnetFlag | rollupIndex | localRootIndex | + note that only the rollup index will be used only in case the mainnet flag is 0 note that global index do not assert the unused bits to 0. This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract @@ -166,13 +179,14 @@ to avoid possible synch attacks |`mainnetExitRoot` | bytes32 | Mainnet exit root |`rollupExitRoot` | bytes32 | Rollup exit root |`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether +|`originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token |`destinationNetwork` | uint32 | Network destination |`destinationAddress` | address | Address destination |`amount` | uint256 | Amount of tokens |`metadata` | bytes | Abi encoded metadata if any, empty otherwise ### claimMessage + ```solidity function claimMessage( bytes32[32] smtProofLocalExitRoot, @@ -188,20 +202,22 @@ to avoid possible synch attacks bytes metadata ) external ``` + Verify merkle proof and execute message If the receiving address is an EOA, the call will result as a success Which means that the amount of ether will be transferred correctly, but the message will not trigger any execution - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the exit root -|`smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root -|`globalIndex` | uint256 | Global index is defined as: -| 191 bits | 1 bit | 32 bits | 32 bits | -| 0 | mainnetFlag | rollupIndex | localRootIndex | + +| Name | Type | Description | +| :----------------------- | :---------- | :----------------------------------------------------------------------- | -------------- | +| `smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the exit root | +| `smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root | +| `globalIndex` | uint256 | Global index is defined as: | +| 191 bits | 1 bit | 32 bits | 32 bits | +| 0 | mainnetFlag | rollupIndex | localRootIndex | + note that only the rollup index will be used only in case the mainnet flag is 0 note that global index do not assert the unused bits to 0. This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract @@ -216,6 +232,7 @@ to avoid possible synch attacks |`metadata` | bytes | Abi encoded metadata if any, empty otherwise ### precalculatedWrapperAddress + ```solidity function precalculatedWrapperAddress( uint32 originNetwork, @@ -225,58 +242,62 @@ to avoid possible synch attacks uint8 decimals ) public returns (address) ``` + Returns the precalculated address of a wrapper using the token information Note Updating the metadata of a token is not supported. Since the metadata has relevance in the address deployed, this function will not return a valid wrapped address if the metadata provided is not the original one. - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether -|`name` | string | Name of the token -|`symbol` | string | Symbol of the token -|`decimals` | uint8 | Decimals of the token + +| Name | Type | Description | +| :------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `originNetwork` | uint32 | Origin network | +| `originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | +| `name` | string | Name of the token | +| `symbol` | string | Symbol of the token | +| `decimals` | uint8 | Decimals of the token | ### getTokenWrappedAddress + ```solidity function getTokenWrappedAddress( uint32 originNetwork, address originTokenAddress ) external returns (address) ``` -Returns the address of a wrapper using the token information if already exist +Returns the address of a wrapper using the token information if already exist #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether + +| Name | Type | Description | +| :------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `originNetwork` | uint32 | Origin network | +| `originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | ### activateEmergencyState + ```solidity function activateEmergencyState( ) external ``` -Function to activate the emergency state - " Only can be called by the Polygon ZK-EVM in extreme situations - +Function to activate the emergency state +" Only can be called by the Polygon ZK-EVM in extreme situations ### deactivateEmergencyState + ```solidity function deactivateEmergencyState( ) external ``` -Function to deactivate the emergency state - " Only can be called by the Polygon ZK-EVM +Function to deactivate the emergency state +" Only can be called by the Polygon ZK-EVM +### \_verifyLeaf -### _verifyLeaf ```solidity function _verifyLeaf( bytes32[32] smtProofLocalExitRoot, @@ -287,160 +308,178 @@ Function to deactivate the emergency state bytes32 leafValue ) internal ``` -Verify leaf and checks that it has not been claimed +Verify leaf and checks that it has not been claimed #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProofLocalExitRoot` | bytes32[32] | Smt proof -|`smtProofRollupExitRoot` | bytes32[32] | Smt proof -|`globalIndex` | uint256 | Index of the leaf -|`mainnetExitRoot` | bytes32 | Mainnet exit root -|`rollupExitRoot` | bytes32 | Rollup exit root -|`leafValue` | bytes32 | leaf value + +| Name | Type | Description | +| :----------------------- | :---------- | :---------------- | +| `smtProofLocalExitRoot` | bytes32[32] | Smt proof | +| `smtProofRollupExitRoot` | bytes32[32] | Smt proof | +| `globalIndex` | uint256 | Index of the leaf | +| `mainnetExitRoot` | bytes32 | Mainnet exit root | +| `rollupExitRoot` | bytes32 | Rollup exit root | +| `leafValue` | bytes32 | leaf value | ### isClaimed + ```solidity function isClaimed( uint32 leafIndex, uint32 sourceBridgeNetwork ) external returns (bool) ``` -Function to check if an index is claimed or not +Function to check if an index is claimed or not #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`leafIndex` | uint32 | Index -|`sourceBridgeNetwork` | uint32 | Origin network + +| Name | Type | Description | +| :-------------------- | :----- | :------------- | +| `leafIndex` | uint32 | Index | +| `sourceBridgeNetwork` | uint32 | Origin network | ### updateGlobalExitRoot + ```solidity function updateGlobalExitRoot( ) external ``` -Function to update the globalExitRoot if the last deposit is not submitted +Function to update the globalExitRoot if the last deposit is not submitted +### \_updateGlobalExitRoot -### _updateGlobalExitRoot ```solidity function _updateGlobalExitRoot( ) internal ``` -Function to update the globalExitRoot +Function to update the globalExitRoot +### \_permit -### _permit ```solidity function _permit( address amount, uint256 permitData ) internal ``` -Function to call token permit method of extended ERC20 - + @param token ERC20 token address +Function to call token permit method of extended ERC20 + @param token ERC20 token address #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`amount` | address | Quantity that is expected to be allowed -|`permitData` | uint256 | Raw data of the call `permit` of the token -### _deployWrappedToken +| Name | Type | Description | +| :----------- | :------ | :----------------------------------------- | +| `amount` | address | Quantity that is expected to be allowed | +| `permitData` | uint256 | Raw data of the call `permit` of the token | + +### \_deployWrappedToken + ```solidity function _deployWrappedToken( bytes32 salt, bytes constructorArgs ) internal returns (contract TokenWrapped newWrappedToken) ``` -Internal function that uses create2 to deploy the wrapped tokens +Internal function that uses create2 to deploy the wrapped tokens #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`salt` | bytes32 | Salt used in create2 params, + +| Name | Type | Description | +| :----- | :------ | :--------------------------- | +| `salt` | bytes32 | Salt used in create2 params, | + tokenInfoHash will be used as salt for all wrappeds except for bridge native WETH, that will be bytes32(0) |`constructorArgs` | bytes | Encoded constructor args for the wrapped token -### _safeSymbol +### \_safeSymbol + ```solidity function _safeSymbol( address token ) internal returns (string) ``` -Provides a safe ERC20.symbol version which returns 'NO_SYMBOL' as fallback string +Provides a safe ERC20.symbol version which returns 'NO_SYMBOL' as fallback string #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | The address of the ERC-20 token contract -### _safeName +| Name | Type | Description | +| :------ | :------ | :--------------------------------------- | +| `token` | address | The address of the ERC-20 token contract | + +### \_safeName + ```solidity function _safeName( address token ) internal returns (string) ``` - Provides a safe ERC20.name version which returns 'NO_NAME' as fallback string. +Provides a safe ERC20.name version which returns 'NO_NAME' as fallback string. #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | The address of the ERC-20 token contract. -### _safeDecimals +| Name | Type | Description | +| :------ | :------ | :---------------------------------------- | +| `token` | address | The address of the ERC-20 token contract. | + +### \_safeDecimals + ```solidity function _safeDecimals( address token ) internal returns (uint8) ``` + Provides a safe ERC20.decimals version which returns '18' as fallback value. Note Tokens with (decimals > 255) are not supported - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | The address of the ERC-20 token contract -### _returnDataToString +| Name | Type | Description | +| :------ | :------ | :--------------------------------------- | +| `token` | address | The address of the ERC-20 token contract | + +### \_returnDataToString + ```solidity function _returnDataToString( bytes data ) internal returns (string) ``` + Function to convert returned data to string returns 'NOT_VALID_ENCODING' as fallback value. - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`data` | bytes | returned data + +| Name | Type | Description | +| :----- | :---- | :------------ | +| `data` | bytes | returned data | ### getTokenMetadata + ```solidity function getTokenMetadata( address token ) public returns (bytes) ``` -Returns the encoded token metadata +Returns the encoded token metadata #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`token` | address | Address of the token + +| Name | Type | Description | +| :------ | :------ | :------------------- | +| `token` | address | Address of the token | ### calculateTokenWrapperAddress + ```solidity function calculateTokenWrapperAddress( uint32 originNetwork, @@ -448,21 +487,24 @@ Returns the encoded token metadata address token ) external returns (address) ``` + Returns the precalculated address of a wrapper using the token address Note Updating the metadata of a token is not supported. Since the metadata has relevance in the address deployed, this function will not return a valid wrapped address if the metadata provided is not the original one. - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether -|`token` | address | Address of the token to calculate the wrapper address + +| Name | Type | Description | +| :------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `originNetwork` | uint32 | Origin network | +| `originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token | +| `token` | address | Address of the token to calculate the wrapper address | ## Events + ### BridgeEvent + ```solidity event BridgeEvent( ) @@ -471,6 +513,7 @@ wrapped address if the metadata provided is not the original one. Emitted when bridge assets or messages to another network ### ClaimEvent + ```solidity event ClaimEvent( ) @@ -479,10 +522,10 @@ Emitted when bridge assets or messages to another network Emitted when a claim is done from another network ### NewWrappedToken + ```solidity event NewWrappedToken( ) ``` Emitted when a new wrapped token is created - diff --git a/docs/v2/lib/DepositContractV2.md b/docs/v2/lib/DepositContractV2.md index 1357d1199..4b56d8543 100644 --- a/docs/v2/lib/DepositContractV2.md +++ b/docs/v2/lib/DepositContractV2.md @@ -1,9 +1,10 @@ This contract will be used in the PolygonZkEVMBridge contract, it inherits the DepositContractBase and adds the logic to calculate the leaf of the tree - ## Functions + ### getLeafValue + ```solidity function getLeafValue( uint8 leafType, @@ -15,17 +16,17 @@ to calculate the leaf of the tree bytes32 metadataHash ) public returns (bytes32) ``` -Given the leaf data returns the leaf value +Given the leaf data returns the leaf value #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message -|`originNetwork` | uint32 | Origin Network -|`originAddress` | address | [0] Origin token address, 0 address is reserved for ether, [1] msg.sender of the message -|`destinationNetwork` | uint32 | Destination network -|`destinationAddress` | address | Destination address -|`amount` | uint256 | [0] Amount of tokens/ether, [1] Amount of ether -|`metadataHash` | bytes32 | Hash of the metadata +| Name | Type | Description | +| :------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message | +| `originNetwork` | uint32 | Origin Network | +| `originAddress` | address | [0] Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token, [1] msg.sender of the message | +| `destinationNetwork` | uint32 | Destination network | +| `destinationAddress` | address | Destination address | +| `amount` | uint256 | [0] Amount of tokens/ether, [1] Amount of ether | +| `metadataHash` | bytes32 | Hash of the metadata | diff --git a/docs/v2/mocks/BridgeReceiverMock.md b/docs/v2/mocks/BridgeReceiverMock.md index e10a14c29..c70664556 100644 --- a/docs/v2/mocks/BridgeReceiverMock.md +++ b/docs/v2/mocks/BridgeReceiverMock.md @@ -1,8 +1,9 @@ Contract for compressing and decompressing claim data - ## Functions + ### claimAsset + ```solidity function claimAsset( bytes32[32] smtProofLocalExitRoot, @@ -18,17 +19,19 @@ Contract for compressing and decompressing claim data bytes metadata ) external ``` -Verify merkle proof and withdraw tokens/ether +Verify merkle proof and withdraw tokens/ether #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the network exit root -|`smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root -|`globalIndex` | uint256 | Global index is defined as: -| 191 bits | 1 bit | 32 bits | 32 bits | -| 0 | mainnetFlag | rollupIndex | localRootIndex | + +| Name | Type | Description | +| :----------------------- | :---------- | :----------------------------------------------------------------------- | -------------- | +| `smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the network exit root | +| `smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root | +| `globalIndex` | uint256 | Global index is defined as: | +| 191 bits | 1 bit | 32 bits | 32 bits | +| 0 | mainnetFlag | rollupIndex | localRootIndex | + note that only the rollup index will be used only in case the mainnet flag is 0 note that global index do not assert the unused bits to 0. This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract @@ -36,13 +39,14 @@ to avoid possible synch attacks |`mainnetExitRoot` | bytes32 | Mainnet exit root |`rollupExitRoot` | bytes32 | Rollup exit root |`originNetwork` | uint32 | Origin network -|`originTokenAddress` | address | Origin token address, 0 address is reserved for ether +|`originTokenAddress` | address | Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token |`destinationNetwork` | uint32 | Network destination |`destinationAddress` | address | Address destination |`amount` | uint256 | Amount of tokens |`metadata` | bytes | Abi encoded metadata if any, empty otherwise ### claimMessage + ```solidity function claimMessage( bytes32[32] smtProofLocalExitRoot, @@ -58,20 +62,22 @@ to avoid possible synch attacks bytes metadata ) external ``` + Verify merkle proof and execute message If the receiving address is an EOA, the call will result as a success Which means that the amount of ether will be transferred correctly, but the message will not trigger any execution - #### Parameters: -| Name | Type | Description | -| :--- | :--- | :------------------------------------------------------------------- | -|`smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the exit root -|`smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root -|`globalIndex` | uint256 | Global index is defined as: -| 191 bits | 1 bit | 32 bits | 32 bits | -| 0 | mainnetFlag | rollupIndex | localRootIndex | + +| Name | Type | Description | +| :----------------------- | :---------- | :----------------------------------------------------------------------- | -------------- | +| `smtProofLocalExitRoot` | bytes32[32] | Smt proof to proof the leaf against the exit root | +| `smtProofRollupExitRoot` | bytes32[32] | Smt proof to proof the rollupLocalExitRoot against the rollups exit root | +| `globalIndex` | uint256 | Global index is defined as: | +| 191 bits | 1 bit | 32 bits | 32 bits | +| 0 | mainnetFlag | rollupIndex | localRootIndex | + note that only the rollup index will be used only in case the mainnet flag is 0 note that global index do not assert the unused bits to 0. This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract @@ -86,24 +92,23 @@ to avoid possible synch attacks |`metadata` | bytes | Abi encoded metadata if any, empty otherwise ### fallback + ```solidity function fallback( ) external ``` - - - ## Events + ### FallbackEvent + ```solidity event FallbackEvent( ) ``` - - ### ClaimAsset + ```solidity event ClaimAsset( ) @@ -112,10 +117,10 @@ to avoid possible synch attacks Emitted when bridge assets or messages to another network ### ClaimMessage + ```solidity event ClaimMessage( ) ``` Emitted when bridge assets or messages to another network - From 54db48320515d2c8a6c3db451ad74d6b8f3c866f Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 7 Nov 2024 13:55:58 +0100 Subject: [PATCH 03/12] Finish script sovereign genesis with hardhat --- .../createSovereignGenesisWithHardhat.ts | 113 +++++++++--------- 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts b/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts index 865047c30..72670d1c2 100644 --- a/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts +++ b/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts @@ -42,6 +42,7 @@ const _ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850 const _IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" as any; const zkevmAddressL2 = ethers.ZeroAddress; +const globalExitRootL2ProxyAddress = "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa"; async function main() { // Constant variables @@ -124,11 +125,11 @@ async function main() { const sovereignGenesisGERImplementation = genesisSovereign.genesis.find(function (obj) { return obj.contractName == "GlobalExitRootManagerL2SovereignChain"; }); - // Change bridge implementation address to the one set at original sovereign genesis + // Change bridge implementation address to the one set at original sovereign genesis. The address is different because they have different initcode const deployedBytecode = await ethers.provider.getCode(bridgeImplementationAddress as string); bridgeImplementationAddress = sovereignGenesisBridgeImplementation.address; await setCode(bridgeImplementationAddress as string, deployedBytecode); - await setNonce(bridgeImplementationAddress as string, 1); + await setNonce(bridgeImplementationAddress as string, 1); /* * deploy bridge proxy and initialize */ @@ -153,9 +154,48 @@ async function main() { deployer, null ); + // Import OZ manifest the deployed contracts, its enough to import just the proxy, the rest are imported automatically ( admin/impl) + await upgrades.forceImport(proxyBridgeAddress as string, sovereignBridgeFactory, "transparent" as any); + /* + *Deployment Global exit root manager implementation, proxy and initialize + */ + const {sovereignParams} = createRollupParameters; + const globalExitRootContractName = "GlobalExitRootManagerL2SovereignChain"; + const GERSovereignFactory = await ethers.getContractFactory(globalExitRootContractName, deployer); + const proxyGERContract = await upgrades.deployProxy(GERSovereignFactory, [sovereignParams.globalExitRootUpdater], { + constructorArgs: [proxyBridgeAddress as string], + unsafeAllow: ["constructor", "state-variable-immutable"], + }); + const proxyGERAddress = proxyGERContract.target; + let GERImplementationAddress = await upgrades.erc1967.getImplementationAddress(proxyGERAddress as string); + + expect(sovereignGenesisGERImplementation.bytecode).to.be.equal( + await ethers.provider.getCode(GERImplementationAddress) + ); + // Compare storage + for (const key in sovereignGenesisGERProxy.storage) { + expect(sovereignGenesisGERProxy.storage[key]).to.be.equal(await getStorageAt(proxyGERAddress as string, key)); + } + // Assert admin address + expect(await upgrades.erc1967.getAdminAddress(proxyGERAddress as string)).to.be.equal(proxyAdminAddress); + expect(await upgrades.erc1967.getAdminAddress(proxyBridgeAddress as string)).to.be.equal(proxyAdminAddress); + + const timelockContractFactory = await ethers.getContractFactory("PolygonZkEVMTimelock", deployer); + const timelockContract = await timelockContractFactory.deploy( + minDelayTimelock, + [timelockAdminAddress], + [timelockAdminAddress], + timelockAdminAddress, + zkevmAddressL2 + ); + await timelockContract.waitForDeployment(); + const finalTimelockContractAddress = timelockContract.target; + + // Transfer ownership of the proxyAdmin to timelock + const proxyAdminInstance = proxyAdminFactory.attach(proxyAdminAddress as string) as ProxyAdmin; + await (await proxyAdminInstance.connect(deployer).transferOwnership(finalTimelockContractAddress as string)).wait(); // Initialize bridge - const {sovereignParams} = createRollupParameters; const sovereignBridgeContract = sovereignBridgeFactory.attach( bridgeImplementationAddress as string ) as BridgeL2SovereignChain; @@ -190,62 +230,15 @@ async function main() { data: initializeData, }); // Check bytecode - expect(sovereignGenesisBridgeProxy.bytecode).to.be.equal(await ethers.provider.getCode(proxyBridgeAddress as string)); + expect(sovereignGenesisBridgeProxy.bytecode).to.be.equal( + await ethers.provider.getCode(proxyBridgeAddress as string) + ); // Check storage for (const key in sovereignGenesisBridgeProxy.storage) { - expect(sovereignGenesisBridgeProxy.storage[key]).to.be.equal(await getStorageAt(proxyBridgeAddress as string, key)); - } - - // Import OZ manifest the deployed contracts, its enough to import just the proxy, the rest are imported automatically ( admin/impl) - await upgrades.forceImport(proxyBridgeAddress as string, sovereignBridgeFactory, "transparent" as any); - - /* - *Deployment Global exit root manager implementation, proxy and initialize - */ - const globalExitRootContractName = "GlobalExitRootManagerL2SovereignChain"; - const GERSovereignFactory = await ethers.getContractFactory(globalExitRootContractName, deployer); - const proxyGERContract = await upgrades.deployProxy(GERSovereignFactory, [sovereignParams.globalExitRootUpdater], { - constructorArgs: [proxyBridgeAddress as string], - unsafeAllow: ["constructor", "state-variable-immutable"], - }); - const proxyGERAddress = proxyGERContract.target; - let GERImplementationAddress = await upgrades.erc1967.getImplementationAddress(proxyGERAddress as string); - // Change GER implementation address to the one set at original sovereign genesis - const deployedGERBytecode = await ethers.provider.getCode(GERImplementationAddress as string); - GERImplementationAddress = sovereignGenesisGERImplementation.address; - await setCode(GERImplementationAddress as string, deployedGERBytecode); - await setNonce(GERImplementationAddress as string, 1); - await setStorageAt(proxyGERAddress as string, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", `0x000000000000000000000000${GERImplementationAddress.slice(2)}`); - expect(sovereignGenesisGERImplementation.bytecode).to.be.equal( - await ethers.provider.getCode(GERImplementationAddress) - ); - // Compare storage - for (const key in sovereignGenesisGERProxy.storage) { - const as = await getStorageAt(proxyGERAddress as string, key) - expect(sovereignGenesisGERProxy.storage[key]).to.be.equal( - await getStorageAt(proxyGERAddress as string, key) + expect(sovereignGenesisBridgeProxy.storage[key]).to.be.equal( + await getStorageAt(proxyBridgeAddress as string, key) ); } - // Assert admin address - expect(await upgrades.erc1967.getAdminAddress(proxyGERAddress as string)).to.be.equal( - proxyAdminAddress - ); - expect(await upgrades.erc1967.getAdminAddress(proxyBridgeAddress as string)).to.be.equal(proxyAdminAddress); - - const timelockContractFactory = await ethers.getContractFactory("PolygonZkEVMTimelock", deployer); - const timelockContract = await timelockContractFactory.deploy( - minDelayTimelock, - [timelockAdminAddress], - [timelockAdminAddress], - timelockAdminAddress, - zkevmAddressL2 - ); - await timelockContract.waitForDeployment(); - const finalTimelockContractAddress = timelockContract.target; - - // Transfer ownership of the proxyAdmin to timelock - const proxyAdminInstance = proxyAdminFactory.attach(proxyAdminAddress as string) as ProxyAdmin; - await (await proxyAdminInstance.connect(deployer).transferOwnership(finalTimelockContractAddress as string)).wait(); // Recreate genesis with the current information: @@ -321,7 +314,7 @@ async function main() { contractName: `${globalExitRootContractName} proxy`, balance: "0", nonce: proxyGlobalExitRootL2Info.nonce.toString(), - address: proxyGERAddress, + address: globalExitRootL2ProxyAddress, bytecode: proxyGlobalExitRootL2Info.bytecode, storage: proxyGlobalExitRootL2Info.storage, }); @@ -393,7 +386,7 @@ async function main() { genesis.push({ accountName: "deployer", balance: "0", - nonce: deployerInfo.nonce.toString(), + nonce: (deployerInfo.nonce + 1).toString(), // Increase nonce by 1 to match the updateVanilla Genesis script, where ger proxy is deployed and initialized in different ransactions address: finalDeployer, }); @@ -420,12 +413,14 @@ async function main() { null, defaultChainId ); - + // Check roots match + const SR = smtUtils.h4toString(zkEVMDB.stateRoot) + expect(SR).to.be.equal(genesisSovereign.root); fs.writeFileSync( pathOutputJson, JSON.stringify( { - root: smtUtils.h4toString(zkEVMDB.stateRoot), + root: SR, genesis: genesis, }, null, From 7bd299595f868e0c4b82c7bc9905193894e684f1 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Mon, 18 Nov 2024 15:13:45 +0700 Subject: [PATCH 04/12] Script sovereign bridge with hardhat small fixes --- deployment/v2/4_createRollup.ts | 3 +- .../createSovereignGenesisWithHardhat.ts | 68 +++++++++++++++---- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/deployment/v2/4_createRollup.ts b/deployment/v2/4_createRollup.ts index 04b8cc5b9..6dc9db011 100644 --- a/deployment/v2/4_createRollup.ts +++ b/deployment/v2/4_createRollup.ts @@ -270,6 +270,7 @@ async function main() { ) { // Get token metadata gasTokenMetadata = await polygonZkEVMBridgeContract.getTokenMetadata(createRollupParameters.gasTokenAddress); + outputJson.gasTokenMetadata = gasTokenMetadata; // If gas token metadata includes `0x124e4f545f56414c49445f454e434f44494e47 (NOT_VALID_ENCODING)` means there is no erc20 token deployed at the selected gas token network if (gasTokenMetadata.includes("124e4f545f56414c49445f454e434f44494e47")) { throw new Error( @@ -293,7 +294,7 @@ async function main() { gasTokenNetwork = 0; gasTokenMetadata = "0x"; } - + outputJson.gasTokenAddress = gasTokenAddress; const nonce = await currentProvider.getTransactionCount(rollupManagerContract.target); const newZKEVMAddress = ethers.getCreateAddress({ from: rollupManagerContract.target as string, diff --git a/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts b/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts index 72670d1c2..ec8ca6eca 100644 --- a/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts +++ b/tools/createSovereignGenesisWithHardhat/createSovereignGenesisWithHardhat.ts @@ -33,7 +33,7 @@ const deployParameters = require(argv.input); const pathOutputJson = path.join(__dirname, argv.out); const genesisSovereign = require("../../docker/deploymentOutput/genesis_sovereign.json"); const createRollupParameters = require("../../deployment/v2/create_rollup_parameters.json"); - +const createRollupOutput = require("../../docker/deploymentOutput/create_rollup_output.json"); /* * bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; @@ -125,6 +125,9 @@ async function main() { const sovereignGenesisGERImplementation = genesisSovereign.genesis.find(function (obj) { return obj.contractName == "GlobalExitRootManagerL2SovereignChain"; }); + const sovereignDeployerAccount = genesisSovereign.genesis.find(function (obj) { + return obj.accountName == "deployer"; + }); // Change bridge implementation address to the one set at original sovereign genesis. The address is different because they have different initcode const deployedBytecode = await ethers.provider.getCode(bridgeImplementationAddress as string); bridgeImplementationAddress = sovereignGenesisBridgeImplementation.address; @@ -199,24 +202,37 @@ async function main() { const sovereignBridgeContract = sovereignBridgeFactory.attach( bridgeImplementationAddress as string ) as BridgeL2SovereignChain; - let gasTokenMetadata, gasTokenAddress; + let gasTokenMetadata, gasTokenAddress, gasTokenNetwork; if ( - deployParameters.gasTokenAddress && - deployParameters.gasTokenAddress !== "" && - deployParameters.gasTokenAddress !== ethers.ZeroAddress + createRollupParameters.gasTokenAddress && + createRollupParameters.gasTokenAddress !== "" && + createRollupParameters.gasTokenAddress !== ethers.ZeroAddress ) { - gasTokenMetadata = await sovereignBridgeContract.getTokenMetadata(deployParameters.gasTokenAddress); - gasTokenAddress = deployParameters.gasTokenAddress; + gasTokenMetadata = createRollupOutput.gasTokenMetadata + gasTokenAddress = createRollupParameters.gasTokenAddress; + const wrappedData = await sovereignBridgeContract.wrappedTokenToTokenInfo( + createRollupParameters.gasTokenAddress + ); + if (wrappedData.originNetwork != 0n) { + // Wrapped token + gasTokenAddress = wrappedData.originTokenAddress; + gasTokenNetwork = wrappedData.originNetwork; + } else { + // Mainnet token + gasTokenAddress = createRollupParameters.gasTokenAddress; + gasTokenNetwork = 0; + } } else { gasTokenMetadata = "0x"; gasTokenAddress = ethers.ZeroAddress; + gasTokenNetwork = 0; } const initializeData = sovereignBridgeFactory.interface.encodeFunctionData( "initialize(uint32,address,uint32,address,address,bytes,address,address,bool)", [ 1, //rollupID gasTokenAddress, - deployParameters.gasTokenNetwork, //gasTokenNetwork, + gasTokenNetwork, //gasTokenNetwork, sovereignGenesisGERProxy.address, // GlobalExitRootManager address ethers.ZeroAddress, //polygonRollupManager gasTokenMetadata, //gasTokenMetadata, @@ -235,12 +251,40 @@ async function main() { ); // Check storage for (const key in sovereignGenesisBridgeProxy.storage) { + const as = await getStorageAt(proxyBridgeAddress as string, key) expect(sovereignGenesisBridgeProxy.storage[key]).to.be.equal( await getStorageAt(proxyBridgeAddress as string, key) ); } - // Recreate genesis with the current information: + // Check weth + if ( + createRollupParameters.gasTokenAddress && + createRollupParameters.gasTokenAddress !== "" && + createRollupParameters.gasTokenAddress !== ethers.ZeroAddress + ) { + const sovereignBridgeProxyContract = sovereignBridgeFactory.attach( + proxyBridgeAddress as string + ) as BridgeL2SovereignChain; + // Add deployed weth + const wethAddress = await sovereignBridgeProxyContract.WETHToken() + const wethBytecode = await ethers.provider.getCode(wethAddress) + const sovereignWETH = genesisSovereign.genesis.find(function (obj) { + return obj.contractName == "WETH"; + }); + // Check storage + for (const key in sovereignWETH.storage) { + expect(sovereignWETH.storage[key]).to.be.equal(await getStorageAt(wethAddress, key)); + } + genesis.push({ + contractName: "WETH", + balance: "0", + nonce: "1", + address: wethAddress, + bytecode: wethBytecode, + storage: sovereignWETH.storage, + }); + } // ZKEVMDeployer const zkEVMDeployerInfo = await getAddressInfo(zkEVMDeployerContract.target); @@ -287,7 +331,7 @@ async function main() { nonce: bridgeProxyInfo.nonce.toString(), address: proxyBridgeAddress, bytecode: bridgeProxyInfo.bytecode, - storage: bridgeProxyInfo.storage, + storage: sovereignGenesisBridgeProxy.storage, // Already checked is the same }); // GER Manager implementation @@ -386,7 +430,7 @@ async function main() { genesis.push({ accountName: "deployer", balance: "0", - nonce: (deployerInfo.nonce + 1).toString(), // Increase nonce by 1 to match the updateVanilla Genesis script, where ger proxy is deployed and initialized in different ransactions + nonce: sovereignDeployerAccount.nonce, // We get nonce from sovereign genesis because the number of transactions is different. With hardhat proxies are deployed and initialized in same transaction address: finalDeployer, }); @@ -415,7 +459,7 @@ async function main() { ); // Check roots match const SR = smtUtils.h4toString(zkEVMDB.stateRoot) - expect(SR).to.be.equal(genesisSovereign.root); + //expect(SR).to.be.equal(genesisSovereign.root); fs.writeFileSync( pathOutputJson, JSON.stringify( From 9e2a4926f60b1c3b35bf3b075854e757aa77bc0f Mon Sep 17 00:00:00 2001 From: Ignasi Date: Tue, 19 Nov 2024 19:44:01 +0700 Subject: [PATCH 05/12] Script create new rollup, first iteration --- deployment/v2/4_createRollup.ts | 2 + tools/addRollupType/addRollupType.ts | 8 +- tools/addRollupType/addRollupTypeTimelock.ts | 6 +- tools/createNewRollup/.gitignore | 4 + tools/createNewRollup/README.md | 48 +++ tools/createNewRollup/createNewRollup.ts | 362 ++++++++++++++++++ .../create_new_rollup.json.example | 22 ++ tools/createNewRollup/genesis.json.example | 92 +++++ 8 files changed, 537 insertions(+), 7 deletions(-) create mode 100644 tools/createNewRollup/.gitignore create mode 100644 tools/createNewRollup/README.md create mode 100644 tools/createNewRollup/createNewRollup.ts create mode 100644 tools/createNewRollup/create_new_rollup.json.example create mode 100644 tools/createNewRollup/genesis.json.example diff --git a/deployment/v2/4_createRollup.ts b/deployment/v2/4_createRollup.ts index 6dc9db011..c890f0c6f 100644 --- a/deployment/v2/4_createRollup.ts +++ b/deployment/v2/4_createRollup.ts @@ -480,6 +480,8 @@ async function main() { outputJson.rollupAddress = newZKEVMAddress; outputJson.verifierAddress = verifierContract.target; outputJson.consensusContract = consensusContract; + outputJson.consensusContractAddress = PolygonconsensusContract.target; + outputJson.rollupTypeId = newRollupTypeID; // Rewrite updated genesis in case of vanilla client if (isVanillaClient) { diff --git a/tools/addRollupType/addRollupType.ts b/tools/addRollupType/addRollupType.ts index 8703c1a77..17fb0ea1f 100644 --- a/tools/addRollupType/addRollupType.ts +++ b/tools/addRollupType/addRollupType.ts @@ -22,7 +22,7 @@ async function main() { /* * Check deploy parameters - * Check that every necessary parameter is fullfilled + * Check that every necessary parameter is fulfilled */ const mandatoryDeploymentParameters = [ "description", @@ -50,11 +50,11 @@ async function main() { programVKey, } = addRollupParameters; - const supportedConensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]; + const supportedConsensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]; const isPessimistic = consensusContract === "PolygonPessimisticConsensus"; - if (!supportedConensus.includes(consensusContract)) { - throw new Error(`Consensus contract not supported, supported contracts are: ${supportedConensus}`); + if (!supportedConsensus.includes(consensusContract)) { + throw new Error(`Consensus contract not supported, supported contracts are: ${supportedConsensus}`); } // Load provider diff --git a/tools/addRollupType/addRollupTypeTimelock.ts b/tools/addRollupType/addRollupTypeTimelock.ts index 92c95595b..ced2bf2c1 100644 --- a/tools/addRollupType/addRollupTypeTimelock.ts +++ b/tools/addRollupType/addRollupTypeTimelock.ts @@ -53,7 +53,7 @@ async function main() { const salt = addRollupParameters.timelockSalt || ethers.ZeroHash; const predecessor = addRollupParameters.predecessor || ethers.ZeroHash; - const supportedConensus = [ + const supportedConsensus = [ "PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonValidiumStorageMigration", @@ -61,8 +61,8 @@ async function main() { ]; const isPessimistic = consensusContract === "PolygonPessimisticConsensus"; - if (!supportedConensus.includes(consensusContract)) { - throw new Error(`Consensus contract not supported, supported contracts are: ${supportedConensus}`); + if (!supportedConsensus.includes(consensusContract)) { + throw new Error(`Consensus contract not supported, supported contracts are: ${supportedConsensus}`); } // Load provider diff --git a/tools/createNewRollup/.gitignore b/tools/createNewRollup/.gitignore new file mode 100644 index 000000000..b3b265ed1 --- /dev/null +++ b/tools/createNewRollup/.gitignore @@ -0,0 +1,4 @@ +create_new_rollup.json +genesis.json +genesis_sovereign.json +create_new_rollup_output.json diff --git a/tools/createNewRollup/README.md b/tools/createNewRollup/README.md new file mode 100644 index 000000000..65139da3b --- /dev/null +++ b/tools/createNewRollup/README.md @@ -0,0 +1,48 @@ +# Add Rollup Type +Script to call `createNewRollup` function + +## Install +``` +npm i +``` + +## Setup +- Config file + - `trustedSequencerURL`: Sequencer URL of the new created rollup + - `networkName`: Network name of the new created rollup + - `trustedSequencer`: Sequencer address of the new created rollup + - `chainID`: ChainID of the rollup, must be a new one, can not have more than 32 bits + - `rollupAdminAddress`: Admin address of the new created rollup + - `consensusContractName`: select between consensus contract. Supported: `["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]` This is the name of the consensus of the rollupType of the rollup to be created + - `gasTokenAddress`: Address of the native gas token of the rollup, zero if ether + - `deployerPvtKey`: Not mandatory, used to deploy from specific wallet + - `maxFeePerGas(optional)`: string, Set `maxFeePerGas`, must define aswell `maxPriorityFeePerGas` to use it + - `maxPriorityFeePerGas(optional)`: string, Set `maxPriorityFeePerGas`, must define aswell `maxFeePerGas` to use it + - `multiplierGas(optional)`: number, Gas multiplier with 3 decimals. If `maxFeePerGas` and `maxPriorityFeePerGas` are set, this will not take effect + - `rollupManagerAddress`: Address of deployed rollupManager contract + - `isVanillaClient`: Flag for vanilla/sovereign clients handling + - `sovereignParams`: + - `bridgeManager`: bridge manager address + - `sovereignWETHAddress`: sovereign WETH address + - `sovereignWETHAddressIsNotMintable`: Flag to indicate if the wrapped ETH is not mintable + - `globalExitRootUpdater`: Address of globalExitRootUpdater for sovereign chains + +## Usage +> All commands are done from root repository. + +### Call 'addNewRollupType' from an EOA + +- Copy configuration files: +``` +cp ./tools/createNewRollup/create_new_rollup.json.example ./tools/createNewRollup/create_new_rollup.json +``` + +``` +cp ./tools/addRollupType/genesis.json.example ./tools/addRollupType/genesis.json +``` + +- Set your parameters +- Run tool: +``` +npx hardhat run ./tools/addRollupType/createNewRollup.ts --network sepolia +``` \ No newline at end of file diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts new file mode 100644 index 000000000..02bb1430b --- /dev/null +++ b/tools/createNewRollup/createNewRollup.ts @@ -0,0 +1,362 @@ +/* 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} from "hardhat"; + +const pathGenesis = path.join(__dirname, "./genesis.json"); +const pathGenesisSovereign = path.join(__dirname, "./genesis_sovereign.json"); +import {processorUtils, Constants} from "@0xpolygonhermez/zkevm-commonjs"; + +const createRollupParameters = require("./create_new_rollup.json"); +let genesis = require(pathGenesis); +import updateVanillaGenesis from "../../deployment/v2/utils/updateVanillaGenesis"; +const pathOutputJson = path.join(__dirname, "./create_new_rollup_output.json"); + +import { + PolygonRollupManager, + PolygonZkEVMEtrog, + PolygonZkEVMBridgeV2, + PolygonValidiumEtrog, + PolygonPessimisticConsensus, +} from "../../typechain-types"; + +async function main() { + const outputJson = {} as any; + /* + * Check deploy parameters + * Check that every necessary parameter is fulfilled + */ + const mandatoryDeploymentParameters = [ + "trustedSequencerURL", + "networkName", + "trustedSequencer", + "chainID", + "rollupAdminAddress", + "consensusContractName", + "rollupManagerAddress", + "rollupTypeId", + "gasTokenAddress", + ]; + + for (const parameterName of mandatoryDeploymentParameters) { + if (createRollupParameters[parameterName] === undefined || createRollupParameters[parameterName] === "") { + throw new Error(`Missing parameter: ${parameterName}`); + } + } + + const { + trustedSequencerURL, + networkName, + trustedSequencer, + chainID, + rollupAdminAddress, + consensusContractName, + isVanillaClient, + sovereignParams, + } = createRollupParameters; + // Check consensus compatibility + if (isVanillaClient) { + if (consensusContractName !== "PolygonPessimisticConsensus") { + throw new Error(`Vanilla client only supports PolygonPessimisticConsensus`); + } + // Check sovereign params + const mandatorySovereignParams = [ + "bridgeManager", + "sovereignWETHAddress", + "sovereignWETHAddressIsNotMintable", + "globalExitRootUpdater", + ]; + for (const parameterName of mandatorySovereignParams) { + if (typeof sovereignParams[parameterName] === undefined || sovereignParams[parameterName] === "") { + throw new Error(`Missing sovereign parameter: ${parameterName}`); + } + } + } + + // Load provider + let currentProvider = ethers.provider; + if (createRollupParameters.multiplierGas || createRollupParameters.maxFeePerGas) { + if (process.env.HARDHAT_NETWORK !== "hardhat") { + currentProvider = ethers.getDefaultProvider( + `https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}` + ) as any; + if (createRollupParameters.maxPriorityFeePerGas && createRollupParameters.maxFeePerGas) { + console.log( + `Hardcoded gas used: MaxPriority${createRollupParameters.maxPriorityFeePerGas} gwei, MaxFee${createRollupParameters.maxFeePerGas} gwei` + ); + const FEE_DATA = new ethers.FeeData( + null, + ethers.parseUnits(createRollupParameters.maxFeePerGas, "gwei"), + ethers.parseUnits(createRollupParameters.maxPriorityFeePerGas, "gwei") + ); + + currentProvider.getFeeData = async () => FEE_DATA; + } else { + console.log("Multiplier gas used: ", createRollupParameters.multiplierGas); + async function overrideFeeData() { + const feedata = await ethers.provider.getFeeData(); + return new ethers.FeeData( + null, + ((feedata.maxFeePerGas as bigint) * BigInt(createRollupParameters.multiplierGas)) / 1000n, + ((feedata.maxPriorityFeePerGas as bigint) * BigInt(createRollupParameters.multiplierGas)) / + 1000n + ); + } + currentProvider.getFeeData = overrideFeeData; + } + } + } + + // Load deployer + let deployer; + if (createRollupParameters.deployerPvtKey) { + deployer = new ethers.Wallet(createRollupParameters.deployerPvtKey, currentProvider); + } else if (process.env.MNEMONIC) { + deployer = ethers.HDNodeWallet.fromMnemonic( + ethers.Mnemonic.fromPhrase(process.env.MNEMONIC), + "m/44'/60'/0'/0/0" + ).connect(currentProvider); + } else { + [deployer] = await ethers.getSigners(); + } + + // Load Rollup manager + const PolygonRollupManagerFactory = await ethers.getContractFactory("PolygonRollupManager", deployer); + const rollupManagerContract = PolygonRollupManagerFactory.attach( + createRollupParameters.rollupManagerAddress + ) as PolygonRollupManager; + + // Load global exit root manager + const globalExitRootManagerFactory = await ethers.getContractFactory("PolygonZkEVMGlobalExitRootV2", deployer); + const globalExitRootManagerAddress = await rollupManagerContract.globalExitRootManager(); + const globalExitRootManagerContract = globalExitRootManagerFactory.attach( + globalExitRootManagerAddress + ) as PolygonRollupManager; + + const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; + if ((await rollupManagerContract.hasRole(DEFAULT_ADMIN_ROLE, deployer.address)) == false) { + throw new Error( + `Deployer does not have admin role. Use the test flag on deploy_parameters if this is a test deployment` + ); + } + + // Check chainID + const rollupID = await rollupManagerContract.chainIDToRollupID(chainID); + if(Number(rollupID) !== 0) { + throw new Error(`Rollup with chainID ${chainID} already exists`); + } + // Check rollupTypeId + const rollupType = await rollupManagerContract.rollupTypeMap(createRollupParameters.rollupTypeId); + const consensusContractAddress = rollupType[0]; + const verifierType = rollupType[3]; + if(consensusContractName === "PolygonPessimisticConsensus") { + expect(verifierType).to.be.equal(1); + } else { + expect(verifierType).to.be.equal(0); + } + // Grant role CREATE_ROLLUP_ROLE to deployer + const CREATE_ROLLUP_ROLE = ethers.id("CREATE_ROLLUP_ROLE"); + if ((await rollupManagerContract.hasRole(CREATE_ROLLUP_ROLE, deployer.address)) == false) + await rollupManagerContract.grantRole(CREATE_ROLLUP_ROLE, deployer.address); + + const nonce = await currentProvider.getTransactionCount(rollupManagerContract.target); + const createdRollupAddress = ethers.getCreateAddress({ + from: rollupManagerContract.target as string, + nonce: nonce, + }); + + // Create new rollup + const txDeployRollup = await rollupManagerContract.createNewRollup( + createRollupParameters.rollupTypeId, + chainID, + rollupAdminAddress, + trustedSequencer, + createRollupParameters.gasTokenAddress, + trustedSequencerURL, + networkName + ); + outputJson.gasTokenAddress = createRollupParameters.gasTokenAddress; + + const receipt = (await txDeployRollup.wait()) as any; + const blockDeploymentRollup = await receipt?.getBlock(); + const timestampReceipt = blockDeploymentRollup.timestamp; + + console.log("#######################\n"); + console.log(`Created new ${consensusContractName} Rollup:`, createdRollupAddress); + + // Assert admin address + expect(await upgrades.erc1967.getAdminAddress(createdRollupAddress)).to.be.equal(rollupManagerContract.target); + expect(await upgrades.erc1967.getImplementationAddress(createdRollupAddress)).to.be.equal( + consensusContractAddress + ); + + // Search added global exit root on the logs + const polygonConsensusFactory = (await ethers.getContractFactory(consensusContractName, deployer)) as any; + let globalExitRoot; + for (const log of receipt?.logs) { + if (log.address == createdRollupAddress) { + const parsedLog = polygonConsensusFactory.interface.parseLog(log); + if (parsedLog != null && parsedLog.name == "InitialSequenceBatches") { + globalExitRoot = parsedLog.args.lastGlobalExitRoot; + } + } + } + + let gasTokenAddress, gasTokenNetwork, gasTokenMetadata; + + // Get bridge instance + const bridgeFactory = await ethers.getContractFactory("PolygonZkEVMBridgeV2", deployer); + const bridgeContractAddress = await rollupManagerContract.bridgeAddress(); + const rollupBridgeContract = bridgeFactory.attach( + bridgeContractAddress + ) as PolygonZkEVMBridgeV2; + if ( + ethers.isAddress(createRollupParameters.gasTokenAddress) && + createRollupParameters.gasTokenAddress !== ethers.ZeroAddress + ) { + // Get token metadata + gasTokenMetadata = await rollupBridgeContract.getTokenMetadata(createRollupParameters.gasTokenAddress); + outputJson.gasTokenMetadata = gasTokenMetadata; + // If gas token metadata includes `0x124e4f545f56414c49445f454e434f44494e47 (NOT_VALID_ENCODING)` means there is no erc20 token deployed at the selected gas token network + if (gasTokenMetadata.includes("124e4f545f56414c49445f454e434f44494e47")) { + throw new Error( + `Invalid gas token address, no ERC20 token deployed at the selected gas token network ${createRollupParameters.gasTokenAddress}` + ); + } + const wrappedData = await rollupBridgeContract.wrappedTokenToTokenInfo( + createRollupParameters.gasTokenAddress + ); + if (wrappedData.originNetwork != 0n) { + // Wrapped token + gasTokenAddress = wrappedData.originTokenAddress; + gasTokenNetwork = wrappedData.originNetwork; + } else { + // Mainnet token + gasTokenAddress = createRollupParameters.gasTokenAddress; + gasTokenNetwork = 0n; + } + } else { + gasTokenAddress = ethers.ZeroAddress; + gasTokenNetwork = 0; + gasTokenMetadata = "0x"; + } + + let batchData = ""; + // If is vanilla client, replace genesis by sovereign contracts, else, inject initialization batch + if (isVanillaClient) { + const initializeParams = { + rollupID: rollupID, + gasTokenAddress, + gasTokenNetwork, + polygonRollupManager: ethers.ZeroAddress, + gasTokenMetadata, + bridgeManager: sovereignParams.bridgeManager, + sovereignWETHAddress: sovereignParams.sovereignWETHAddress, + sovereignWETHAddressIsNotMintable: sovereignParams.sovereignWETHAddressIsNotMintable, + globalExitRootUpdater: sovereignParams.globalExitRootUpdater, + }; + genesis = await updateVanillaGenesis(genesis, chainID, initializeParams); + // Add weth address to deployment output if gas token address is provided and sovereignWETHAddress is not provided + if ( + gasTokenAddress !== ethers.ZeroAddress && + ethers.isAddress(gasTokenAddress) && + (sovereignParams.sovereignWETHAddress === ethers.ZeroAddress || + !ethers.isAddress(sovereignParams.sovereignWETHAddress)) + ) { + const wethObject = genesis.genesis.find(function (obj: {contractName: string}) { + return obj.contractName == "WETH"; + }); + outputJson.WETHAddress = wethObject.address; + } + } else { + if (consensusContractName === "PolygonPessimisticConsensus") { + // Add the first batch of the created rollup + const newPessimisticRollup = (await polygonConsensusFactory.attach( + createdRollupAddress + )) as PolygonPessimisticConsensus; + + // Get last GER + const lastGER = await globalExitRootManagerContract.getLastGlobalExitRoot(); + + const dataInjectedTx = await rollupBridgeContract.interface.encodeFunctionData("initialize", [ + rollupID, + gasTokenAddress, + gasTokenNetwork, + Constants.ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2, // Global exit root address on L2 + ethers.ZeroAddress, // Rollup manager on L2 does not exist + gasTokenMetadata as any, + ]); + + // check maximum length is 65535 + if ((dataInjectedTx.length - 2) / 2 > 0xffff) { + // throw error + throw new Error(`HugeTokenMetadataNotSupported`); + } + + const injectedTx = { + type: 0, // force ethers to parse it as a legacy transaction + chainId: 0, // force ethers to parse it as a pre-EIP155 transaction + to: await newPessimisticRollup.bridgeAddress(), + value: 0, + gasPrice: 0, + gasLimit: 30000000, + nonce: 0, + data: dataInjectedTx, + signature: { + v: "0x1b", + r: "0x00000000000000000000000000000000000000000000000000000005ca1ab1e0", + s: "0x000000000000000000000000000000000000000000000000000000005ca1ab1e", + }, + }; + + // serialize transactions + const txObject = ethers.Transaction.from(injectedTx); + + const customData = processorUtils.rawTxToCustomRawTx(txObject.serialized); + batchData = { + batchL2Data: customData, + globalExitRoot: lastGER, + timestamp: blockDeploymentRollup.timestamp, + sequencer: trustedSequencer, + l1BlockNumber: blockDeploymentRollup.number, + l1BlockHash: blockDeploymentRollup.hash, + l1ParentHash: blockDeploymentRollup.parentHash, + } as any; + } else { + // Add the first batch of the created rollup + const newRollupContract = (await polygonConsensusFactory.attach(createdRollupAddress)) as PolygonZkEVMEtrog; + batchData = { + batchL2Data: await newRollupContract.generateInitializeTransaction( + Number(rollupID), + gasTokenAddress, + gasTokenNetwork, + gasTokenMetadata as any + ), + globalExitRoot: globalExitRoot, + timestamp: timestampReceipt, + sequencer: trustedSequencer, + } as any; + } + } + outputJson.firstBatchData = batchData; + outputJson.genesis = genesis.root; + outputJson.createRollupBlockNumber = blockDeploymentRollup.number; + outputJson.rollupAddress = createdRollupAddress; + outputJson.consensusContract = consensusContractName; + outputJson.rollupID = Number(rollupID); + // Rewrite updated genesis in case of vanilla client + if (isVanillaClient) { + fs.writeFileSync(pathGenesisSovereign, JSON.stringify(genesis, null, 1)); + } + fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/tools/createNewRollup/create_new_rollup.json.example b/tools/createNewRollup/create_new_rollup.json.example new file mode 100644 index 000000000..156aa3cd1 --- /dev/null +++ b/tools/createNewRollup/create_new_rollup.json.example @@ -0,0 +1,22 @@ +{ + "trustedSequencerURL": "http://zkevm-json-rpc:8123", + "networkName": "zkevm", + "trustedSequencer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "chainID": 1001, + "rollupAdminAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "consensusContractName": "PolygonZkEVMEtrog", + "gasTokenAddress": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + "deployerPvtKey": "", + "maxFeePerGas": "", + "maxPriorityFeePerGas": "", + "multiplierGas": "", + "rollupManagerAddress": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", + "rollupTypeId": 1, + "isVanillaClient": false, + "sovereignParams": { + "bridgeManager": "0xC7899Ff6A3aC2FF59261bD960A8C880DF06E1041", + "sovereignWETHAddress": "0x0000000000000000000000000000000000000000", + "sovereignWETHAddressIsNotMintable": false, + "globalExitRootUpdater": "0xB55B27Cca633A73108893985350bc26B8A00C43a" + } +} \ No newline at end of file diff --git a/tools/createNewRollup/genesis.json.example b/tools/createNewRollup/genesis.json.example new file mode 100644 index 000000000..93b7f5b26 --- /dev/null +++ b/tools/createNewRollup/genesis.json.example @@ -0,0 +1,92 @@ +{ + "root": "0x433ba1f86d65cf39d003f7dec3c6dcdbf14b17c169fba89a16732b88254a3b1e", + "genesis": [ + { + "contractName": "PolygonZkEVMDeployer", + "balance": "0", + "nonce": "4", + "address": "0xFbD07134824dDEa24E4ae414c18ecbFa98169A24", + "bytecode": "0x60806040526004361061006e575f3560e01c8063715018a61161004c578063715018a6146100e25780638da5cb5b146100f6578063e11ae6cb1461011f578063f2fde38b14610132575f80fd5b80632b79805a146100725780634a94d487146100875780636d07dbf81461009a575b5f80fd5b610085610080366004610908565b610151565b005b6100856100953660046109a2565b6101c2565b3480156100a5575f80fd5b506100b96100b43660046109f5565b610203565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ed575f80fd5b50610085610215565b348015610101575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166100b9565b61008561012d366004610a15565b610228565b34801561013d575f80fd5b5061008561014c366004610a61565b61028e565b61015961034a565b5f6101658585856103ca565b90506101718183610527565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101ca61034a565b6101d583838361056a565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b905f90a1505050565b5f61020e8383610598565b9392505050565b61021d61034a565b6102265f6105a4565b565b61023061034a565b5f61023c8484846103ca565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b61029661034a565b73ffffffffffffffffffffffffffffffffffffffff811661033e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610347816105a4565b50565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610226576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610335565b5f83471015610435576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610335565b81515f0361049f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610335565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff811661020e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610335565b606061020e83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250610618565b6060610590848484604051806060016040528060298152602001610b0860299139610618565b949350505050565b5f61020e83833061072d565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610335565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516106d29190610a9c565b5f6040518083038185875af1925050503d805f811461070c576040519150601f19603f3d011682016040523d82523d5f602084013e610711565b606091505b509150915061072287838387610756565b979650505050505050565b5f604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156107eb5782515f036107e45773ffffffffffffffffffffffffffffffffffffffff85163b6107e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610335565b5081610590565b61059083838151156108005781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103359190610ab7565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112610870575f80fd5b813567ffffffffffffffff8082111561088b5761088b610834565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108d1576108d1610834565b816040528381528660208588010111156108e9575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f806080858703121561091b575f80fd5b8435935060208501359250604085013567ffffffffffffffff80821115610940575f80fd5b61094c88838901610861565b93506060870135915080821115610961575f80fd5b5061096e87828801610861565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099d575f80fd5b919050565b5f805f606084860312156109b4575f80fd5b6109bd8461097a565b9250602084013567ffffffffffffffff8111156109d8575f80fd5b6109e486828701610861565b925050604084013590509250925092565b5f8060408385031215610a06575f80fd5b50508035926020909101359150565b5f805f60608486031215610a27575f80fd5b8335925060208401359150604084013567ffffffffffffffff811115610a4b575f80fd5b610a5786828701610861565b9150509250925092565b5f60208284031215610a71575f80fd5b61020e8261097a565b5f5b83811015610a94578181015183820152602001610a7c565b50505f910152565b5f8251610aad818460208701610a7a565b9190910192915050565b602081525f8251806020840152610ad5816040850160208701610a7a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220330b94dc698c4d290bf55c23f13b473cde6a6bae0030cb902de18af54e35839f64736f6c63430008140033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266" + } + }, + { + "contractName": "ProxyAdmin", + "balance": "0", + "nonce": "1", + "address": "0xfADB60b5059e31614e02083fF6C021a24C31c891", + "bytecode": "0x608060405260043610610079575f3560e01c80639623609d1161004c5780639623609d1461012357806399a88ec414610136578063f2fde38b14610155578063f3b7dead14610174575f80fd5b8063204e1c7a1461007d578063715018a6146100c55780637eff275e146100db5780638da5cb5b146100fa575b5f80fd5b348015610088575f80fd5b5061009c6100973660046105e8565b610193565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d0575f80fd5b506100d9610244565b005b3480156100e6575f80fd5b506100d96100f536600461060a565b610257565b348015610105575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff1661009c565b6100d961013136600461066e565b6102e0565b348015610141575f80fd5b506100d961015036600461060a565b610371565b348015610160575f80fd5b506100d961016f3660046105e8565b6103cd565b34801561017f575f80fd5b5061009c61018e3660046105e8565b610489565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b5f60405180830381855afa9150503d805f8114610215576040519150601f19603f3d011682016040523d82523d5f602084013e61021a565b606091505b509150915081610228575f80fd5b8080602001905181019061023c919061075b565b949350505050565b61024c6104d3565b6102555f610553565b565b61025f6104d3565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b5f604051808303815f87803b1580156102c6575f80fd5b505af11580156102d8573d5f803e3d5ffd5b505050505050565b6102e86104d3565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061033e9086908690600401610776565b5f604051808303818588803b158015610355575f80fd5b505af1158015610367573d5f803e3d5ffd5b5050505050505050565b6103796104d3565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102af565b6103d56104d3565b73ffffffffffffffffffffffffffffffffffffffff811661047d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61048681610553565b50565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610255576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610474565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81168114610486575f80fd5b5f602082840312156105f8575f80fd5b8135610603816105c7565b9392505050565b5f806040838503121561061b575f80fd5b8235610626816105c7565b91506020830135610636816105c7565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f805f60608486031215610680575f80fd5b833561068b816105c7565b9250602084013561069b816105c7565b9150604084013567ffffffffffffffff808211156106b7575f80fd5b818601915086601f8301126106ca575f80fd5b8135818111156106dc576106dc610641565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561072257610722610641565b8160405282815289602084870101111561073a575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f6020828403121561076b575f80fd5b8151610603816105c7565b73ffffffffffffffffffffffffffffffffffffffff831681525f602060408184015283518060408501525f5b818110156107be578581018301518582016060015282016107a2565b505f6060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea26469706673582212203083a4ccc2e42eed60bd19037f2efa77ed086dc7a5403f75bebb995dcba2221c64736f6c63430008140033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f" + } + }, + { + "contractName": "PolygonZkEVMBridgeV2", + "balance": "0", + "nonce": "1", + "address": "0xBC9585CB224A8F42EF9C9F0b99c531B450b11886", + "bytecode": "0x6080604052600436106101db575f3560e01c806383f24403116100fd578063ccaa2d1111610092578063ee25560b11610062578063ee25560b146105a9578063f5efcd79146105d4578063f811bff7146105f3578063fb57083414610612575f80fd5b8063ccaa2d111461053b578063cd5865791461055a578063d02103ca1461056d578063dbc1697614610595575f80fd5b8063bab161bf116100cd578063bab161bf146104b9578063be5831c7146104da578063c00f14ab146104fd578063cc4616321461051c575f80fd5b806383f244031461043d5780638ed7e3f21461045c578063aaa13cc21461047b578063b8b284d01461049a575f80fd5b80633cbc795b116101735780637843298b116101435780637843298b146103c257806379e2cf97146103e157806381b1c174146103f557806383c43a5514610429575f80fd5b80633cbc795b146103385780633e197043146103705780634b2f336d1461038f5780635ca1e165146103ae575f80fd5b806327aef4e8116101ae57806327aef4e81461026d5780632dfdf0b51461028e578063318aee3d146102b15780633c351e1014610319575f80fd5b806315064c96146101df5780632072f6c51461020d57806322e95f2c14610223578063240ff3781461025a575b5f80fd5b3480156101ea575f80fd5b506068546101f89060ff1681565b60405190151581526020015b60405180910390f35b348015610218575f80fd5b50610221610631565b005b34801561022e575f80fd5b5061024261023d366004612e6f565b610666565b6040516001600160a01b039091168152602001610204565b610221610268366004612ef6565b6106d0565b348015610278575f80fd5b50610281610759565b6040516102049190612fb8565b348015610299575f80fd5b506102a360535481565b604051908152602001610204565b3480156102bc575f80fd5b506102f56102cb366004612fd1565b606b6020525f908152604090205463ffffffff81169064010000000090046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b03909116602083015201610204565b348015610324575f80fd5b50606d54610242906001600160a01b031681565b348015610343575f80fd5b50606d5461035b90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610204565b34801561037b575f80fd5b506102a361038a366004612ffa565b6107e5565b34801561039a575f80fd5b50606f54610242906001600160a01b031681565b3480156103b9575f80fd5b506102a361088e565b3480156103cd575f80fd5b506102426103dc366004613074565b61096a565b3480156103ec575f80fd5b50610221610993565b348015610400575f80fd5b5061024261040f3660046130ba565b606a6020525f90815260409020546001600160a01b031681565b348015610434575f80fd5b506102816109b4565b348015610448575f80fd5b506102a36104573660046130e2565b6109d3565b348015610467575f80fd5b50606c54610242906001600160a01b031681565b348015610486575f80fd5b506102426104953660046131e3565b610aa8565b3480156104a5575f80fd5b506102216104b4366004613279565b610be7565b3480156104c4575f80fd5b5060685461035b90610100900463ffffffff1681565b3480156104e5575f80fd5b5060685461035b90600160c81b900463ffffffff1681565b348015610508575f80fd5b50610281610517366004612fd1565b610c79565b348015610527575f80fd5b506101f86105363660046132f7565b610cbe565b348015610546575f80fd5b50610221610555366004613328565b610d46565b61022161056836600461340c565b611181565b348015610578575f80fd5b50606854610242906501000000000090046001600160a01b031681565b3480156105a0575f80fd5b5061022161154a565b3480156105b4575f80fd5b506102a36105c33660046130ba565b60696020525f908152604090205481565b3480156105df575f80fd5b506102216105ee366004613328565b61157d565b3480156105fe575f80fd5b5061022161060d36600461349c565b6117f9565b34801561061d575f80fd5b506101f861062c36600461353f565b611b14565b606c546001600160a01b0316331461065c57604051631736745960e31b815260040160405180910390fd5b610664611b2b565b565b6040805160e084901b6001600160e01b031916602080830191909152606084901b6bffffffffffffffffffffffff1916602483015282516018818403018152603890920183528151918101919091205f908152606a90915220546001600160a01b03165b92915050565b60685460ff16156106f457604051630bc011ff60e21b815260040160405180910390fd5b341580159061070d5750606f546001600160a01b031615155b15610744576040517f6f625c4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610752858534868686611b86565b5050505050565b606e805461076690613584565b80601f016020809104026020016040519081016040528092919081815260200182805461079290613584565b80156107dd5780601f106107b4576101008083540402835291602001916107dd565b820191905f5260205f20905b8154815290600101906020018083116107c057829003601f168201915b505050505081565b6040517fff0000000000000000000000000000000000000000000000000000000000000060f889901b1660208201526001600160e01b031960e088811b821660218401526bffffffffffffffffffffffff19606089811b821660258601529188901b909216603984015285901b16603d82015260518101839052607181018290525f90609101604051602081830303815290604052805190602001209050979650505050505050565b6053545f90819081805b6020811015610961578083901c6001166001036108f557603381602081106108c2576108c26135bc565b01546040805160208101929092528101859052606001604051602081830303815290604052805190602001209350610922565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b60408051602081018490529081018390526060016040516020818303038152906040528051906020012091508080610959906135e4565b915050610898565b50919392505050565b5f61098b848461097985611c50565b61098286611d3a565b61049587611e1b565b949350505050565b605354606854600160c81b900463ffffffff16101561066457610664611ee8565b60405180611ba00160405280611b668152602001613c36611b66913981565b5f83815b6020811015610a9f57600163ffffffff8516821c81169003610a4257848160208110610a0557610a056135bc565b602002013582604051602001610a25929190918252602082015260400190565b604051602081830303815290604052805190602001209150610a8d565b81858260208110610a5557610a556135bc565b6020020135604051602001610a74929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b80610a97816135e4565b9150506109d7565b50949350505050565b6040516001600160e01b031960e087901b1660208201526bffffffffffffffffffffffff19606086901b1660248201525f9081906038016040516020818303038152906040528051906020012090505f60ff60f81b308360405180611ba00160405280611b668152602001613c36611b669139898989604051602001610b30939291906135fc565b60408051601f1981840301815290829052610b4e9291602001613634565b60405160208183030381529060405280519060200120604051602001610bc394939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff1615610c0b57604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b0316610c4d576040517fdde3cda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f54610c63906001600160a01b031685611f96565b610c71868686868686611b86565b505050505050565b6060610c8482611c50565b610c8d83611d3a565b610c9684611e1b565b604051602001610ca8939291906135fc565b6040516020818303038152906040529050919050565b6068545f908190610100900463ffffffff16158015610ce3575063ffffffff83166001145b15610cf5575063ffffffff8316610d1d565b610d0a64010000000063ffffffff8516613662565b610d1a9063ffffffff8616613679565b90505b600881901c5f90815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff1615610d6a57604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614610d9a576040516302caf51760e11b815260040160405180910390fd5b610dcd8c8c8c8c8c610dc85f8e8e8e8e8e8e8e604051610dbb92919061368c565b60405180910390206107e5565b612006565b6001600160a01b038616610ecd57606f546001600160a01b0316610eb1575f6001600160a01b03851684825b6040519080825280601f01601f191660200182016040528015610e23576020820181803683370190505b50604051610e31919061369b565b5f6040518083038185875af1925050503d805f8114610e6b576040519150601f19603f3d011682016040523d82523d5f602084013e610e70565b606091505b5050905080610eab576040517f6747a28800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611117565b606f54610ec8906001600160a01b03168585612198565b611117565b606d546001600160a01b038781169116148015610efb5750606d5463ffffffff888116600160a01b90920416145b15610f12575f6001600160a01b0385168482610df9565b60685463ffffffff610100909104811690881603610f3e57610ec86001600160a01b038716858561220a565b6040516001600160e01b031960e089901b1660208201526bffffffffffffffffffffffff19606088901b1660248201525f9060380160408051601f1981840301815291815281516020928301205f818152606a9093529120549091506001600160a01b031680611109575f610fe88386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061228b92505050565b9050610ff5818888612198565b80606a5f8581526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808b63ffffffff1681526020018a6001600160a01b0316815250606b5f836001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548163ffffffff021916908363ffffffff1602179055506020820151815f0160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398a8a8388886040516110fb9594939291906136de565b60405180910390a150611114565b611114818787612198565b50505b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b60685460ff16156111a557604051630bc011ff60e21b815260040160405180910390fd5b6111ad61231e565b60685463ffffffff6101009091048116908816036111de576040516302caf51760e11b815260040160405180910390fd5b5f806060876001600160a01b0388166112da5788341461122a576040517fb89240f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff1694509061125790613584565b80601f016020809104026020016040519081016040528092919081815260200182805461128390613584565b80156112ce5780601f106112a5576101008083540402835291602001916112ce565b820191905f5260205f20905b8154815290600101906020018083116112b157829003601f168201915b505050505091506114c1565b3415611312576040517f798ee6f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546001600160a01b039081169089160361133757611332888a611f96565b6114c1565b6001600160a01b038089165f908152606b602090815260409182902082518084019093525463ffffffff811683526401000000009004909216918101829052901561139757611386898b611f96565b6020810151815190955093506114b4565b85156113a9576113a9898b8989612377565b6040516370a0823160e01b81523060048201525f906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156113ed573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114119190613716565b90506114286001600160a01b038b1633308e612716565b6040516370a0823160e01b81523060048201525f906001600160a01b038c16906370a0823190602401602060405180830381865afa15801561146c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114909190613716565b905061149c828261372d565b6068548c9850610100900463ffffffff169650935050505b6114bd89610c79565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b5f84868e8e8688605354604051611500989796959493929190613740565b60405180910390a16115266115215f85878f8f8789805190602001206107e5565b612767565b861561153457611534611ee8565b5050505061154160018055565b50505050505050565b606c546001600160a01b0316331461157557604051631736745960e31b815260040160405180910390fd5b610664612868565b60685460ff16156115a157604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff86811661010090920416146115d1576040516302caf51760e11b815260040160405180910390fd5b6115f38c8c8c8c8c610dc860018e8e8e8e8e8e8e604051610dbb92919061368c565b606f545f906001600160a01b03166116a657846001600160a01b031684888a868660405160240161162794939291906137a9565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161165c919061369b565b5f6040518083038185875af1925050503d805f8114611696576040519150601f19603f3d011682016040523d82523d5f602084013e61169b565b606091505b505080915050611757565b606f546116bd906001600160a01b03168686612198565b846001600160a01b0316878985856040516024016116de94939291906137a9565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b17905251611713919061369b565b5f604051808303815f865af19150503d805f811461174c576040519150601f19603f3d011682016040523d82523d5f602084013e611751565b606091505b50909150505b8061178e576040517f37e391c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518c815263ffffffff8a1660208201526001600160a01b0389811682840152871660608201526080810186905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a150505050505050505050505050565b5f54610100900460ff161580801561181757505f54600160ff909116105b806118305750303b15801561183057505f5460ff166001145b6118a75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f805460ff1916600117905580156118c8575f805461ff0019166101001790555b606880547fffffffffffffff000000000000000000000000000000000000000000000000ff1661010063ffffffff8a16027fffffffffffffff0000000000000000000000000000000000000000ffffffffff1617650100000000006001600160a01b038781169190910291909117909155606c805473ffffffffffffffffffffffffffffffffffffffff191685831617905586166119a35763ffffffff85161561199e576040517f1a874c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611abf565b606d805463ffffffff8716600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009091166001600160a01b03891617179055606e6119f28382613826565b50611a915f801b6012604051602001611a7d91906060808252600d908201527f5772617070656420457468657200000000000000000000000000000000000000608082015260a0602082018190526004908201527f574554480000000000000000000000000000000000000000000000000000000060c082015260ff91909116604082015260e00190565b60405160208183030381529060405261228b565b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555b611ac76128d8565b8015611541575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b5f81611b218686866109d3565b1495945050505050565b60685460ff1615611b4f57604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a5497905f90a1565b60685463ffffffff610100909104811690871603611bb7576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff16338989898888605354604051611c0b999897969594939291906138e2565b60405180910390a1611c426115216001606860019054906101000a900463ffffffff16338a8a8a8989604051610dbb92919061368c565b8215610c7157610c71611ee8565b60408051600481526024810182526020810180516001600160e01b03167f06fdde030000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611caf919061369b565b5f60405180830381855afa9150503d805f8114611ce7576040519150601f19603f3d011682016040523d82523d5f602084013e611cec565b606091505b509150915081611d31576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525061098b565b61098b8161294a565b60408051600481526024810182526020810180516001600160e01b03167f95d89b410000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611d99919061369b565b5f60405180830381855afa9150503d805f8114611dd1576040519150601f19603f3d011682016040523d82523d5f602084013e611dd6565b606091505b509150915081611d31576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525061098b565b60408051600481526024810182526020810180516001600160e01b03167f313ce5670000000000000000000000000000000000000000000000000000000017905290515f91829182916001600160a01b03861691611e79919061369b565b5f60405180830381855afa9150503d805f8114611eb1576040519150601f19603f3d011682016040523d82523d5f602084013e611eb6565b606091505b5091509150818015611ec9575080516020145b611ed457601261098b565b8080602001905181019061098b919061394d565b6053546068805463ffffffff909216600160c81b027fffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117908190556001600160a01b0365010000000000909104166333d6247d611f4961088e565b6040518263ffffffff1660e01b8152600401611f6791815260200190565b5f604051808303815f87803b158015611f7e575f80fd5b505af1158015611f90573d5f803e3d5ffd5b50505050565b6040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b03831690639dc29fac906044015f604051808303815f87803b158015611ff4575f80fd5b505af1158015610c71573d5f803e3d5ffd5b606854604080516020808201879052818301869052825180830384018152606083019384905280519101207f257b36320000000000000000000000000000000000000000000000000000000090925260648101919091525f916501000000000090046001600160a01b03169063257b3632906084016020604051808303815f875af1158015612097573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120bb9190613716565b9050805f036120f5576040517e2f6fad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806801000000000000000087161561213957869150612117848a8489611b14565b612134576040516338105f3b60e21b815260040160405180910390fd5b612183565b602087901c612149816001613968565b915087925061216461215c868c866109d3565b8a8389611b14565b612181576040516338105f3b60e21b815260040160405180910390fd5b505b61218d8282612b1a565b505050505050505050565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390528416906340c10f19906044015f604051808303815f87803b1580156121f8575f80fd5b505af1158015611541573d5f803e3d5ffd5b6040516001600160a01b0383166024820152604481018290526122869084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612bda565b505050565b5f8060405180611ba00160405280611b668152602001613c36611b669139836040516020016122bb929190613634565b6040516020818303038152906040529050838151602083015ff591506001600160a01b038216612317576040517fbefb092000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b6002600154036123705760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161189e565b6002600155565b5f6123856004828486613985565b61238e916139ac565b90507f2afa5331000000000000000000000000000000000000000000000000000000006001600160e01b0319821601612568575f8080808080806123d5896004818d613985565b8101906123e291906139dc565b9650965096509650965096509650336001600160a01b0316876001600160a01b0316146124225760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b038616301461244b5760405163750643af60e01b815260040160405180910390fd5b8a8514612484576040517f03fffc4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b03167fd505accf000000000000000000000000000000000000000000000000000000001790529151918e169161251b919061369b565b5f604051808303815f865af19150503d805f8114612554576040519150601f19603f3d011682016040523d82523d5f602084013e612559565b606091505b50505050505050505050610752565b6001600160e01b031981166323f2ebc360e21b146125b2576040517fe282c0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f808080808080806125c78a6004818e613985565b8101906125d49190613a2b565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146126165760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b038716301461263f5760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f16916126c6919061369b565b5f604051808303815f865af19150503d805f81146126ff576040519150601f19603f3d011682016040523d82523d5f602084013e612704565b606091505b50505050505050505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611f909085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161224f565b80600161277660206002613b89565b612780919061372d565b605354106127ba576040517fef5ccf6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60535f81546127c9906135e4565b918290555090505f5b6020811015612859578082901c6001166001036128055782603382602081106127fd576127fd6135bc565b015550505050565b60338160208110612818576128186135bc565b015460408051602081019290925281018490526060016040516020818303038152906040528051906020012092508080612851906135e4565b9150506127d2565b50612286613b94565b60018055565b60685460ff166128a4576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b3905f90a1565b5f54610100900460ff166129425760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161189e565b610664612cbe565b6060604082511061296957818060200190518101906106ca9190613ba8565b8151602003612adc575f5b6020811080156129bb5750828181518110612991576129916135bc565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b156129d257806129ca816135e4565b915050612974565b805f03612a1457505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b5f8167ffffffffffffffff811115612a2e57612a2e61311e565b6040519080825280601f01601f191660200182016040528015612a58576020820181803683370190505b5090505f5b82811015612ad457848181518110612a7757612a776135bc565b602001015160f81c60f81b828281518110612a9457612a946135bc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535080612acc816135e4565b915050612a5d565b509392505050565b505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b919050565b6068545f90610100900463ffffffff16158015612b3d575063ffffffff82166001145b15612b4f575063ffffffff8216612b77565b612b6464010000000063ffffffff8416613662565b612b749063ffffffff8516613679565b90505b600881901c5f8181526069602052604081208054600160ff861690811b91821892839055929091908183169003611541576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612c2e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612d289092919063ffffffff16565b8051909150156122865780806020019051810190612c4c9190613c1a565b6122865760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161189e565b5f54610100900460ff166128625760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161189e565b606061098b84845f85855f80866001600160a01b03168587604051612d4d919061369b565b5f6040518083038185875af1925050503d805f8114612d87576040519150601f19603f3d011682016040523d82523d5f602084013e612d8c565b606091505b5091509150612d9d87838387612da8565b979650505050505050565b60608315612e165782515f03612e0f576001600160a01b0385163b612e0f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161189e565b508161098b565b61098b8383815115612e2b5781518083602001fd5b8060405162461bcd60e51b815260040161189e9190612fb8565b803563ffffffff81168114612b15575f80fd5b6001600160a01b0381168114612e6c575f80fd5b50565b5f8060408385031215612e80575f80fd5b612e8983612e45565b91506020830135612e9981612e58565b809150509250929050565b8015158114612e6c575f80fd5b5f8083601f840112612ec1575f80fd5b50813567ffffffffffffffff811115612ed8575f80fd5b602083019150836020828501011115612eef575f80fd5b9250929050565b5f805f805f60808688031215612f0a575f80fd5b612f1386612e45565b94506020860135612f2381612e58565b93506040860135612f3381612ea4565b9250606086013567ffffffffffffffff811115612f4e575f80fd5b612f5a88828901612eb1565b969995985093965092949392505050565b5f5b83811015612f85578181015183820152602001612f6d565b50505f910152565b5f8151808452612fa4816020860160208601612f6b565b601f01601f19169290920160200192915050565b602081525f612fca6020830184612f8d565b9392505050565b5f60208284031215612fe1575f80fd5b8135612fca81612e58565b60ff81168114612e6c575f80fd5b5f805f805f805f60e0888a031215613010575f80fd5b873561301b81612fec565b965061302960208901612e45565b9550604088013561303981612e58565b945061304760608901612e45565b9350608088013561305781612e58565b9699959850939692959460a0840135945060c09093013592915050565b5f805f60608486031215613086575f80fd5b61308f84612e45565b9250602084013561309f81612e58565b915060408401356130af81612e58565b809150509250925092565b5f602082840312156130ca575f80fd5b5035919050565b8061040081018310156106ca575f80fd5b5f805f61044084860312156130f5575f80fd5b8335925061310685602086016130d1565b91506131156104208501612e45565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561315b5761315b61311e565b604052919050565b5f67ffffffffffffffff82111561317c5761317c61311e565b50601f01601f191660200190565b5f61319c61319784613163565b613132565b90508281528383830111156131af575f80fd5b828260208301375f602084830101529392505050565b5f82601f8301126131d4575f80fd5b612fca8383356020850161318a565b5f805f805f60a086880312156131f7575f80fd5b61320086612e45565b9450602086013561321081612e58565b9350604086013567ffffffffffffffff8082111561322c575f80fd5b61323889838a016131c5565b9450606088013591508082111561324d575f80fd5b5061325a888289016131c5565b925050608086013561326b81612fec565b809150509295509295909350565b5f805f805f8060a0878903121561328e575f80fd5b61329787612e45565b955060208701356132a781612e58565b94506040870135935060608701356132be81612ea4565b9250608087013567ffffffffffffffff8111156132d9575f80fd5b6132e589828a01612eb1565b979a9699509497509295939492505050565b5f8060408385031215613308575f80fd5b61331183612e45565b915061331f60208401612e45565b90509250929050565b5f805f805f805f805f805f806109208d8f031215613344575f80fd5b61334e8e8e6130d1565b9b5061335e8e6104008f016130d1565b9a506108008d013599506108208d013598506108408d013597506133856108608e01612e45565b96506133956108808e0135612e58565b6108808d013595506133aa6108a08e01612e45565b94506133ba6108c08e0135612e58565b6108c08d013593506108e08d0135925067ffffffffffffffff6109008e013511156133e3575f80fd5b6133f48e6109008f01358f01612eb1565b81935080925050509295989b509295989b509295989b565b5f805f805f805f60c0888a031215613422575f80fd5b61342b88612e45565b9650602088013561343b81612e58565b955060408801359450606088013561345281612e58565b9350608088013561346281612ea4565b925060a088013567ffffffffffffffff81111561347d575f80fd5b6134898a828b01612eb1565b989b979a50959850939692959293505050565b5f805f805f8060c087890312156134b1575f80fd5b6134ba87612e45565b955060208701356134ca81612e58565b94506134d860408801612e45565b935060608701356134e881612e58565b925060808701356134f881612e58565b915060a087013567ffffffffffffffff811115613513575f80fd5b8701601f81018913613523575f80fd5b6135328982356020840161318a565b9150509295509295509295565b5f805f806104608587031215613553575f80fd5b8435935061356486602087016130d1565b92506135736104208601612e45565b939692955092936104400135925050565b600181811c9082168061359857607f821691505b6020821081036135b657634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016135f5576135f56135d0565b5060010190565b606081525f61360e6060830186612f8d565b82810360208401526136208186612f8d565b91505060ff83166040830152949350505050565b5f8351613645818460208801612f6b565b835190830190613659818360208801612f6b565b01949350505050565b80820281158282048414176106ca576106ca6135d0565b808201808211156106ca576106ca6135d0565b818382375f9101908152919050565b5f82516136ac818460208701612f6b565b9190910192915050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b63ffffffff861681525f6001600160a01b03808716602084015280861660408401525060806060830152612d9d6080830184866136b6565b5f60208284031215613726575f80fd5b5051919050565b818103818111156106ca576106ca6135d0565b5f61010060ff8b16835263ffffffff808b1660208501526001600160a01b03808b166040860152818a1660608601528089166080860152508660a08501528160c085015261379082850187612f8d565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff84166020820152606060408201525f6137d76060830184866136b6565b9695505050505050565b601f821115612286575f81815260208120601f850160051c810160208610156138075750805b601f850160051c820191505b81811015610c7157828155600101613813565b815167ffffffffffffffff8111156138405761384061311e565b6138548161384e8454613584565b846137e1565b602080601f831160018114613887575f84156138705750858301515b5f19600386901b1c1916600185901b178555610c71565b5f85815260208120601f198616915b828110156138b557888601518255948401946001909101908401613896565b50858210156138d257878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61010060ff8c16835263ffffffff808c1660208501526001600160a01b03808c166040860152818b166060860152808a166080860152508760a08501528160c085015261393382850187896136b6565b925080851660e085015250509a9950505050505050505050565b5f6020828403121561395d575f80fd5b8151612fca81612fec565b63ffffffff818116838216019080821115612317576123176135d0565b5f8085851115613993575f80fd5b8386111561399f575f80fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156139d45780818660040360031b1b83161692505b505092915050565b5f805f805f805f60e0888a0312156139f2575f80fd5b87356139fd81612e58565b96506020880135613a0d81612e58565b95506040880135945060608801359350608088013561305781612fec565b5f805f805f805f80610100898b031215613a43575f80fd5b8835613a4e81612e58565b97506020890135613a5e81612e58565b965060408901359550606089013594506080890135613a7c81612ea4565b935060a0890135613a8c81612fec565b979a969950949793969295929450505060c08201359160e0013590565b600181815b80851115613ae357815f1904821115613ac957613ac96135d0565b80851615613ad657918102915b93841c9390800290613aae565b509250929050565b5f82613af9575060016106ca565b81613b0557505f6106ca565b8160018114613b1b5760028114613b2557613b41565b60019150506106ca565b60ff841115613b3657613b366135d0565b50506001821b6106ca565b5060208310610133831016604e8410600b8410161715613b64575081810a6106ca565b613b6e8383613aa9565b805f1904821115613b8157613b816135d0565b029392505050565b5f612fca8383613aeb565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215613bb8575f80fd5b815167ffffffffffffffff811115613bce575f80fd5b8201601f81018413613bde575f80fd5b8051613bec61319782613163565b818152856020838501011115613c00575f80fd5b613c11826020830160208601612f6b565b95945050505050565b5f60208284031215613c2a575f80fd5b8151612fca81612ea456fe6101006040523480156200001257600080fd5b5060405162001b6638038062001b6683398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516116aa620004bc6000396000610237015260008181610307015281816105c001526106a70152600061053a015260008181610379015261050401526116aa6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf1461039b578063dd62ed3e146103ae578063ffa1ad74146103f457600080fd5b8063a457c2d71461034e578063a9059cbb14610361578063cd0d00961461037457600080fd5b806395d89b41116100bd57806395d89b41146102e75780639dc29fac146102ef578063a3c573eb1461030257600080fd5b806370a08231146102915780637ecebe00146102c757600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b610184610430565b60405161019191906113e4565b60405180910390f35b6101ad6101a8366004611479565b6104c2565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad6102043660046114a3565b6104dc565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c1610500565b6101ad610277366004611479565b61055c565b61028f61028a366004611479565b6105a8565b005b6101c161029f3660046114df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101c16102d53660046114df565b60056020526000908152604090205481565b610184610680565b61028f6102fd366004611479565b61068f565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101ad61035c366004611479565b61075e565b6101ad61036f366004611479565b61082f565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103a9366004611501565b61083d565b6101c16103bc366004611574565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101846040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60606003805461043f906115a7565b80601f016020809104026020016040519081016040528092919081815260200182805461046b906115a7565b80156104b85780601f1061048d576101008083540402835291602001916104b8565b820191906000526020600020905b81548152906001019060200180831161049b57829003601f168201915b5050505050905090565b6000336104d0818585610b73565b60019150505b92915050565b6000336104ea858285610d27565b6104f5858585610dfe565b506001949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610537576105324661106d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104d090829086906105a3908790611629565b610b73565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b61067c8282611135565b5050565b60606004805461043f906115a7565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d427269646765000000000000000000000000000000006064820152608401610669565b61067c8282611228565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610822576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610669565b6104f58286868403610b73565b6000336104d0818585610dfe565b834211156108cc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d6974000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a9190866109268361163c565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610991610500565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610a55573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610ad057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e6174757265000000000000000000000000000000000000000000000000006064820152608401610669565b610b678a8a8a610b73565b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610df85781811015610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610669565b610df88484848403610b73565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610df8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611098610430565b8051602091820120604080518082018252600181527f310000000000000000000000000000000000000000000000000000000000000090840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff82166111b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610669565b80600260008282546111c49190611629565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166112cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610d1a565b600060208083528351808285015260005b81811015611411578581018301518582016040015282016113f5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461147457600080fd5b919050565b6000806040838503121561148c57600080fd5b61149583611450565b946020939093013593505050565b6000806000606084860312156114b857600080fd5b6114c184611450565b92506114cf60208501611450565b9150604084013590509250925092565b6000602082840312156114f157600080fd5b6114fa82611450565b9392505050565b600080600080600080600060e0888a03121561151c57600080fd5b61152588611450565b965061153360208901611450565b95506040880135945060608801359350608088013560ff8116811461155757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561158757600080fd5b61159083611450565b915061159e60208401611450565b90509250929050565b600181811c908216806115bb57607f821691505b6020821081036115f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104d6576104d66115fa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361166d5761166d6115fa565b506001019056fea26469706673582212208d88fee561cff7120d381c345cfc534cef8229a272dc5809d4bbb685ad67141164736f6c63430008110033a2646970667358221220b1fe94b20ec78ba8655e62b6a2f33873bb846d19da5ab9523a4def0b2135654564736f6c63430008140033" + }, + { + "contractName": "PolygonZkEVMBridgeV2 proxy", + "balance": "340282366920938463463374607431768211455", + "nonce": "1", + "address": "0xf93FA1eD44BbbE74855f6FaFD8e7c517F8aa3716", + "bytecode": "0x60806040526004361061005d575f3560e01c80635c60da1b116100425780635c60da1b146100a65780638f283970146100e3578063f851a440146101025761006c565b80633659cfe6146100745780634f1ef286146100935761006c565b3661006c5761006a610116565b005b61006a610116565b34801561007f575f80fd5b5061006a61008e366004610854565b610130565b61006a6100a136600461086d565b610178565b3480156100b1575f80fd5b506100ba6101eb565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ee575f80fd5b5061006a6100fd366004610854565b610228565b34801561010d575f80fd5b506100ba610255565b61011e610282565b61012e610129610359565b610362565b565b610138610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d8160405180602001604052805f8152505f6103bf565b50565b61016d610116565b610180610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101e3576101de8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250600192506103bf915050565b505050565b6101de610116565b5f6101f4610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610359565b905090565b610225610116565b90565b610230610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d816103e9565b5f61025e610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610380565b61028a610380565b73ffffffffffffffffffffffffffffffffffffffff16330361012e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b5f61021861044a565b365f80375f80365f845af43d5f803e80801561037c573d5ff35b3d5ffd5b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103c883610471565b5f825111806103d45750805b156101de576103e383836104bd565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610412610380565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161016d816104e9565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103a3565b61047a816105f5565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606104e28383604051806060016040528060278152602001610977602791396106c0565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff811661058c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610350565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b610699576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610350565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105af565b60605f808573ffffffffffffffffffffffffffffffffffffffff16856040516106e9919061090b565b5f60405180830381855af49150503d805f8114610721576040519150601f19603f3d011682016040523d82523d5f602084013e610726565b606091505b509150915061073786838387610741565b9695505050505050565b606083156107d65782515f036107cf5773ffffffffffffffffffffffffffffffffffffffff85163b6107cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610350565b50816107e0565b6107e083836107e8565b949350505050565b8151156107f85781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103509190610926565b803573ffffffffffffffffffffffffffffffffffffffff8116811461084f575f80fd5b919050565b5f60208284031215610864575f80fd5b6104e28261082c565b5f805f6040848603121561087f575f80fd5b6108888461082c565b9250602084013567ffffffffffffffff808211156108a4575f80fd5b818601915086601f8301126108b7575f80fd5b8135818111156108c5575f80fd5b8760208285010111156108d6575f80fd5b6020830194508093505050509250925092565b5f5b838110156109035781810151838201526020016108eb565b50505f910152565b5f825161091c8184602087016108e9565b9190910192915050565b602081525f82518060208401526109448160408501602087016108e9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202ac98acbfbb3d3ac1b74050e18c4e76db25a3ff2801ec69bf85d0c61414d502b64736f6c63430008140033", + "storage": { + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000fadb60b5059e31614e02083ff6c021a24c31c891", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000bc9585cb224a8f42ef9c9f0b99c531b450b11886" + } + }, + { + "contractName": "PolygonZkEVMGlobalExitRootL2", + "balance": "0", + "nonce": "1", + "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "bytecode": "0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806301fd90441461004e578063257b36321461006a57806333d6247d14610089578063a3c573eb1461009e575b5f80fd5b61005760015481565b6040519081526020015b60405180910390f35b61005761007836600461015e565b5f6020819052908152604090205481565b61009c61009736600461015e565b6100ea565b005b6100c57f000000000000000000000000f93fa1ed44bbbe74855f6fafd8e7c517f8aa371681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610061565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f93fa1ed44bbbe74855f6fafd8e7c517f8aa37161614610159576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b5f6020828403121561016e575f80fd5b503591905056fea2646970667358221220b0e055b3a526de8b3e41419aba10074521f2fc6fc76f05d25e4055bd2429ed5b64736f6c63430008140033" + }, + { + "contractName": "PolygonZkEVMGlobalExitRootL2 proxy", + "balance": "0", + "nonce": "1", + "address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa", + "bytecode": "0x60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033", + "storage": { + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000fadb60b5059e31614e02083ff6c021a24c31c891", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9" + } + }, + { + "contractName": "PolygonZkEVMTimelock", + "balance": "0", + "nonce": "1", + "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "bytecode": "0x6080604052600436106101bd575f3560e01c806364d62353116100f2578063b1c5f42711610092578063d547741f11610062578063d547741f1461063a578063e38335e514610659578063f23a6e611461066c578063f27a0c92146106b0575f80fd5b8063b1c5f4271461058d578063bc197c81146105ac578063c4d252f5146105f0578063d45c44351461060f575f80fd5b80638f61f4f5116100cd5780638f61f4f5146104c557806391d14854146104f8578063a217fddf14610547578063b08e51c01461055a575f80fd5b806364d62353146104685780638065657f146104875780638f2a0bb0146104a6575f80fd5b8063248a9ca31161015d57806331d507501161013857806331d50750146103b357806336568abe146103d25780633a6aae72146103f1578063584b153e14610449575f80fd5b8063248a9ca3146103375780632ab0f529146103655780632f2ff15d14610394575f80fd5b80630d3cf6fc116101985780630d3cf6fc1461025e578063134008d31461029157806313bc9f20146102a4578063150b7a02146102c3575f80fd5b806301d5062a146101c857806301ffc9a7146101e957806307bd02651461021d575f80fd5b366101c457005b5f80fd5b3480156101d3575f80fd5b506101e76101e2366004611bf6565b6106c4565b005b3480156101f4575f80fd5b50610208610203366004611c65565b610757565b60405190151581526020015b60405180910390f35b348015610228575f80fd5b506102507fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610214565b348015610269575f80fd5b506102507f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101e761029f366004611ca4565b6107b2565b3480156102af575f80fd5b506102086102be366004611d0b565b6108a7565b3480156102ce575f80fd5b506103066102dd366004611e28565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610214565b348015610342575f80fd5b50610250610351366004611d0b565b5f9081526020819052604090206001015490565b348015610370575f80fd5b5061020861037f366004611d0b565b5f908152600160208190526040909120541490565b34801561039f575f80fd5b506101e76103ae366004611e8c565b6108cc565b3480156103be575f80fd5b506102086103cd366004611d0b565b6108f5565b3480156103dd575f80fd5b506101e76103ec366004611e8c565b61090d565b3480156103fc575f80fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b348015610454575f80fd5b50610208610463366004611d0b565b6109c5565b348015610473575f80fd5b506101e7610482366004611d0b565b6109da565b348015610492575f80fd5b506102506104a1366004611ca4565b610aaa565b3480156104b1575f80fd5b506101e76104c0366004611ef7565b610ae8565b3480156104d0575f80fd5b506102507fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b348015610503575f80fd5b50610208610512366004611e8c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610552575f80fd5b506102505f81565b348015610565575f80fd5b506102507ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b348015610598575f80fd5b506102506105a7366004611fa0565b610d18565b3480156105b7575f80fd5b506103066105c63660046120be565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b3480156105fb575f80fd5b506101e761060a366004611d0b565b610d5c565b34801561061a575f80fd5b50610250610629366004611d0b565b5f9081526001602052604090205490565b348015610645575f80fd5b506101e7610654366004611e8c565b610e56565b6101e7610667366004611fa0565b610e7a565b348015610677575f80fd5b50610306610686366004612161565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106bb575f80fd5b50610250611121565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc16106ee81611200565b5f6106fd898989898989610aaa565b9050610709818461120d565b5f817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161074496959493929190612208565b60405180910390a3505050505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107ac57506107ac82611359565b92915050565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661082e5761082e81336113ef565b5f61083d888888888888610aaa565b905061084981856114a6565b610855888888886115e2565b5f817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161088c9493929190612252565b60405180910390a361089d816116e2565b5050505050505050565b5f818152600160205260408120546001811180156108c55750428111155b9392505050565b5f828152602081905260409020600101546108e681611200565b6108f0838361178a565b505050565b5f8181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109c18282611878565b5050565b5f818152600160208190526040822054610906565b333014610a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109ae565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b5f868686868686604051602001610ac696959493929190612208565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b1281611200565b888714610ba1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b888514610c30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f610c418b8b8b8b8b8b8b8b610d18565b9050610c4d818461120d565b5f5b8a811015610d0a5780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610c8c57610c8c612291565b9050602002016020810190610ca191906122be565b8d8d86818110610cb357610cb3612291565b905060200201358c8c87818110610ccc57610ccc612291565b9050602002810190610cde91906122d7565b8c8b604051610cf296959493929190612208565b60405180910390a3610d0381612365565b9050610c4f565b505050505050505050505050565b5f8888888888888888604051602001610d38989796959493929190612447565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610d8681611200565b610d8f826109c5565b610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109ae565b5f828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b5f82815260208190526040902060010154610e7081611200565b6108f08383611878565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610ef657610ef681336113ef565b878614610f85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b878414611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f6110258a8a8a8a8a8a8a8a610d18565b905061103181856114a6565b5f5b8981101561110b575f8b8b8381811061104e5761104e612291565b905060200201602081019061106391906122be565b90505f8a8a8481811061107857611078612291565b905060200201359050365f8a8a8681811061109557611095612291565b90506020028101906110a791906122d7565b915091506110b7848484846115e2565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b58868686866040516110ee9493929190612252565b60405180910390a3505050508061110490612365565b9050611033565b50611115816116e2565b50505050505050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16158015906111ef57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef919061250c565b156111f957505f90565b5060025490565b61120a81336113ef565b50565b611216826108f5565b156112a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109ae565b6112ab611121565b81101561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109ae565b611344814261252b565b5f928352600160205260409092209190915550565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107ac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107ac565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c15761142c8161192d565b61143783602061194c565b604051602001611448929190612560565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109ae916004016125e0565b6114af826108a7565b61153b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b80158061155657505f81815260016020819052604090912054145b6109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f8473ffffffffffffffffffffffffffffffffffffffff1684848460405161160b929190612630565b5f6040518083038185875af1925050503d805f8114611645576040519150601f19603f3d011682016040523d82523d5f602084013e61164a565b606091505b50509050806116db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109ae565b5050505050565b6116eb816108a7565b611777576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b5f90815260016020819052604090912055565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561181a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107ac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61195a83600261263f565b61196590600261252b565b67ffffffffffffffff81111561197d5761197d611d22565b6040519080825280601f01601f1916602001820160405280156119a7576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106119dd576119dd612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a3f57611a3f612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f611a7984600261263f565b611a8490600161252b565b90505b6001811115611b20577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611ac557611ac5612291565b1a60f81b828281518110611adb57611adb612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c93611b1981612656565b9050611a87565b5083156108c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109ae565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bac575f80fd5b919050565b5f8083601f840112611bc1575f80fd5b50813567ffffffffffffffff811115611bd8575f80fd5b602083019150836020828501011115611bef575f80fd5b9250929050565b5f805f805f805f60c0888a031215611c0c575f80fd5b611c1588611b89565b965060208801359550604088013567ffffffffffffffff811115611c37575f80fd5b611c438a828b01611bb1565b989b979a50986060810135976080820135975060a09091013595509350505050565b5f60208284031215611c75575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108c5575f80fd5b5f805f805f8060a08789031215611cb9575f80fd5b611cc287611b89565b955060208701359450604087013567ffffffffffffffff811115611ce4575f80fd5b611cf089828a01611bb1565b979a9699509760608101359660809091013595509350505050565b5f60208284031215611d1b575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d9657611d96611d22565b604052919050565b5f82601f830112611dad575f80fd5b813567ffffffffffffffff811115611dc757611dc7611d22565b611df860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d4f565b818152846020838601011115611e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215611e3b575f80fd5b611e4485611b89565b9350611e5260208601611b89565b925060408501359150606085013567ffffffffffffffff811115611e74575f80fd5b611e8087828801611d9e565b91505092959194509250565b5f8060408385031215611e9d575f80fd5b82359150611ead60208401611b89565b90509250929050565b5f8083601f840112611ec6575f80fd5b50813567ffffffffffffffff811115611edd575f80fd5b6020830191508360208260051b8501011115611bef575f80fd5b5f805f805f805f805f60c08a8c031215611f0f575f80fd5b893567ffffffffffffffff80821115611f26575f80fd5b611f328d838e01611eb6565b909b50995060208c0135915080821115611f4a575f80fd5b611f568d838e01611eb6565b909950975060408c0135915080821115611f6e575f80fd5b50611f7b8c828d01611eb6565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b5f805f805f805f8060a0898b031215611fb7575f80fd5b883567ffffffffffffffff80821115611fce575f80fd5b611fda8c838d01611eb6565b909a50985060208b0135915080821115611ff2575f80fd5b611ffe8c838d01611eb6565b909850965060408b0135915080821115612016575f80fd5b506120238b828c01611eb6565b999c989b509699959896976060870135966080013595509350505050565b5f82601f830112612050575f80fd5b8135602067ffffffffffffffff82111561206c5761206c611d22565b8160051b61207b828201611d4f565b9283528481018201928281019087851115612094575f80fd5b83870192505b848310156120b35782358252918301919083019061209a565b979650505050505050565b5f805f805f60a086880312156120d2575f80fd5b6120db86611b89565b94506120e960208701611b89565b9350604086013567ffffffffffffffff80821115612105575f80fd5b61211189838a01612041565b94506060880135915080821115612126575f80fd5b61213289838a01612041565b93506080880135915080821115612147575f80fd5b5061215488828901611d9e565b9150509295509295909350565b5f805f805f60a08688031215612175575f80fd5b61217e86611b89565b945061218c60208701611b89565b93506040860135925060608601359150608086013567ffffffffffffffff8111156121b5575f80fd5b61215488828901611d9e565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a060408201525f61223d60a0830186886121c1565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f6122876060830184866121c1565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156122ce575f80fd5b6108c582611b89565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261230a575f80fd5b83018035915067ffffffffffffffff821115612324575f80fd5b602001915036819003821315611bef575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361239557612395612338565b5060010190565b8183525f6020808501808196508560051b81019150845f5b8781101561243a57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126123f2575f80fd5b8701858101903567ffffffffffffffff81111561240d575f80fd5b80360382131561241b575f80fd5b6124268682846121c1565b9a87019a95505050908401906001016123b4565b5091979650505050505050565b60a080825281018890525f8960c08301825b8b8110156124945773ffffffffffffffffffffffffffffffffffffffff61247f84611b89565b16825260209283019290910190600101612459565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156124cc575f80fd5b8860051b9150818a602083013701828103602090810160408501526124f4908201878961239c565b60608401959095525050608001529695505050505050565b5f6020828403121561251c575f80fd5b815180151581146108c5575f80fd5b808201808211156107ac576107ac612338565b5f5b83811015612558578181015183820152602001612540565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f835161259781601785016020880161253e565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516125d481602884016020880161253e565b01602801949350505050565b602081525f82518060208401526125fe81604085016020870161253e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b818382375f9101908152919050565b80820281158282048414176107ac576107ac612338565b5f8161266457612664612338565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220af70dfb7a469eaff210674e43170a7e152bbb10571ef60492e6d753b73b32d1a64736f6c63430008140033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000e10", + "0xaedcc9e7897c0d335bdc5d92fe3a8b4f23727fe558cd1c19f332b28716a30559": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xf5e61edb9c9cc6bfbae4463e9a2b1dd6ac3b44ddef38f18016e56ba0363910d9": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x64494413541ff93b31aa309254e3fed72a7456e9845988b915b4c7a7ceba8814": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", + "0x60b9d94c75b7b3f721925089391e4644cd890cb5e6466f9596dfbd2c54e0b280": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x3412d5605ac6cd444957cedb533e5dacad6378b4bc819ebe3652188a665066d6": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", + "0x4b63b79f1e338a49559dcd3193ac9eecc50d0f275d24e97cc8c319e5a31a8bd0": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d706a": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", + "0x800d5dfe4bba53eedee06cd4546a27da8de00f12db83f56062976d4493fda899": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xc3ad33e20b0c56a223ad5104fff154aa010f8715b9c981fd38fdc60a4d1a52fc": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5" + } + }, + { + "accountName": "keyless Deployer", + "balance": "0", + "nonce": "1", + "address": "0x694AB5383a002a4796f95530c14Cf0C25ec3EA03" + }, + { + "accountName": "deployer", + "balance": "100000000000000000000000", + "nonce": "8", + "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + } + ] +} \ No newline at end of file From a67a670565c89617315ab9a943c11decdda37c5f Mon Sep 17 00:00:00 2001 From: Ignasi Date: Fri, 22 Nov 2024 20:22:55 +0700 Subject: [PATCH 06/12] Update create rollup script with last fixes --- tools/createNewRollup/createNewRollup.ts | 74 ++++++++++++++----- .../create_new_rollup.json.example | 3 +- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index 02bb1430b..6e67f4804 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -59,6 +59,15 @@ async function main() { isVanillaClient, sovereignParams, } = createRollupParameters; + + const supportedConsensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]; + + if (!supportedConsensus.includes(consensusContractName)) { + throw new Error( + `Consensus contract ${consensusContractName} not supported, supported contracts are: ${supportedConsensus}` + ); + } + // Check consensus compatibility if (isVanillaClient) { if (consensusContractName !== "PolygonPessimisticConsensus") { @@ -70,6 +79,7 @@ async function main() { "sovereignWETHAddress", "sovereignWETHAddressIsNotMintable", "globalExitRootUpdater", + "globalExitRootRemover", ]; for (const parameterName of mandatorySovereignParams) { if (typeof sovereignParams[parameterName] === undefined || sovereignParams[parameterName] === "") { @@ -146,19 +156,21 @@ async function main() { } // Check chainID - const rollupID = await rollupManagerContract.chainIDToRollupID(chainID); - if(Number(rollupID) !== 0) { + let rollupID = await rollupManagerContract.chainIDToRollupID(chainID); + if (Number(rollupID) !== 0) { throw new Error(`Rollup with chainID ${chainID} already exists`); } // Check rollupTypeId const rollupType = await rollupManagerContract.rollupTypeMap(createRollupParameters.rollupTypeId); const consensusContractAddress = rollupType[0]; - const verifierType = rollupType[3]; - if(consensusContractName === "PolygonPessimisticConsensus") { - expect(verifierType).to.be.equal(1); - } else { - expect(verifierType).to.be.equal(0); + const verifierType = Number(rollupType[3]); + if (consensusContractName === "PolygonPessimisticConsensus" && verifierType !== 1) { + throw new Error(`Verifier type should be 1 for ${consensusContractName}`); + } + if (consensusContractName !== "PolygonPessimisticConsensus" && verifierType !== 0) { + throw new Error(`Verifier type should be 0 for ${consensusContractName}`); } + // Grant role CREATE_ROLLUP_ROLE to deployer const CREATE_ROLLUP_ROLE = ethers.id("CREATE_ROLLUP_ROLE"); if ((await rollupManagerContract.hasRole(CREATE_ROLLUP_ROLE, deployer.address)) == false) @@ -172,7 +184,7 @@ async function main() { // Create new rollup const txDeployRollup = await rollupManagerContract.createNewRollup( - createRollupParameters.rollupTypeId, + createRollupParameters.rollupTypeId, chainID, rollupAdminAddress, trustedSequencer, @@ -189,14 +201,43 @@ async function main() { console.log("#######################\n"); console.log(`Created new ${consensusContractName} Rollup:`, createdRollupAddress); + // Update rollupId + rollupID = await rollupManagerContract.chainIDToRollupID(chainID); + + const polygonConsensusFactory = (await ethers.getContractFactory(consensusContractName, deployer)) as any; + const dataAvailabilityProtocol = createRollupParameters.dataAvailabilityProtocol || "PolygonDataCommittee"; + if (consensusContractName.includes("PolygonValidiumEtrog") && dataAvailabilityProtocol === "PolygonDataCommittee") { + // deploy data committee + const PolygonDataCommitteeContract = (await ethers.getContractFactory("PolygonDataCommittee", deployer)) as any; + let polygonDataCommittee = await upgrades.deployProxy(PolygonDataCommitteeContract, [], { + unsafeAllow: ["constructor"], + }); + await polygonDataCommittee?.waitForDeployment(); + + // Load data commitee + const PolygonValidiumContract = (await polygonConsensusFactory.attach( + createdRollupAddress + )) as PolygonValidiumEtrog; + // add data commitee to the consensus contract + if ((await PolygonValidiumContract.admin()) == deployer.address) { + await ( + await PolygonValidiumContract.setDataAvailabilityProtocol(polygonDataCommittee?.target as any) + ).wait(); + + // // Setup data commitee to 0 + // await (await polygonDataCommittee?.setupCommittee(0, [], "0x")).wait(); + } else { + await (await polygonDataCommittee?.transferOwnership(rollupAdminAddress)).wait(); + } + + outputJson.polygonDataCommitteeAddress = polygonDataCommittee?.target; + } + // Assert admin address expect(await upgrades.erc1967.getAdminAddress(createdRollupAddress)).to.be.equal(rollupManagerContract.target); - expect(await upgrades.erc1967.getImplementationAddress(createdRollupAddress)).to.be.equal( - consensusContractAddress - ); + expect(await upgrades.erc1967.getImplementationAddress(createdRollupAddress)).to.be.equal(consensusContractAddress); // Search added global exit root on the logs - const polygonConsensusFactory = (await ethers.getContractFactory(consensusContractName, deployer)) as any; let globalExitRoot; for (const log of receipt?.logs) { if (log.address == createdRollupAddress) { @@ -212,9 +253,7 @@ async function main() { // Get bridge instance const bridgeFactory = await ethers.getContractFactory("PolygonZkEVMBridgeV2", deployer); const bridgeContractAddress = await rollupManagerContract.bridgeAddress(); - const rollupBridgeContract = bridgeFactory.attach( - bridgeContractAddress - ) as PolygonZkEVMBridgeV2; + const rollupBridgeContract = bridgeFactory.attach(bridgeContractAddress) as PolygonZkEVMBridgeV2; if ( ethers.isAddress(createRollupParameters.gasTokenAddress) && createRollupParameters.gasTokenAddress !== ethers.ZeroAddress @@ -228,9 +267,7 @@ async function main() { `Invalid gas token address, no ERC20 token deployed at the selected gas token network ${createRollupParameters.gasTokenAddress}` ); } - const wrappedData = await rollupBridgeContract.wrappedTokenToTokenInfo( - createRollupParameters.gasTokenAddress - ); + const wrappedData = await rollupBridgeContract.wrappedTokenToTokenInfo(createRollupParameters.gasTokenAddress); if (wrappedData.originNetwork != 0n) { // Wrapped token gasTokenAddress = wrappedData.originTokenAddress; @@ -259,6 +296,7 @@ async function main() { sovereignWETHAddress: sovereignParams.sovereignWETHAddress, sovereignWETHAddressIsNotMintable: sovereignParams.sovereignWETHAddressIsNotMintable, globalExitRootUpdater: sovereignParams.globalExitRootUpdater, + globalExitRootRemover: sovereignParams.globalExitRootRemover, }; genesis = await updateVanillaGenesis(genesis, chainID, initializeParams); // Add weth address to deployment output if gas token address is provided and sovereignWETHAddress is not provided diff --git a/tools/createNewRollup/create_new_rollup.json.example b/tools/createNewRollup/create_new_rollup.json.example index 156aa3cd1..755defc54 100644 --- a/tools/createNewRollup/create_new_rollup.json.example +++ b/tools/createNewRollup/create_new_rollup.json.example @@ -17,6 +17,7 @@ "bridgeManager": "0xC7899Ff6A3aC2FF59261bD960A8C880DF06E1041", "sovereignWETHAddress": "0x0000000000000000000000000000000000000000", "sovereignWETHAddressIsNotMintable": false, - "globalExitRootUpdater": "0xB55B27Cca633A73108893985350bc26B8A00C43a" + "globalExitRootUpdater": "0xB55B27Cca633A73108893985350bc26B8A00C43a", + "globalExitRootRemover": "0xB55B27Cca633A73108893985350bc26B8A00C43a" } } \ No newline at end of file From e38fc43db0d161dd05cd4f1078069220cc3a9db3 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Mon, 25 Nov 2024 18:40:11 +0700 Subject: [PATCH 07/12] Improved comments and readme --- tools/createNewRollup/README.md | 7 ++++--- tools/createNewRollup/createNewRollup.ts | 25 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/createNewRollup/README.md b/tools/createNewRollup/README.md index 65139da3b..07a6e9e81 100644 --- a/tools/createNewRollup/README.md +++ b/tools/createNewRollup/README.md @@ -1,5 +1,6 @@ # Add Rollup Type -Script to call `createNewRollup` function +Script to call `createNewRollup` function. +- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, a new `genesis_sovereign.json` will be created. ## Install ``` @@ -36,7 +37,7 @@ npm i ``` cp ./tools/createNewRollup/create_new_rollup.json.example ./tools/createNewRollup/create_new_rollup.json ``` - +- Copy genesis file (only for sovereign chains) ``` cp ./tools/addRollupType/genesis.json.example ./tools/addRollupType/genesis.json ``` @@ -45,4 +46,4 @@ cp ./tools/addRollupType/genesis.json.example ./tools/addRollupType/genesis.json - Run tool: ``` npx hardhat run ./tools/addRollupType/createNewRollup.ts --network sepolia -``` \ No newline at end of file +``` diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index 6e67f4804..e8ef873a1 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -7,13 +7,10 @@ import fs = require("fs"); import * as dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname, "../../.env")}); import {ethers, upgrades} from "hardhat"; - -const pathGenesis = path.join(__dirname, "./genesis.json"); -const pathGenesisSovereign = path.join(__dirname, "./genesis_sovereign.json"); import {processorUtils, Constants} from "@0xpolygonhermez/zkevm-commonjs"; const createRollupParameters = require("./create_new_rollup.json"); -let genesis = require(pathGenesis); + import updateVanillaGenesis from "../../deployment/v2/utils/updateVanillaGenesis"; const pathOutputJson = path.join(__dirname, "./create_new_rollup_output.json"); @@ -60,6 +57,7 @@ async function main() { sovereignParams, } = createRollupParameters; + // Check supported consensus is correct const supportedConsensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]; if (!supportedConsensus.includes(consensusContractName)) { @@ -148,6 +146,7 @@ async function main() { globalExitRootManagerAddress ) as PolygonRollupManager; + // Check if the deployer has right to deploy new rollups from rollupManager contract const DEFAULT_ADMIN_ROLE = ethers.ZeroHash; if ((await rollupManagerContract.hasRole(DEFAULT_ADMIN_ROLE, deployer.address)) == false) { throw new Error( @@ -176,6 +175,7 @@ async function main() { if ((await rollupManagerContract.hasRole(CREATE_ROLLUP_ROLE, deployer.address)) == false) await rollupManagerContract.grantRole(CREATE_ROLLUP_ROLE, deployer.address); + // Get rollup address deterministically const nonce = await currentProvider.getTransactionCount(rollupManagerContract.target); const createdRollupAddress = ethers.getCreateAddress({ from: rollupManagerContract.target as string, @@ -204,6 +204,7 @@ async function main() { // Update rollupId rollupID = await rollupManagerContract.chainIDToRollupID(chainID); + // If is a validium, data committee must be set up const polygonConsensusFactory = (await ethers.getContractFactory(consensusContractName, deployer)) as any; const dataAvailabilityProtocol = createRollupParameters.dataAvailabilityProtocol || "PolygonDataCommittee"; if (consensusContractName.includes("PolygonValidiumEtrog") && dataAvailabilityProtocol === "PolygonDataCommittee") { @@ -214,17 +215,17 @@ async function main() { }); await polygonDataCommittee?.waitForDeployment(); - // Load data commitee + // Load data committee const PolygonValidiumContract = (await polygonConsensusFactory.attach( createdRollupAddress )) as PolygonValidiumEtrog; - // add data commitee to the consensus contract + // add data committee to the consensus contract if ((await PolygonValidiumContract.admin()) == deployer.address) { await ( await PolygonValidiumContract.setDataAvailabilityProtocol(polygonDataCommittee?.target as any) ).wait(); - // // Setup data commitee to 0 + // // Setup data committee to 0 // await (await polygonDataCommittee?.setupCommittee(0, [], "0x")).wait(); } else { await (await polygonDataCommittee?.transferOwnership(rollupAdminAddress)).wait(); @@ -286,6 +287,8 @@ async function main() { let batchData = ""; // If is vanilla client, replace genesis by sovereign contracts, else, inject initialization batch if (isVanillaClient) { + const pathGenesis = path.join(__dirname, "./genesis.json"); + let genesis = require(pathGenesis); const initializeParams = { rollupID: rollupID, gasTokenAddress, @@ -311,6 +314,7 @@ async function main() { }); outputJson.WETHAddress = wethObject.address; } + fs.writeFileSync(pathGenesis, JSON.stringify(genesis, null, 1)); } else { if (consensusContractName === "PolygonPessimisticConsensus") { // Add the first batch of the created rollup @@ -382,16 +386,11 @@ async function main() { } } outputJson.firstBatchData = batchData; - outputJson.genesis = genesis.root; + outputJson.genesis = rollupType.genesis; outputJson.createRollupBlockNumber = blockDeploymentRollup.number; outputJson.rollupAddress = createdRollupAddress; outputJson.consensusContract = consensusContractName; outputJson.rollupID = Number(rollupID); - // Rewrite updated genesis in case of vanilla client - if (isVanillaClient) { - fs.writeFileSync(pathGenesisSovereign, JSON.stringify(genesis, null, 1)); - } - fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); } main().catch((e) => { From f988f1cfec16c215ca7cfec0815ff8c2249193d2 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 28 Nov 2024 14:21:21 +0700 Subject: [PATCH 08/12] krlos review remediations --- deployment/v2/4_createRollup.ts | 4 +- hardhat.config.ts | 6 +- src/pessimistic-utils.js | 7 ++ tools/addRollupType/README.md | 10 +-- tools/addRollupType/addRollupType.ts | 50 +++++------ tools/createNewRollup/.gitignore | 1 + tools/createNewRollup/README.md | 70 +++++++++------ tools/createNewRollup/createNewRollup.ts | 89 +++++++++++++------ .../create_new_rollup.json.example | 4 +- .../.gitignore | 1 + 10 files changed, 153 insertions(+), 89 deletions(-) create mode 100644 tools/createSovereignGenesisWithHardhat/.gitignore diff --git a/deployment/v2/4_createRollup.ts b/deployment/v2/4_createRollup.ts index c890f0c6f..d566aed2c 100644 --- a/deployment/v2/4_createRollup.ts +++ b/deployment/v2/4_createRollup.ts @@ -377,7 +377,9 @@ async function main() { } let batchData = ""; - // If is vanilla client, replace genesis by sovereign contracts, else, inject initialization batch + /** + If the system is running a "vanilla client" (i.e., a basic, unmodified Ethereum client or rollup setup), the genesis block should include the deployment of the sovereign contracts, and these contracts should already be initialized with their required initial state and configurations. This means that the genesis block will contain the initial state for these contracts, allowing the system to start running without needing any additional initialization steps. However, for other rollups, additional configuration is needed. In this case, instead of having everything pre-initialized in the genesis block, we must inject an "initialization batch" into the genesis file. This batch will contain specific instructions for initializing the contracts at the time of rollup deployment. The injected initialization batch allows the system to be configured dynamically during deployment. + */ if (isVanillaClient) { const initializeParams = { rollupID: rollupID, diff --git a/hardhat.config.ts b/hardhat.config.ts index 9c4bb60cd..8b79a2ebe 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -90,7 +90,7 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - runs: 500, + runs: 500, // Should have the same optimizations as PolygonTransparentProxy }, evmVersion: "shanghai", }, // try yul optimizer @@ -110,7 +110,7 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - runs: 200, + runs: 500, // Should have the same optimizations as PolygonTransparentProxy }, evmVersion: "shanghai", }, // try yul optimizer @@ -120,7 +120,7 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - runs: 10, + runs: 500, // Should have the same optimizations as PolygonTransparentProxy }, evmVersion: "shanghai", }, // try yul optimizer diff --git a/src/pessimistic-utils.js b/src/pessimistic-utils.js index 80054a815..a1c0bdac3 100644 --- a/src/pessimistic-utils.js +++ b/src/pessimistic-utils.js @@ -9,6 +9,12 @@ const ConsensusTypes = { Ecdsa: 0, }; +const ConsensusContracts = { + PolygonZkEVMEtrog: 'PolygonZkEVMEtrog', + PolygonValidiumEtrog: 'PolygonValidiumEtrog', + PolygonPessimisticConsensus: 'PolygonPessimisticConsensus', + +}; /** * Compute input for SNARK circuit: sha256( * initStateRoot, initBlobStateRoot, initBlobAccInputHash, initNumBlob, chainId, forkID @@ -60,4 +66,5 @@ module.exports = { ConsensusTypes, computeInputPessimisticBytes, computeConsensusHashEcdsa, + ConsensusContracts, }; diff --git a/tools/addRollupType/README.md b/tools/addRollupType/README.md index c3863a178..5c95a7ad7 100644 --- a/tools/addRollupType/README.md +++ b/tools/addRollupType/README.md @@ -9,20 +9,20 @@ npm i ## Setup - Config file - `consensusContract`: select between consensus contract. Supported: `["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]` - - `consensusContractAddress`: gets this address instead of deployong a new consensus implementation + - `consensusContractAddress`: gets this address instead of deploying a new consensus implementation - `polygonRollupManagerAddress`: polygonRollupManager smart contract address - `verifierAddress`: verifier to be used - `description`: string to describe rollup type added. Example: "Type: Validium, Version: etrog, genesis: /ipfs/QmUXnRoPbUmZuEZCGyiHjEsoNcFVu3hLtSvhpnfBS2mAYU" - `forkID`: forkID to be used - - `programVKey`: program key for pessimsitic consensus + - `programVKey`: program key for pessimistic consensus - `genesisRoot`: initial genesis root. Must match the `genesis.json` generated. - `timelockDelay`: timelock delay - `timelockSalt(optional)`: timelock salt - `predecessor(optional)`: timelock predecessor - `deployerPvtKey(optional)`: private key deployer - First option will load `deployerPvtKey`. Otherwise, `process.env.MNEMONIC` will be loaded from the `.env` file - - `maxFeePerGas(optional)`: string, Set `maxFeePerGas`, must define aswell `maxPriorityFeePerGas` to use it - - `maxPriorityFeePerGas(optional)`: string, Set `maxPriorityFeePerGas`, must define aswell `maxFeePerGas` to use it + - `maxFeePerGas(optional)`: string, Set `maxFeePerGas`, must define as well `maxPriorityFeePerGas` to use it + - `maxPriorityFeePerGas(optional)`: string, Set `maxPriorityFeePerGas`, must define as well `maxFeePerGas` to use it - `multiplierGas(optional)`: number, Gas multiplier with 3 decimals. If `maxFeePerGas` and `maxPriorityFeePerGas` are set, this will not take effect - A network should be selected when running the script - examples: `-- sepolia` or `--mainnet` @@ -66,6 +66,6 @@ npx hardhat run ./tools/addRollupType/addRollupType.ts --network sepolia - scheduleData - executeData > send data to the timelock contract address: -> - use your favourite browser extension +> - use your favorite browser extension > - send tx to timelock address with hex data as `scheduleData` > - wait timelockDelay and then send `executeData` to timelock address \ No newline at end of file diff --git a/tools/addRollupType/addRollupType.ts b/tools/addRollupType/addRollupType.ts index 17fb0ea1f..25584a6e0 100644 --- a/tools/addRollupType/addRollupType.ts +++ b/tools/addRollupType/addRollupType.ts @@ -8,7 +8,7 @@ import * as dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname, "../../.env")}); import {ethers, upgrades} from "hardhat"; -const addRollupParameters = require("./add_rollup_type.json"); +const addRollupTypeParameters = require("./add_rollup_type.json"); const genesis = require("./genesis.json"); const dateStr = new Date().toISOString(); @@ -35,7 +35,7 @@ async function main() { ]; for (const parameterName of mandatoryDeploymentParameters) { - if (addRollupParameters[parameterName] === undefined || addRollupParameters[parameterName] === "") { + if (addRollupTypeParameters[parameterName] === undefined || addRollupTypeParameters[parameterName] === "") { throw new Error(`Missing parameter: ${parameterName}`); } } @@ -48,7 +48,7 @@ async function main() { verifierAddress, genesisRoot, programVKey, - } = addRollupParameters; + } = addRollupTypeParameters; const supportedConsensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]; const isPessimistic = consensusContract === "PolygonPessimisticConsensus"; @@ -59,30 +59,30 @@ async function main() { // Load provider let currentProvider = ethers.provider; - if (addRollupParameters.multiplierGas || addRollupParameters.maxFeePerGas) { + if (addRollupTypeParameters.multiplierGas || addRollupTypeParameters.maxFeePerGas) { if (process.env.HARDHAT_NETWORK !== "hardhat") { currentProvider = ethers.getDefaultProvider( `https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}` ) as any; - if (addRollupParameters.maxPriorityFeePerGas && addRollupParameters.maxFeePerGas) { + if (addRollupTypeParameters.maxPriorityFeePerGas && addRollupTypeParameters.maxFeePerGas) { console.log( - `Hardcoded gas used: MaxPriority${addRollupParameters.maxPriorityFeePerGas} gwei, MaxFee${addRollupParameters.maxFeePerGas} gwei` + `Hardcoded gas used: MaxPriority${addRollupTypeParameters.maxPriorityFeePerGas} gwei, MaxFee${addRollupTypeParameters.maxFeePerGas} gwei` ); const FEE_DATA = new ethers.FeeData( null, - ethers.parseUnits(addRollupParameters.maxFeePerGas, "gwei"), - ethers.parseUnits(addRollupParameters.maxPriorityFeePerGas, "gwei") + ethers.parseUnits(addRollupTypeParameters.maxFeePerGas, "gwei"), + ethers.parseUnits(addRollupTypeParameters.maxPriorityFeePerGas, "gwei") ); currentProvider.getFeeData = async () => FEE_DATA; } else { - console.log("Multiplier gas used: ", addRollupParameters.multiplierGas); + console.log("Multiplier gas used: ", addRollupTypeParameters.multiplierGas); async function overrideFeeData() { const feedata = await ethers.provider.getFeeData(); return new ethers.FeeData( null, - ((feedata.maxFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n, - ((feedata.maxPriorityFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n + ((feedata.maxFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n, + ((feedata.maxPriorityFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n ); } currentProvider.getFeeData = overrideFeeData; @@ -92,8 +92,8 @@ async function main() { // Load deployer let deployer; - if (addRollupParameters.deployerPvtKey) { - deployer = new ethers.Wallet(addRollupParameters.deployerPvtKey, currentProvider); + if (addRollupTypeParameters.deployerPvtKey) { + deployer = new ethers.Wallet(addRollupTypeParameters.deployerPvtKey, currentProvider); } else if (process.env.MNEMONIC) { deployer = ethers.HDNodeWallet.fromMnemonic( ethers.Mnemonic.fromPhrase(process.env.MNEMONIC), @@ -126,7 +126,7 @@ async function main() { // get bridge address in genesis file let genesisBridgeAddress = ethers.ZeroAddress; for (let i = 0; i < genesis.genesis.length; i++) { - if (genesis.genesis[i].contractName === "PolygonZkEVMBridge proxy") { + if (genesis.genesis[i].contractName === "PolygonZkEVMBridgeV2 proxy") { genesisBridgeAddress = genesis.genesis[i].address; break; } @@ -134,7 +134,7 @@ async function main() { if (polygonZkEVMBridgeAddress.toLowerCase() !== genesisBridgeAddress.toLowerCase()) { throw new Error( - `'PolygonZkEVMBridge proxy' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` + `'PolygonZkEVMBridgeV2 proxy' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` ); } } @@ -158,29 +158,29 @@ async function main() { let consensusContractAddress; if ( - typeof addRollupParameters.consensusContractAddress !== "undefined" && - ethers.isAddress(addRollupParameters.consensusContractAddress) + typeof addRollupTypeParameters.consensusContractAddress !== "undefined" && + ethers.isAddress(addRollupTypeParameters.consensusContractAddress) ) { - consensusContractAddress = addRollupParameters.consensusContractAddress; + consensusContractAddress = addRollupTypeParameters.consensusContractAddress; } else { - const PolygonconsensusFactory = (await ethers.getContractFactory(consensusContract, deployer)) as any; - let PolygonconsensusContract; + const PolygonConsensusFactory = (await ethers.getContractFactory(consensusContract, deployer)) as any; + let PolygonConsensusContract; - PolygonconsensusContract = await PolygonconsensusFactory.deploy( + PolygonConsensusContract = await PolygonConsensusFactory.deploy( polygonZkEVMGlobalExitRootAddress, polTokenAddress, polygonZkEVMBridgeAddress, polygonRollupManagerAddress ); - await PolygonconsensusContract.waitForDeployment(); + await PolygonConsensusContract.waitForDeployment(); console.log("#######################\n"); console.log(`new consensus name: ${consensusContract}`); - console.log(`new PolygonconsensusContract impl: ${PolygonconsensusContract.target}`); + console.log(`new PolygonConsensusContract impl: ${PolygonConsensusContract.target}`); console.log("you can verify the new impl address with:"); console.log( - `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonconsensusContract.target} --network ${process.env.HARDHAT_NETWORK}\n` + `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonConsensusContract.target} --network ${process.env.HARDHAT_NETWORK}\n` ); console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", [ polygonZkEVMGlobalExitRootAddress, @@ -189,7 +189,7 @@ async function main() { polygonRollupManagerAddress, ]); - consensusContractAddress = PolygonconsensusContract.target; + consensusContractAddress = PolygonConsensusContract.target; } // Add a new rollup type diff --git a/tools/createNewRollup/.gitignore b/tools/createNewRollup/.gitignore index b3b265ed1..8b0e11ef9 100644 --- a/tools/createNewRollup/.gitignore +++ b/tools/createNewRollup/.gitignore @@ -2,3 +2,4 @@ create_new_rollup.json genesis.json genesis_sovereign.json create_new_rollup_output.json +create_new_rollup_output*.json diff --git a/tools/createNewRollup/README.md b/tools/createNewRollup/README.md index 07a6e9e81..0108fa49b 100644 --- a/tools/createNewRollup/README.md +++ b/tools/createNewRollup/README.md @@ -1,49 +1,61 @@ -# Add Rollup Type -Script to call `createNewRollup` function. -- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, a new `genesis_sovereign.json` will be created. +# Create new Rollup + +Script to call `createNewRollup` function. + +- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, a new `genesis_sovereign.json` will be created. ## Install + ``` npm i ``` ## Setup -- Config file - - `trustedSequencerURL`: Sequencer URL of the new created rollup - - `networkName`: Network name of the new created rollup - - `trustedSequencer`: Sequencer address of the new created rollup - - `chainID`: ChainID of the rollup, must be a new one, can not have more than 32 bits - - `rollupAdminAddress`: Admin address of the new created rollup - - `consensusContractName`: select between consensus contract. Supported: `["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]` This is the name of the consensus of the rollupType of the rollup to be created - - `gasTokenAddress`: Address of the native gas token of the rollup, zero if ether - - `deployerPvtKey`: Not mandatory, used to deploy from specific wallet - - `maxFeePerGas(optional)`: string, Set `maxFeePerGas`, must define aswell `maxPriorityFeePerGas` to use it - - `maxPriorityFeePerGas(optional)`: string, Set `maxPriorityFeePerGas`, must define aswell `maxFeePerGas` to use it - - `multiplierGas(optional)`: number, Gas multiplier with 3 decimals. If `maxFeePerGas` and `maxPriorityFeePerGas` are set, this will not take effect - - `rollupManagerAddress`: Address of deployed rollupManager contract - - `isVanillaClient`: Flag for vanilla/sovereign clients handling - - `sovereignParams`: - - `bridgeManager`: bridge manager address - - `sovereignWETHAddress`: sovereign WETH address - - `sovereignWETHAddressIsNotMintable`: Flag to indicate if the wrapped ETH is not mintable - - `globalExitRootUpdater`: Address of globalExitRootUpdater for sovereign chains + +- Config file + - `trustedSequencerURL`: Sequencer URL of the new created rollup + - `networkName`: Network name of the new created rollup + - `trustedSequencer`: Sequencer address of the new created rollup + - `chainID`: ChainID of the rollup, must be a new one, can not have more than 32 bits + - `rollupAdminAddress`: Admin address of the new created rollup + - `consensusContractName`: select between consensus contract. Supported: `["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]`. This is the name of the consensus of the rollupType of the rollup to be created + - `gasTokenAddress`: Address of the native gas token of the rollup, zero if ether + - `deployerPvtKey`: Not mandatory, used to deploy from specific wallet + - `maxFeePerGas(optional)`: string, Set `maxFeePerGas`, must define as well `maxPriorityFeePerGas` to use it + - `maxPriorityFeePerGas(optional)`: string, Set `maxPriorityFeePerGas`, must define as well `maxFeePerGas` to use it + - `multiplierGas(optional)`: number, Gas multiplier with 3 decimals. If `maxFeePerGas` and `maxPriorityFeePerGas` are set, this will not take effect + - `timelockDelay`: timelock delay, if is zero, no timelock is executed, direct deploy + - `timelockSalt(optional)`: timelock salt + - `rollupManagerAddress`: Address of deployed rollupManager contract + - `isVanillaClient`: Flag for vanilla/sovereign clients handling + - `sovereignParams`: + - `bridgeManager`: bridge manager address + - `sovereignWETHAddress`: sovereign WETH address + - `sovereignWETHAddressIsNotMintable`: Flag to indicate if the wrapped ETH is not mintable + - `globalExitRootUpdater`: Address of globalExitRootUpdater for sovereign chains + - `globalExitRootRemover`: Address of globalExitRootRemover for sovereign chains ## Usage + > All commands are done from root repository. -### Call 'addNewRollupType' from an EOA +### Call 'createNewRollup' from an EOA + +- Copy configuration files: -- Copy configuration files: ``` cp ./tools/createNewRollup/create_new_rollup.json.example ./tools/createNewRollup/create_new_rollup.json ``` -- Copy genesis file (only for sovereign chains) + +- Copy genesis file (only for sovereign chains) + ``` -cp ./tools/addRollupType/genesis.json.example ./tools/addRollupType/genesis.json +cp ./tools/createNewRollup/genesis.json.example ./tools/createNewRollup/genesis.json ``` -- Set your parameters -- Run tool: +- Set your parameters +- Run tool: + ``` -npx hardhat run ./tools/addRollupType/createNewRollup.ts --network sepolia +npx hardhat run ./tools/createNewRollup/createNewRollup.ts --network sepolia ``` diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index e8ef873a1..bfc022a65 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -3,16 +3,14 @@ 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} from "hardhat"; import {processorUtils, Constants} from "@0xpolygonhermez/zkevm-commonjs"; - +import {VerifierType, ConsensusContracts} from "../../src/pessimistic-utils"; const createRollupParameters = require("./create_new_rollup.json"); import updateVanillaGenesis from "../../deployment/v2/utils/updateVanillaGenesis"; -const pathOutputJson = path.join(__dirname, "./create_new_rollup_output.json"); import { PolygonRollupManager, @@ -23,6 +21,7 @@ import { } from "../../typechain-types"; async function main() { + console.log("Starting script to create new rollup..."); const outputJson = {} as any; /* * Check deploy parameters @@ -58,7 +57,11 @@ async function main() { } = createRollupParameters; // Check supported consensus is correct - const supportedConsensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog", "PolygonPessimisticConsensus"]; + const supportedConsensus = [ + ConsensusContracts.PolygonZkEVMEtrog, + ConsensusContracts.PolygonValidiumEtrog, + ConsensusContracts.PolygonPessimisticConsensus, + ]; if (!supportedConsensus.includes(consensusContractName)) { throw new Error( @@ -107,11 +110,11 @@ async function main() { } else { console.log("Multiplier gas used: ", createRollupParameters.multiplierGas); async function overrideFeeData() { - const feedata = await ethers.provider.getFeeData(); + const feeData = await ethers.provider.getFeeData(); return new ethers.FeeData( null, - ((feedata.maxFeePerGas as bigint) * BigInt(createRollupParameters.multiplierGas)) / 1000n, - ((feedata.maxPriorityFeePerGas as bigint) * BigInt(createRollupParameters.multiplierGas)) / + ((feeData.maxFeePerGas as bigint) * BigInt(createRollupParameters.multiplierGas)) / 1000n, + ((feeData.maxPriorityFeePerGas as bigint) * BigInt(createRollupParameters.multiplierGas)) / 1000n ); } @@ -153,7 +156,7 @@ async function main() { `Deployer does not have admin role. Use the test flag on deploy_parameters if this is a test deployment` ); } - + const polygonConsensusFactory = (await ethers.getContractFactory(consensusContractName, deployer)) as any; // Check chainID let rollupID = await rollupManagerContract.chainIDToRollupID(chainID); if (Number(rollupID) !== 0) { @@ -163,13 +166,39 @@ async function main() { const rollupType = await rollupManagerContract.rollupTypeMap(createRollupParameters.rollupTypeId); const consensusContractAddress = rollupType[0]; const verifierType = Number(rollupType[3]); - if (consensusContractName === "PolygonPessimisticConsensus" && verifierType !== 1) { - throw new Error(`Verifier type should be 1 for ${consensusContractName}`); + if ( + consensusContractName === ConsensusContracts.PolygonPessimisticConsensus && + verifierType !== VerifierType.Pessimistic + ) { + throw new Error(`Verifier type should be ${VerifierType.StateTransition} for ${consensusContractName}`); } - if (consensusContractName !== "PolygonPessimisticConsensus" && verifierType !== 0) { - throw new Error(`Verifier type should be 0 for ${consensusContractName}`); + if (consensusContractName !== ConsensusContracts.PolygonPessimisticConsensus) { + if (verifierType !== VerifierType.StateTransition) { + throw new Error(`Verifier type should be ${VerifierType.Pessimistic} for ${consensusContractName}`); + } + const polygonValidiumConsensusFactory = (await ethers.getContractFactory( + ConsensusContracts.PolygonValidiumEtrog, + deployer + )) as any; + const polygonValidiumConsensusContract = polygonValidiumConsensusFactory.attach( + consensusContractAddress + ) as PolygonValidiumEtrog; + try { + await polygonValidiumConsensusContract.isSequenceWithDataAvailabilityAllowed(); + if (consensusContractName === ConsensusContracts.PolygonZkEVMEtrog) { + throw new Error( + `The consensus contract at ${consensusContractAddress} does not have the public var isSequenceWithDataAvailabilityAllowed, this means is a validium and you are trying to create a rollup` + ); + } + } catch (e) { + // If it reverts means that the function is not in the contract so the deployed consensus is a PolygonZKEVMEtrog, else is Validium + if (consensusContractName === ConsensusContracts.PolygonValidiumEtrog) { + throw new Error( + `The consensus contract at ${consensusContractAddress} does not have the public var isSequenceWithDataAvailabilityAllowed, this means is a rollup and you are trying to create a validium` + ); + } + } } - // Grant role CREATE_ROLLUP_ROLE to deployer const CREATE_ROLLUP_ROLE = ethers.id("CREATE_ROLLUP_ROLE"); if ((await rollupManagerContract.hasRole(CREATE_ROLLUP_ROLE, deployer.address)) == false) @@ -181,7 +210,7 @@ async function main() { from: rollupManagerContract.target as string, nonce: nonce, }); - + console.log("Deploying rollup...."); // Create new rollup const txDeployRollup = await rollupManagerContract.createNewRollup( createRollupParameters.rollupTypeId, @@ -199,22 +228,24 @@ async function main() { const timestampReceipt = blockDeploymentRollup.timestamp; console.log("#######################\n"); - console.log(`Created new ${consensusContractName} Rollup:`, createdRollupAddress); + console.log( + `Created new ${consensusContractName} Rollup: ${createdRollupAddress} with rollupTypeId: ${createRollupParameters.rollupTypeId}` + ); // Update rollupId rollupID = await rollupManagerContract.chainIDToRollupID(chainID); // If is a validium, data committee must be set up - const polygonConsensusFactory = (await ethers.getContractFactory(consensusContractName, deployer)) as any; const dataAvailabilityProtocol = createRollupParameters.dataAvailabilityProtocol || "PolygonDataCommittee"; if (consensusContractName.includes("PolygonValidiumEtrog") && dataAvailabilityProtocol === "PolygonDataCommittee") { + console.log("Is a validium, setting up data committee..."); // deploy data committee const PolygonDataCommitteeContract = (await ethers.getContractFactory("PolygonDataCommittee", deployer)) as any; let polygonDataCommittee = await upgrades.deployProxy(PolygonDataCommitteeContract, [], { unsafeAllow: ["constructor"], }); await polygonDataCommittee?.waitForDeployment(); - + console.log(`Deployed PolygonDataCommittee at ${polygonDataCommittee?.address}`); // Load data committee const PolygonValidiumContract = (await polygonConsensusFactory.attach( createdRollupAddress @@ -224,13 +255,11 @@ async function main() { await ( await PolygonValidiumContract.setDataAvailabilityProtocol(polygonDataCommittee?.target as any) ).wait(); - - // // Setup data committee to 0 - // await (await polygonDataCommittee?.setupCommittee(0, [], "0x")).wait(); } else { + console.log("Is a validium, setting up data committee..."); await (await polygonDataCommittee?.transferOwnership(rollupAdminAddress)).wait(); + console.log(`Transferred ownership of PolygonDataCommittee to ${rollupAdminAddress}`); } - outputJson.polygonDataCommitteeAddress = polygonDataCommittee?.target; } @@ -285,10 +314,14 @@ async function main() { } let batchData = ""; - // If is vanilla client, replace genesis by sovereign contracts, else, inject initialization batch + /** + If the system is running a "vanilla client" (i.e., a basic, unmodified Ethereum client or rollup setup), the genesis block should include the deployment of the sovereign contracts, and these contracts should already be initialized with their required initial state and configurations. This means that the genesis block will contain the initial state for these contracts, allowing the system to start running without needing any additional initialization steps. However, for other rollups, additional configuration is needed. In this case, instead of having everything pre-initialized in the genesis block, we must inject an "initialization batch" into the genesis file. This batch will contain specific instructions for initializing the contracts at the time of rollup deployment. The injected initialization batch allows the system to be configured dynamically during deployment. + */ + if (isVanillaClient) { + console.log("Vanilla client detected, updating genesis..."); const pathGenesis = path.join(__dirname, "./genesis.json"); - let genesis = require(pathGenesis); + let genesis = JSON.parse(fs.readFileSync(pathGenesis, "utf8")); const initializeParams = { rollupID: rollupID, gasTokenAddress, @@ -309,14 +342,16 @@ async function main() { (sovereignParams.sovereignWETHAddress === ethers.ZeroAddress || !ethers.isAddress(sovereignParams.sovereignWETHAddress)) ) { + console.log("Rollup with custom gas token, adding WETH address to deployment output..."); const wethObject = genesis.genesis.find(function (obj: {contractName: string}) { return obj.contractName == "WETH"; }); outputJson.WETHAddress = wethObject.address; } - fs.writeFileSync(pathGenesis, JSON.stringify(genesis, null, 1)); + outputJson.genesis_sovereign = JSON.stringify(genesis, null, 1); } else { if (consensusContractName === "PolygonPessimisticConsensus") { + console.log("Pessimistic rollup detected, injecting initialization batch..."); // Add the first batch of the created rollup const newPessimisticRollup = (await polygonConsensusFactory.attach( createdRollupAddress @@ -370,6 +405,7 @@ async function main() { l1ParentHash: blockDeploymentRollup.parentHash, } as any; } else { + console.log("Setting initialization batch for the rollup..."); // Add the first batch of the created rollup const newRollupContract = (await polygonConsensusFactory.attach(createdRollupAddress)) as PolygonZkEVMEtrog; batchData = { @@ -389,8 +425,11 @@ async function main() { outputJson.genesis = rollupType.genesis; outputJson.createRollupBlockNumber = blockDeploymentRollup.number; outputJson.rollupAddress = createdRollupAddress; - outputJson.consensusContract = consensusContractName; + outputJson.consensusContractName = consensusContractName; outputJson.rollupID = Number(rollupID); + const destPath = createRollupParameters.outputPath ? createRollupParameters.outputPath : `./create_new_rollup_output_${new Date().getTime() / 1000}.json`; + fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); + console.log("Finished script, output saved at: ", argv.output); } main().catch((e) => { diff --git a/tools/createNewRollup/create_new_rollup.json.example b/tools/createNewRollup/create_new_rollup.json.example index 755defc54..3d38c09d5 100644 --- a/tools/createNewRollup/create_new_rollup.json.example +++ b/tools/createNewRollup/create_new_rollup.json.example @@ -5,11 +5,13 @@ "chainID": 1001, "rollupAdminAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "consensusContractName": "PolygonZkEVMEtrog", - "gasTokenAddress": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + "gasTokenAddress": "0x0000000000000000000000000000000000000000", "deployerPvtKey": "", "maxFeePerGas": "", "maxPriorityFeePerGas": "", "multiplierGas": "", + "timelockDelay": 0, + "timelockSalt": "", "rollupManagerAddress": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", "rollupTypeId": 1, "isVanillaClient": false, diff --git a/tools/createSovereignGenesisWithHardhat/.gitignore b/tools/createSovereignGenesisWithHardhat/.gitignore new file mode 100644 index 000000000..90d5f2d60 --- /dev/null +++ b/tools/createSovereignGenesisWithHardhat/.gitignore @@ -0,0 +1 @@ +genesis-sovereign_hardhat.json \ No newline at end of file From 4f1636b586376085b7799b68e71119a9146d5fca Mon Sep 17 00:00:00 2001 From: Ignasi Date: Fri, 29 Nov 2024 12:19:58 +0700 Subject: [PATCH 09/12] Add type param al create rollup script --- tools/addRollupType/addRollupTypeTimelock.ts | 42 ++-- tools/createNewRollup/.gitignore | 2 +- tools/createNewRollup/README.md | 12 +- tools/createNewRollup/createNewRollup.ts | 220 +++++++++++++----- .../create_new_rollup.json.example | 1 + tools/utils.js | 54 +++++ 6 files changed, 253 insertions(+), 78 deletions(-) create mode 100644 tools/utils.js diff --git a/tools/addRollupType/addRollupTypeTimelock.ts b/tools/addRollupType/addRollupTypeTimelock.ts index ced2bf2c1..073afba3c 100644 --- a/tools/addRollupType/addRollupTypeTimelock.ts +++ b/tools/addRollupType/addRollupTypeTimelock.ts @@ -21,7 +21,7 @@ async function main() { /* * Check deploy parameters - * Check that every necessary parameter is fullfilled + * Check that every necessary parameter is fulfilled */ const mandatoryDeploymentParameters = [ "description", @@ -86,11 +86,11 @@ async function main() { } else { console.log("Multiplier gas used: ", addRollupParameters.multiplierGas); async function overrideFeeData() { - const feedata = await ethers.provider.getFeeData(); + const feeData = await ethers.provider.getFeeData(); return new ethers.FeeData( null, - ((feedata.maxFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n, - ((feedata.maxPriorityFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n + ((feeData.maxFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n, + ((feeData.maxPriorityFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n ); } currentProvider.getFeeData = overrideFeeData; @@ -114,8 +114,8 @@ async function main() { console.log("Using with: ", deployer.address); // Load Rollup manager - const PolgonRollupManagerFactory = await ethers.getContractFactory("PolygonRollupManager", deployer); - const rollupManagerContract = PolgonRollupManagerFactory.attach( + const PolygonRollupManagerFactory = await ethers.getContractFactory("PolygonRollupManager", deployer); + const rollupManagerContract = PolygonRollupManagerFactory.attach( polygonRollupManagerAddress ) as PolygonRollupManager; @@ -133,7 +133,7 @@ async function main() { // get bridge address in genesis file let genesisBridgeAddress = ethers.ZeroAddress; - for (let i = 0; i < genesis.genesis.lenght; i++) { + for (let i = 0; i < genesis.genesis.length; i++) { if (genesis.genesis[i].contractName === "PolygonZkEVMBridge proxy") { genesisBridgeAddress = genesis.genesis[i].address; break; @@ -148,33 +148,33 @@ async function main() { } // Create consensus implementation if needed - const PolygonconsensusFactory = (await ethers.getContractFactory(consensusContract, deployer)) as any; - let PolygonconsensusContract; - let PolygonconsensusContractAddress; + const PolygonConsensusFactory = (await ethers.getContractFactory(consensusContract, deployer)) as any; + let PolygonConsensusContract; + let PolygonConsensusContractAddress; if ( typeof addRollupParameters.consensusContractAddress !== "undefined" && ethers.isAddress(addRollupParameters.consensusContractAddress) ) { - PolygonconsensusContractAddress = addRollupParameters.consensusContractAddress; + PolygonConsensusContractAddress = addRollupParameters.consensusContractAddress; } else { - PolygonconsensusContract = await PolygonconsensusFactory.deploy( + PolygonConsensusContract = await PolygonConsensusFactory.deploy( polygonZkEVMGlobalExitRootAddress, polTokenAddress, polygonZkEVMBridgeAddress, polygonRollupManagerAddress ); - await PolygonconsensusContract.waitForDeployment(); + await PolygonConsensusContract.waitForDeployment(); - PolygonconsensusContractAddress = PolygonconsensusContract.target; + PolygonConsensusContractAddress = PolygonConsensusContract.target; console.log("#######################\n"); console.log(`new consensus name: ${consensusContract}`); - console.log(`new PolygonconsensusContract impl: ${PolygonconsensusContractAddress}`); + console.log(`new PolygonConsensusContract impl: ${PolygonConsensusContractAddress}`); console.log("you can verify the new impl address with:"); console.log( - `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonconsensusContractAddress} --network ${process.env.HARDHAT_NETWORK}\n` + `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonConsensusContractAddress} --network ${process.env.HARDHAT_NETWORK}\n` ); console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", [ polygonZkEVMGlobalExitRootAddress, @@ -205,8 +205,8 @@ async function main() { const operation = genOperation( polygonRollupManagerAddress, 0, // value - PolgonRollupManagerFactory.interface.encodeFunctionData("addNewRollupType", [ - PolygonconsensusContractAddress, + PolygonRollupManagerFactory.interface.encodeFunctionData("addNewRollupType", [ + PolygonConsensusContractAddress, verifierAddress, forkID, rollupVerifierType, @@ -246,7 +246,7 @@ async function main() { outputJson.executeData = executeData; outputJson.id = operation.id; - // Decode the scheduleData for better readibility + // Decode the scheduleData for better readability const timelockTx = timelockContractFactory.interface.parseTransaction({data: scheduleData}); const paramsArray = timelockTx?.fragment.inputs; const objectDecoded = {}; @@ -257,7 +257,7 @@ async function main() { objectDecoded[currentParam.name] = timelockTx?.args[i]; if (currentParam.name == "data") { - const decodedRollupManagerData = PolgonRollupManagerFactory.interface.parseTransaction({ + const decodedRollupManagerData = PolygonRollupManagerFactory.interface.parseTransaction({ data: timelockTx?.args[i], }); const objectDecodedData = {}; @@ -273,7 +273,7 @@ async function main() { outputJson.decodedScheduleData = objectDecoded; - // Decode the schedule data to better readibiltiy: + // Decode the schedule data to better readability: fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); } diff --git a/tools/createNewRollup/.gitignore b/tools/createNewRollup/.gitignore index 8b0e11ef9..bbc469664 100644 --- a/tools/createNewRollup/.gitignore +++ b/tools/createNewRollup/.gitignore @@ -2,4 +2,4 @@ create_new_rollup.json genesis.json genesis_sovereign.json create_new_rollup_output.json -create_new_rollup_output*.json +create_new_rollup_output*.json \ No newline at end of file diff --git a/tools/createNewRollup/README.md b/tools/createNewRollup/README.md index 0108fa49b..f2e3f618e 100644 --- a/tools/createNewRollup/README.md +++ b/tools/createNewRollup/README.md @@ -2,7 +2,7 @@ Script to call `createNewRollup` function. -- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, a new `genesis_sovereign.json` will be created. +- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, this new sovereign genesis will be appended at the output file ## Install @@ -13,6 +13,10 @@ npm i ## Setup - Config file + - `type`: Specify the type of rollup creation, only available: + - EOA: If creating the rollup from a wallet, the script will execute the creation of the rollup on the specified network + - Multisig: If creating the rollup from a multisig, the script will output the calldata of the transaction to execute for creating the rollup + - Timelock: If creating the rollup through a timelock, the script will output the execute and schedule data to send to the timelock contract - `trustedSequencerURL`: Sequencer URL of the new created rollup - `networkName`: Network name of the new created rollup - `trustedSequencer`: Sequencer address of the new created rollup @@ -24,8 +28,8 @@ npm i - `maxFeePerGas(optional)`: string, Set `maxFeePerGas`, must define as well `maxPriorityFeePerGas` to use it - `maxPriorityFeePerGas(optional)`: string, Set `maxPriorityFeePerGas`, must define as well `maxFeePerGas` to use it - `multiplierGas(optional)`: number, Gas multiplier with 3 decimals. If `maxFeePerGas` and `maxPriorityFeePerGas` are set, this will not take effect - - `timelockDelay`: timelock delay, if is zero, no timelock is executed, direct deploy - - `timelockSalt(optional)`: timelock salt + - `timelockDelay(optional)`: timelock delay, only required on timelock type + - `timelockSalt(optional)`: timelock salt, only required on timelock type - `rollupManagerAddress`: Address of deployed rollupManager contract - `isVanillaClient`: Flag for vanilla/sovereign clients handling - `sovereignParams`: @@ -59,3 +63,5 @@ cp ./tools/createNewRollup/genesis.json.example ./tools/createNewRollup/genesis. ``` npx hardhat run ./tools/createNewRollup/createNewRollup.ts --network sepolia ``` + +Recommendation: run the tool from the interactive rollup manager cli -> https://github.com/0xPolygonHermez/rollup-manager-cli diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index bfc022a65..e07fb4ab2 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -9,7 +9,7 @@ import {ethers, upgrades} from "hardhat"; import {processorUtils, Constants} from "@0xpolygonhermez/zkevm-commonjs"; import {VerifierType, ConsensusContracts} from "../../src/pessimistic-utils"; const createRollupParameters = require("./create_new_rollup.json"); - +import {genOperation, createNewRollupTypes, convertBigIntsToNumbers} from "../utils"; import updateVanillaGenesis from "../../deployment/v2/utils/updateVanillaGenesis"; import { @@ -21,8 +21,14 @@ import { } from "../../typechain-types"; async function main() { - console.log("Starting script to create new rollup..."); + console.log(`Starting script to create new rollup from ${createRollupParameters.type}...`); const outputJson = {} as any; + const destPath = createRollupParameters.outputPath + ? createRollupParameters.outputPath + : `./outputs/create_new_rollup_output_${createRollupParameters.type}_${Math.floor( + new Date().getTime() / 1000 + )}.json`; + /* * Check deploy parameters * Check that every necessary parameter is fulfilled @@ -37,8 +43,19 @@ async function main() { "rollupManagerAddress", "rollupTypeId", "gasTokenAddress", + "type", ]; - + // check create rollup type + switch (createRollupParameters.type) { + case createNewRollupTypes.EOA: + case createNewRollupTypes.MULTISIG: + break; + case createNewRollupTypes.TIMELOCK: + mandatoryDeploymentParameters.push("timelockDelay"); + break; + default: + throw new Error(`Invalid type ${createRollupParameters.type}`); + } for (const parameterName of mandatoryDeploymentParameters) { if (createRollupParameters[parameterName] === undefined || createRollupParameters[parameterName] === "") { throw new Error(`Missing parameter: ${parameterName}`); @@ -87,6 +104,16 @@ async function main() { throw new Error(`Missing sovereign parameter: ${parameterName}`); } } + // Vanilla checks like in bridge contract + if(ethers.isAddress(createRollupParameters.gasTokenAddress) && + createRollupParameters.gasTokenAddress !== ethers.ZeroAddress && + sovereignParams.sovereignWETHAddress === ethers.ZeroAddress && sovereignParams.sovereignWETHAddressIsNotMintable === true) { + throw new Error("InvalidSovereignWETHAddressParams: if gasTokenAddress is not 0x0, and sovereignWETHAddress is 0x0, sovereignWETHAddressIsNotMintable must be false"); + } + + if(createRollupParameters.gasTokenAddress === ethers.ZeroAddress && (sovereignParams.sovereignWETHAddress !== ethers.ZeroAddress || sovereignParams.sovereignWETHAddressIsNotMintable === true)) { + throw new Error("InvalidSovereignWETHAddressParams: If gasTokenAddress is 0x0, sovereignWETHAddress must be 0x0 and sovereignWETHAddressIsNotMintable must be false"); + } } // Load provider @@ -210,28 +237,140 @@ async function main() { from: rollupManagerContract.target as string, nonce: nonce, }); - console.log("Deploying rollup...."); - // Create new rollup - const txDeployRollup = await rollupManagerContract.createNewRollup( - createRollupParameters.rollupTypeId, - chainID, - rollupAdminAddress, - trustedSequencer, - createRollupParameters.gasTokenAddress, - trustedSequencerURL, - networkName - ); + let globalExitRoot = ""; + let batchData = {}; + // Populate output json + outputJson.consensusContractName = consensusContractName; + outputJson.rollupAddress = createdRollupAddress; + outputJson.genesis = rollupType.genesis; outputJson.gasTokenAddress = createRollupParameters.gasTokenAddress; + if (createRollupParameters.type === createNewRollupTypes.TIMELOCK) { + console.log("Creating timelock txs for rollup creation..."); + const salt = createRollupParameters.timelockSalt || ethers.ZeroHash; + const predecessor = ethers.ZeroHash; + const timelockContractFactory = await ethers.getContractFactory("PolygonZkEVMTimelock", deployer); + const operation = genOperation( + createRollupParameters.rollupManagerAddress, + 0, // value + PolygonRollupManagerFactory.interface.encodeFunctionData("createNewRollup", [ + createRollupParameters.rollupTypeId, + chainID, + rollupAdminAddress, + trustedSequencer, + createRollupParameters.gasTokenAddress, + trustedSequencerURL, + networkName, + ]), + predecessor, // predecessor + salt // salt + ); + // Schedule operation + const scheduleData = timelockContractFactory.interface.encodeFunctionData("schedule", [ + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + createRollupParameters.timelockDelay, + ]); + // Execute operation + const executeData = timelockContractFactory.interface.encodeFunctionData("execute", [ + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + ]); + console.log({scheduleData}); + console.log({executeData}); + outputJson.scheduleData = scheduleData; + outputJson.executeData = executeData; + // Decode the scheduleData for better readability + const timelockTx = timelockContractFactory.interface.parseTransaction({data: scheduleData}); + const paramsArray = timelockTx?.fragment.inputs; + const objectDecoded = {}; + for (let i = 0; i < paramsArray?.length; i++) { + const currentParam = paramsArray[i]; + + objectDecoded[currentParam.name] = timelockTx?.args[i]; + + if (currentParam.name == "data") { + const decodedRollupManagerData = PolygonRollupManagerFactory.interface.parseTransaction({ + data: timelockTx?.args[i], + }); + const objectDecodedData = {}; + const paramsArrayData = decodedRollupManagerData?.fragment.inputs; + + for (let j = 0; j < paramsArrayData?.length; j++) { + const currentParam = paramsArrayData[j]; + objectDecodedData[currentParam.name] = decodedRollupManagerData?.args[j]; + } + objectDecoded["decodedData"] = objectDecodedData; + } + } - const receipt = (await txDeployRollup.wait()) as any; - const blockDeploymentRollup = await receipt?.getBlock(); - const timestampReceipt = blockDeploymentRollup.timestamp; + outputJson.decodedScheduleData = convertBigIntsToNumbers(objectDecoded); + fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); + console.log("Finished script, output saved at: ", destPath); + process.exit(0); + } else if (createRollupParameters.type === createNewRollupTypes.MULTISIG) { + console.log("Creating calldata for rollup creation from multisig..."); + const txDeployRollupCalldata = PolygonRollupManagerFactory.interface.encodeFunctionData("createNewRollup", [ + createRollupParameters.rollupTypeId, + chainID, + rollupAdminAddress, + trustedSequencer, + createRollupParameters.gasTokenAddress, + trustedSequencerURL, + networkName, + ]); + outputJson.txDeployRollupCalldata = txDeployRollupCalldata; + fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); + console.log("Finished script, output saved at: ", destPath); + process.exit(0); + } else { + console.log("Deploying rollup...."); + // Create new rollup + const txDeployRollup = await rollupManagerContract.createNewRollup( + createRollupParameters.rollupTypeId, + chainID, + rollupAdminAddress, + trustedSequencer, + createRollupParameters.gasTokenAddress, + trustedSequencerURL, + networkName + ); - console.log("#######################\n"); - console.log( - `Created new ${consensusContractName} Rollup: ${createdRollupAddress} with rollupTypeId: ${createRollupParameters.rollupTypeId}` - ); + const receipt = (await txDeployRollup.wait()) as any; + const blockDeploymentRollup = await receipt?.getBlock(); + batchData = { + timestamp: blockDeploymentRollup.timestamp, + l1BlockNumber: blockDeploymentRollup.number, + l1BlockHash: blockDeploymentRollup.hash, + l1ParentHash: blockDeploymentRollup.parentHash, + }; + outputJson.createRollupBlockNumber = blockDeploymentRollup.number; + console.log("#######################\n"); + console.log( + `Created new ${consensusContractName} Rollup: ${createdRollupAddress} with rollupTypeId: ${createRollupParameters.rollupTypeId}` + ); + + // Search added global exit root on the logs + for (const log of receipt?.logs) { + if (log.address == createdRollupAddress) { + const parsedLog = polygonConsensusFactory.interface.parseLog(log); + if (parsedLog != null && parsedLog.name == "InitialSequenceBatches") { + globalExitRoot = parsedLog.args.lastGlobalExitRoot; + } + } + } + // Assert admin address + expect(await upgrades.erc1967.getAdminAddress(createdRollupAddress)).to.be.equal(rollupManagerContract.target); + expect(await upgrades.erc1967.getImplementationAddress(createdRollupAddress)).to.be.equal( + consensusContractAddress + ); + } // Update rollupId rollupID = await rollupManagerContract.chainIDToRollupID(chainID); @@ -263,21 +402,6 @@ async function main() { outputJson.polygonDataCommitteeAddress = polygonDataCommittee?.target; } - // Assert admin address - expect(await upgrades.erc1967.getAdminAddress(createdRollupAddress)).to.be.equal(rollupManagerContract.target); - expect(await upgrades.erc1967.getImplementationAddress(createdRollupAddress)).to.be.equal(consensusContractAddress); - - // Search added global exit root on the logs - let globalExitRoot; - for (const log of receipt?.logs) { - if (log.address == createdRollupAddress) { - const parsedLog = polygonConsensusFactory.interface.parseLog(log); - if (parsedLog != null && parsedLog.name == "InitialSequenceBatches") { - globalExitRoot = parsedLog.args.lastGlobalExitRoot; - } - } - } - let gasTokenAddress, gasTokenNetwork, gasTokenMetadata; // Get bridge instance @@ -313,7 +437,6 @@ async function main() { gasTokenMetadata = "0x"; } - let batchData = ""; /** If the system is running a "vanilla client" (i.e., a basic, unmodified Ethereum client or rollup setup), the genesis block should include the deployment of the sovereign contracts, and these contracts should already be initialized with their required initial state and configurations. This means that the genesis block will contain the initial state for these contracts, allowing the system to start running without needing any additional initialization steps. However, for other rollups, additional configuration is needed. In this case, instead of having everything pre-initialized in the genesis block, we must inject an "initialization batch" into the genesis file. This batch will contain specific instructions for initializing the contracts at the time of rollup deployment. The injected initialization batch allows the system to be configured dynamically during deployment. */ @@ -348,7 +471,7 @@ async function main() { }); outputJson.WETHAddress = wethObject.address; } - outputJson.genesis_sovereign = JSON.stringify(genesis, null, 1); + outputJson.genesis_sovereign = genesis; } else { if (consensusContractName === "PolygonPessimisticConsensus") { console.log("Pessimistic rollup detected, injecting initialization batch..."); @@ -395,20 +518,16 @@ async function main() { const txObject = ethers.Transaction.from(injectedTx); const customData = processorUtils.rawTxToCustomRawTx(txObject.serialized); - batchData = { + batchData = Object.assign(batchData, { batchL2Data: customData, globalExitRoot: lastGER, - timestamp: blockDeploymentRollup.timestamp, sequencer: trustedSequencer, - l1BlockNumber: blockDeploymentRollup.number, - l1BlockHash: blockDeploymentRollup.hash, - l1ParentHash: blockDeploymentRollup.parentHash, - } as any; + }); } else { console.log("Setting initialization batch for the rollup..."); // Add the first batch of the created rollup const newRollupContract = (await polygonConsensusFactory.attach(createdRollupAddress)) as PolygonZkEVMEtrog; - batchData = { + batchData = Object.assign(batchData, { batchL2Data: await newRollupContract.generateInitializeTransaction( Number(rollupID), gasTokenAddress, @@ -416,20 +535,15 @@ async function main() { gasTokenMetadata as any ), globalExitRoot: globalExitRoot, - timestamp: timestampReceipt, sequencer: trustedSequencer, - } as any; + }); } } outputJson.firstBatchData = batchData; - outputJson.genesis = rollupType.genesis; - outputJson.createRollupBlockNumber = blockDeploymentRollup.number; - outputJson.rollupAddress = createdRollupAddress; - outputJson.consensusContractName = consensusContractName; outputJson.rollupID = Number(rollupID); - const destPath = createRollupParameters.outputPath ? createRollupParameters.outputPath : `./create_new_rollup_output_${new Date().getTime() / 1000}.json`; + fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); - console.log("Finished script, output saved at: ", argv.output); + console.log("Finished script, output saved at: ", destPath); } main().catch((e) => { diff --git a/tools/createNewRollup/create_new_rollup.json.example b/tools/createNewRollup/create_new_rollup.json.example index 3d38c09d5..bd666a349 100644 --- a/tools/createNewRollup/create_new_rollup.json.example +++ b/tools/createNewRollup/create_new_rollup.json.example @@ -1,4 +1,5 @@ { + "type":"EOA", "trustedSequencerURL": "http://zkevm-json-rpc:8123", "networkName": "zkevm", "trustedSequencer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", diff --git a/tools/utils.js b/tools/utils.js new file mode 100644 index 000000000..6d03168f2 --- /dev/null +++ b/tools/utils.js @@ -0,0 +1,54 @@ +/* eslint-disable no-prototype-builtins */ +/* eslint-disable no-restricted-syntax */ +const ethers = require('ethers'); + +function genOperation(target, value, data, predecessor, salt) { + const abiEncoded = ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], + [target, value, data, predecessor, salt], + ); + const id = ethers.keccak256(abiEncoded); + return { + id, + target, + value, + data, + predecessor, + salt, + }; +} + +const createNewRollupTypes = { + EOA: 'EOA', + MULTISIG: 'Multisig', + TIMELOCK: 'Timelock', +}; + +// Function to recursively convert BigInts to Numbers +function convertBigIntsToNumbers(obj) { + if (typeof obj === 'bigint') { + return Number(obj); // Convert BigInt to Number + } + + if (Array.isArray(obj)) { + return obj.map(convertBigIntsToNumbers); // Recursively process each element in the array + } + + if (typeof obj === 'object' && obj !== null) { + const newObj = {}; + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + newObj[key] = convertBigIntsToNumbers(obj[key]); // Recursively process each property + } + } + return newObj; + } + + return obj; // Return the value if it's not a BigInt, object, or array +} + +module.exports = { + genOperation, + createNewRollupTypes, + convertBigIntsToNumbers +}; From 664b0a13aa73389edd97071f7fe3dc7f6c266d23 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Mon, 2 Dec 2024 15:57:32 +0700 Subject: [PATCH 10/12] More review remediations --- .../PolygonPessimisticConsensus.sol | 2 +- tools/addRollupType/addRollupType.ts | 53 +++++++++++++------ tools/addRollupType/addRollupTypeTimelock.ts | 41 +++++++------- tools/createNewRollup/createNewRollup.ts | 32 +++++++---- tools/utils.js | 4 +- 5 files changed, 82 insertions(+), 50 deletions(-) diff --git a/contracts/v2/consensus/pessimistic/PolygonPessimisticConsensus.sol b/contracts/v2/consensus/pessimistic/PolygonPessimisticConsensus.sol index f847d3c05..cc2d59525 100644 --- a/contracts/v2/consensus/pessimistic/PolygonPessimisticConsensus.sol +++ b/contracts/v2/consensus/pessimistic/PolygonPessimisticConsensus.sol @@ -14,7 +14,7 @@ contract PolygonPessimisticConsensus is * @param _globalExitRootManager Global exit root manager address * @param _pol POL token address * @param _bridgeAddress Bridge address - * @param _rollupManager Global exit root manager address + * @param _rollupManager Rollup manager address */ constructor( IPolygonZkEVMGlobalExitRootV2 _globalExitRootManager, diff --git a/tools/addRollupType/addRollupType.ts b/tools/addRollupType/addRollupType.ts index 25584a6e0..a4d803c03 100644 --- a/tools/addRollupType/addRollupType.ts +++ b/tools/addRollupType/addRollupType.ts @@ -6,16 +6,19 @@ import fs = require("fs"); import * as dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname, "../../.env")}); -import {ethers, upgrades} from "hardhat"; +import {ethers, run} from "hardhat"; const addRollupTypeParameters = require("./add_rollup_type.json"); const genesis = require("./genesis.json"); const dateStr = new Date().toISOString(); -const pathOutputJson = path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`); +const pathOutputJson = addRollupTypeParameters.outputPath + ? path.join(__dirname, addRollupTypeParameters.outputPath) + : path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`);; import {PolygonRollupManager} from "../../typechain-types"; import "../../deployment/helpers/utils"; +import {supportedBridgeContracts} from "../utils"; async function main() { const outputJson = {} as any; @@ -82,7 +85,8 @@ async function main() { return new ethers.FeeData( null, ((feedata.maxFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n, - ((feedata.maxPriorityFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n + ((feedata.maxPriorityFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / + 1000n ); } currentProvider.getFeeData = overrideFeeData; @@ -125,16 +129,18 @@ async function main() { // get bridge address in genesis file let genesisBridgeAddress = ethers.ZeroAddress; + let bridgeContractName = ""; for (let i = 0; i < genesis.genesis.length; i++) { - if (genesis.genesis[i].contractName === "PolygonZkEVMBridgeV2 proxy") { + if (supportedBridgeContracts.includes(genesis.genesis[i].contractName)) { genesisBridgeAddress = genesis.genesis[i].address; + bridgeContractName = genesis.genesis[i].contractName; break; } } if (polygonZkEVMBridgeAddress.toLowerCase() !== genesisBridgeAddress.toLowerCase()) { throw new Error( - `'PolygonZkEVMBridgeV2 proxy' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` + `'${bridgeContractName}' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` ); } } @@ -173,22 +179,35 @@ async function main() { polygonRollupManagerAddress ); await PolygonConsensusContract.waitForDeployment(); - console.log("#######################\n"); console.log(`new consensus name: ${consensusContract}`); console.log(`new PolygonConsensusContract impl: ${PolygonConsensusContract.target}`); - console.log("you can verify the new impl address with:"); - console.log( - `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonConsensusContract.target} --network ${process.env.HARDHAT_NETWORK}\n` - ); - console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", [ - polygonZkEVMGlobalExitRootAddress, - polTokenAddress, - polygonZkEVMBridgeAddress, - polygonRollupManagerAddress, - ]); - + try { + console.log("Verifying contract..."); + await run("verify:verify", { + address: PolygonConsensusContract.target, + constructorArguments: [ + polygonZkEVMGlobalExitRootAddress, + polTokenAddress, + polygonZkEVMBridgeAddress, + polygonRollupManagerAddress, + ], + }); + } catch (e) { + console.log(e) + console.log("Automatic verification failed. Please verify the contract manually."); + console.log("you can verify the new impl address with:"); + console.log( + `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonConsensusContract.target} --network ${process.env.HARDHAT_NETWORK}\n` + ); + console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", [ + polygonZkEVMGlobalExitRootAddress, + polTokenAddress, + polygonZkEVMBridgeAddress, + polygonRollupManagerAddress, + ]); + } consensusContractAddress = PolygonConsensusContract.target; } diff --git a/tools/addRollupType/addRollupTypeTimelock.ts b/tools/addRollupType/addRollupTypeTimelock.ts index 073afba3c..bfc9a27da 100644 --- a/tools/addRollupType/addRollupTypeTimelock.ts +++ b/tools/addRollupType/addRollupTypeTimelock.ts @@ -8,12 +8,13 @@ import * as dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname, "../../.env")}); import {ethers, upgrades} from "hardhat"; -const addRollupParameters = require("./add_rollup_type.json"); +const addRollupTypeParameters = require("./add_rollup_type.json"); const genesis = require("./genesis.json"); const dateStr = new Date().toISOString(); -const pathOutputJson = path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`); -import {PolygonRollupManager} from "../../typechain-types"; +const pathOutputJson = addRollupTypeParameters.outputPath + ? path.join(__dirname, addRollupTypeParameters.outputPath) + : path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`); import "../../deployment/helpers/utils"; async function main() { @@ -34,7 +35,7 @@ async function main() { ]; for (const parameterName of mandatoryDeploymentParameters) { - if (addRollupParameters[parameterName] === undefined || addRollupParameters[parameterName] === "") { + if (addRollupTypeParameters[parameterName] === undefined || addRollupTypeParameters[parameterName] === "") { throw new Error(`Missing parameter: ${parameterName}`); } } @@ -48,10 +49,10 @@ async function main() { timelockDelay, genesisRoot, programVKey, - } = addRollupParameters; + } = addRollupTypeParameters; - const salt = addRollupParameters.timelockSalt || ethers.ZeroHash; - const predecessor = addRollupParameters.predecessor || ethers.ZeroHash; + const salt = addRollupTypeParameters.timelockSalt || ethers.ZeroHash; + const predecessor = addRollupTypeParameters.predecessor || ethers.ZeroHash; const supportedConsensus = [ "PolygonZkEVMEtrog", @@ -67,30 +68,30 @@ async function main() { // Load provider let currentProvider = ethers.provider; - if (addRollupParameters.multiplierGas || addRollupParameters.maxFeePerGas) { + if (addRollupTypeParameters.multiplierGas || addRollupTypeParameters.maxFeePerGas) { if (process.env.HARDHAT_NETWORK !== "hardhat") { currentProvider = ethers.getDefaultProvider( `https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}` ) as any; - if (addRollupParameters.maxPriorityFeePerGas && addRollupParameters.maxFeePerGas) { + if (addRollupTypeParameters.maxPriorityFeePerGas && addRollupTypeParameters.maxFeePerGas) { console.log( - `Hardcoded gas used: MaxPriority${addRollupParameters.maxPriorityFeePerGas} gwei, MaxFee${addRollupParameters.maxFeePerGas} gwei` + `Hardcoded gas used: MaxPriority${addRollupTypeParameters.maxPriorityFeePerGas} gwei, MaxFee${addRollupTypeParameters.maxFeePerGas} gwei` ); const FEE_DATA = new ethers.FeeData( null, - ethers.parseUnits(addRollupParameters.maxFeePerGas, "gwei"), - ethers.parseUnits(addRollupParameters.maxPriorityFeePerGas, "gwei") + ethers.parseUnits(addRollupTypeParameters.maxFeePerGas, "gwei"), + ethers.parseUnits(addRollupTypeParameters.maxPriorityFeePerGas, "gwei") ); currentProvider.getFeeData = async () => FEE_DATA; } else { - console.log("Multiplier gas used: ", addRollupParameters.multiplierGas); + console.log("Multiplier gas used: ", addRollupTypeParameters.multiplierGas); async function overrideFeeData() { const feeData = await ethers.provider.getFeeData(); return new ethers.FeeData( null, - ((feeData.maxFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n, - ((feeData.maxPriorityFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n + ((feeData.maxFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n, + ((feeData.maxPriorityFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n ); } currentProvider.getFeeData = overrideFeeData; @@ -100,8 +101,8 @@ async function main() { // Load deployer let deployer; - if (addRollupParameters.deployerPvtKey) { - deployer = new ethers.Wallet(addRollupParameters.deployerPvtKey, currentProvider); + if (addRollupTypeParameters.deployerPvtKey) { + deployer = new ethers.Wallet(addRollupTypeParameters.deployerPvtKey, currentProvider); } else if (process.env.MNEMONIC) { deployer = ethers.HDNodeWallet.fromMnemonic( ethers.Mnemonic.fromPhrase(process.env.MNEMONIC), @@ -153,10 +154,10 @@ async function main() { let PolygonConsensusContractAddress; if ( - typeof addRollupParameters.consensusContractAddress !== "undefined" && - ethers.isAddress(addRollupParameters.consensusContractAddress) + typeof addRollupTypeParameters.consensusContractAddress !== "undefined" && + ethers.isAddress(addRollupTypeParameters.consensusContractAddress) ) { - PolygonConsensusContractAddress = addRollupParameters.consensusContractAddress; + PolygonConsensusContractAddress = addRollupTypeParameters.consensusContractAddress; } else { PolygonConsensusContract = await PolygonConsensusFactory.deploy( polygonZkEVMGlobalExitRootAddress, diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index e07fb4ab2..82d73e45c 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -23,11 +23,10 @@ import { async function main() { console.log(`Starting script to create new rollup from ${createRollupParameters.type}...`); const outputJson = {} as any; + const dateStr = new Date().toISOString(); const destPath = createRollupParameters.outputPath - ? createRollupParameters.outputPath - : `./outputs/create_new_rollup_output_${createRollupParameters.type}_${Math.floor( - new Date().getTime() / 1000 - )}.json`; + ? path.join(__dirname, createRollupParameters.outputPath) + : `./outputs/create_new_rollup_output_${createRollupParameters.type}_${dateStr}.json`; /* * Check deploy parameters @@ -105,14 +104,25 @@ async function main() { } } // Vanilla checks like in bridge contract - if(ethers.isAddress(createRollupParameters.gasTokenAddress) && - createRollupParameters.gasTokenAddress !== ethers.ZeroAddress && - sovereignParams.sovereignWETHAddress === ethers.ZeroAddress && sovereignParams.sovereignWETHAddressIsNotMintable === true) { - throw new Error("InvalidSovereignWETHAddressParams: if gasTokenAddress is not 0x0, and sovereignWETHAddress is 0x0, sovereignWETHAddressIsNotMintable must be false"); + if ( + ethers.isAddress(createRollupParameters.gasTokenAddress) && + createRollupParameters.gasTokenAddress !== ethers.ZeroAddress && + sovereignParams.sovereignWETHAddress === ethers.ZeroAddress && + sovereignParams.sovereignWETHAddressIsNotMintable === true + ) { + throw new Error( + "InvalidSovereignWETHAddressParams: if gasTokenAddress is not 0x0, and sovereignWETHAddress is 0x0, sovereignWETHAddressIsNotMintable must be false" + ); } - if(createRollupParameters.gasTokenAddress === ethers.ZeroAddress && (sovereignParams.sovereignWETHAddress !== ethers.ZeroAddress || sovereignParams.sovereignWETHAddressIsNotMintable === true)) { - throw new Error("InvalidSovereignWETHAddressParams: If gasTokenAddress is 0x0, sovereignWETHAddress must be 0x0 and sovereignWETHAddressIsNotMintable must be false"); + if ( + createRollupParameters.gasTokenAddress === ethers.ZeroAddress && + (sovereignParams.sovereignWETHAddress !== ethers.ZeroAddress || + sovereignParams.sovereignWETHAddressIsNotMintable === true) + ) { + throw new Error( + "InvalidSovereignWETHAddressParams: If gasTokenAddress is 0x0, sovereignWETHAddress must be 0x0 and sovereignWETHAddressIsNotMintable must be false" + ); } } @@ -542,7 +552,7 @@ async function main() { outputJson.firstBatchData = batchData; outputJson.rollupID = Number(rollupID); - fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); + fs.writeFileSync(destPath, JSON.stringify(outputJson, null, 1)); console.log("Finished script, output saved at: ", destPath); } diff --git a/tools/utils.js b/tools/utils.js index 6d03168f2..69766503b 100644 --- a/tools/utils.js +++ b/tools/utils.js @@ -2,6 +2,7 @@ /* eslint-disable no-restricted-syntax */ const ethers = require('ethers'); +const supportedBridgeContracts = ['PolygonZkEVMBridgeV2 proxy', 'PolygonZkEVMBridge proxy', 'BridgeL2SovereignChain proxy']; function genOperation(target, value, data, predecessor, salt) { const abiEncoded = ethers.AbiCoder.defaultAbiCoder().encode( ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], @@ -50,5 +51,6 @@ function convertBigIntsToNumbers(obj) { module.exports = { genOperation, createNewRollupTypes, - convertBigIntsToNumbers + convertBigIntsToNumbers, + supportedBridgeContracts, }; From bcc4f014986d8ea425bf43980d2045eba0cef538 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Tue, 3 Dec 2024 00:12:11 +0700 Subject: [PATCH 11/12] Small fixes --- .../BridgeL2SovereignChain.sol | 6 +- tools/createNewRollup/README.md | 56 ++++++++++++------- tools/createNewRollup/createNewRollup.ts | 7 ++- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol b/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol index a83152bd8..ea85d2c2f 100644 --- a/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol +++ b/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol @@ -463,7 +463,7 @@ contract BridgeL2SovereignChain is /** * @notice Function to check if an index is claimed or not - * @dev function override to improve a bit the performance and bytecode not checking unnecessary conditions for sovereign chains context + * @dev function overridden to improve a bit the performance and bytecode not checking unnecessary conditions for sovereign chains context * @param leafIndex Index * @param sourceBridgeNetwork Origin network */ @@ -482,7 +482,7 @@ contract BridgeL2SovereignChain is /** * @notice Function to check that an index is not claimed and set it as claimed - * @dev function override to improve a bit the performance and bytecode not checking unnecessary conditions for sovereign chains context + * @dev function overridden to improve a bit the performance and bytecode not checking unnecessary conditions for sovereign chains context * @param leafIndex Index * @param sourceBridgeNetwork Origin network */ @@ -503,7 +503,7 @@ contract BridgeL2SovereignChain is /** * @notice Function to call token permit method of extended ERC20 - * @dev We override this function from PolygonZkEVMBridgeV2 to improve a bit the performance and bytecode not checking unnecessary conditions for sovereign chains context + * @dev function overridden from PolygonZkEVMBridgeV2 to improve a bit the performance and bytecode not checking unnecessary conditions for sovereign chains context + @param token ERC20 token address * @param amount Quantity that is expected to be allowed * @param permitData Raw data of the call `permit` of the token diff --git a/tools/createNewRollup/README.md b/tools/createNewRollup/README.md index f2e3f618e..353a282ae 100644 --- a/tools/createNewRollup/README.md +++ b/tools/createNewRollup/README.md @@ -4,15 +4,37 @@ Script to call `createNewRollup` function. - This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, this new sovereign genesis will be appended at the output file -## Install +## Setup + +- install packages ``` npm i ``` -## Setup +- Set env variables +```` +cp .env.example .env +```` + + +Fill `.env` with your `INFURA_PROJECT_ID` and `ETHERSCAN_API_KEY` + +- Copy configuration files: + +``` +cp ./tools/createNewRollup/create_new_rollup.json.example ./tools/createNewRollup/create_new_rollup.json +``` + +- Copy genesis file (only for sovereign chains) + +``` +cp ./tools/createNewRollup/genesis.json.example ./tools/createNewRollup/genesis.json +``` + +- Set your parameters -> create_new_rollup.json + -- Config file - `type`: Specify the type of rollup creation, only available: - EOA: If creating the rollup from a wallet, the script will execute the creation of the rollup on the specified network - Multisig: If creating the rollup from a multisig, the script will output the calldata of the transaction to execute for creating the rollup @@ -31,6 +53,7 @@ npm i - `timelockDelay(optional)`: timelock delay, only required on timelock type - `timelockSalt(optional)`: timelock salt, only required on timelock type - `rollupManagerAddress`: Address of deployed rollupManager contract + - `rollupTypeId`: The id of the rollup type of the rollup to deploy. WARNING: the type must match with the `consensusContractName`. Example: if the type is validium, the contract name has to be `PolygonValidiumEtrog` - `isVanillaClient`: Flag for vanilla/sovereign clients handling - `sovereignParams`: - `bridgeManager`: bridge manager address @@ -39,29 +62,22 @@ npm i - `globalExitRootUpdater`: Address of globalExitRootUpdater for sovereign chains - `globalExitRootRemover`: Address of globalExitRootRemover for sovereign chains -## Usage - -> All commands are done from root repository. +- Set your parameters -> genesis.json + - Is the genesis used to create the rollupType + - It is only necessary in case you want to create a sovereign/vanilla chain because it will be updated -### Call 'createNewRollup' from an EOA - -- Copy configuration files: +- Run tool: ``` -cp ./tools/createNewRollup/create_new_rollup.json.example ./tools/createNewRollup/create_new_rollup.json +npx hardhat run ./tools/createNewRollup/createNewRollup.ts --network sepolia ``` -- Copy genesis file (only for sovereign chains) +### More Info +- All commands are done from root repository. +- The output files will be saved at `./tools/createNewRollup/create_new_rollup_output_{type}_{date}.json` +- In case is a sovereign chain, the updated genesis is saved inside the output file, the original `genesis.json` is not modified +- If the script fails, check the logs, most of the errors are handled and are auto explanatory -``` -cp ./tools/createNewRollup/genesis.json.example ./tools/createNewRollup/genesis.json -``` - -- Set your parameters -- Run tool: -``` -npx hardhat run ./tools/createNewRollup/createNewRollup.ts --network sepolia -``` Recommendation: run the tool from the interactive rollup manager cli -> https://github.com/0xPolygonHermez/rollup-manager-cli diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index 82d73e45c..3f5647027 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -26,7 +26,7 @@ async function main() { const dateStr = new Date().toISOString(); const destPath = createRollupParameters.outputPath ? path.join(__dirname, createRollupParameters.outputPath) - : `./outputs/create_new_rollup_output_${createRollupParameters.type}_${dateStr}.json`; + : path.join(__dirname, `create_new_rollup_output_${createRollupParameters.type}_${dateStr}.json`); /* * Check deploy parameters @@ -254,6 +254,7 @@ async function main() { outputJson.rollupAddress = createdRollupAddress; outputJson.genesis = rollupType.genesis; outputJson.gasTokenAddress = createRollupParameters.gasTokenAddress; + outputJson.rollupManagerAddress = createRollupParameters.rollupManagerAddress; if (createRollupParameters.type === createNewRollupTypes.TIMELOCK) { console.log("Creating timelock txs for rollup creation..."); const salt = createRollupParameters.timelockSalt || ethers.ZeroHash; @@ -320,7 +321,7 @@ async function main() { } outputJson.decodedScheduleData = convertBigIntsToNumbers(objectDecoded); - fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); + fs.writeFileSync(destPath, JSON.stringify(outputJson, null, 1)); console.log("Finished script, output saved at: ", destPath); process.exit(0); } else if (createRollupParameters.type === createNewRollupTypes.MULTISIG) { @@ -335,7 +336,7 @@ async function main() { networkName, ]); outputJson.txDeployRollupCalldata = txDeployRollupCalldata; - fs.writeFileSync(path.join(__dirname, destPath), JSON.stringify(outputJson, null, 1)); + fs.writeFileSync(destPath, JSON.stringify(outputJson, null, 1)); console.log("Finished script, output saved at: ", destPath); process.exit(0); } else { From 429aa37f709cfedf63592fbd86391317b4217997 Mon Sep 17 00:00:00 2001 From: krlosMata Date: Tue, 10 Dec 2024 18:29:57 +0100 Subject: [PATCH 12/12] minor fixes --- package-lock.json | 47 ++----------------- tools/addRollupType/addRollupType.ts | 5 +- tools/addRollupType/addRollupTypeTimelock.ts | 46 ++++++++++++------ tools/createNewRollup/README.md | 36 +++++--------- tools/createNewRollup/createNewRollup.ts | 32 +++++++++---- .../create_new_rollup.json.example | 6 +-- tools/utils.js | 3 ++ 7 files changed, 79 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8a022a994..7da7594bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2495,7 +2495,6 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true }, "node_modules/@oclif/core": { @@ -2717,7 +2716,6 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true }, "node_modules/@oclif/errors": { @@ -2938,7 +2936,6 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true }, "node_modules/@oclif/help/node_modules/wrap-ansi": { @@ -3079,9 +3076,9 @@ }, "node_modules/@openzeppelin/contracts5": { "name": "@openzeppelin/contracts", - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.2.tgz", - "integrity": "sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.0.tgz", + "integrity": "sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw==", "dev": true }, "node_modules/@openzeppelin/defender-admin-client": { @@ -3164,7 +3161,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.15.0.tgz", "integrity": "sha512-nuf/xegMIuKCO0hMrxI1KQKTzQw1iCl/9kew2nJM9MrFIohhfEXItc5rbJRoV/jehmK/Jhi9ATF9OHH09StEsQ==", - "dev": true, "dependencies": { "amazon-cognito-identity-js": "^6.3.6", @@ -6244,7 +6240,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -6410,17 +6405,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -16800,28 +16784,6 @@ "node": "*" } }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -17435,7 +17397,8 @@ "version": "0.2.7", "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/hmac-drbg": { "version": "1.0.1", diff --git a/tools/addRollupType/addRollupType.ts b/tools/addRollupType/addRollupType.ts index a4d803c03..d39e120e1 100644 --- a/tools/addRollupType/addRollupType.ts +++ b/tools/addRollupType/addRollupType.ts @@ -13,8 +13,8 @@ const genesis = require("./genesis.json"); const dateStr = new Date().toISOString(); const pathOutputJson = addRollupTypeParameters.outputPath - ? path.join(__dirname, addRollupTypeParameters.outputPath) - : path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`);; + ? path.join(__dirname, addRollupTypeParameters.outputPath) + : path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`); import {PolygonRollupManager} from "../../typechain-types"; import "../../deployment/helpers/utils"; @@ -195,7 +195,6 @@ async function main() { ], }); } catch (e) { - console.log(e) console.log("Automatic verification failed. Please verify the contract manually."); console.log("you can verify the new impl address with:"); console.log( diff --git a/tools/addRollupType/addRollupTypeTimelock.ts b/tools/addRollupType/addRollupTypeTimelock.ts index bfc9a27da..3403b84fe 100644 --- a/tools/addRollupType/addRollupTypeTimelock.ts +++ b/tools/addRollupType/addRollupTypeTimelock.ts @@ -6,7 +6,7 @@ import fs = require("fs"); import * as dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname, "../../.env")}); -import {ethers, upgrades} from "hardhat"; +import {ethers, run} from "hardhat"; const addRollupTypeParameters = require("./add_rollup_type.json"); const genesis = require("./genesis.json"); @@ -16,6 +16,7 @@ const pathOutputJson = addRollupTypeParameters.outputPath ? path.join(__dirname, addRollupTypeParameters.outputPath) : path.join(__dirname, `./add_rollup_type_output-${dateStr}.json`); import "../../deployment/helpers/utils"; +import {supportedBridgeContracts} from "../utils"; async function main() { const outputJson = {} as any; @@ -91,7 +92,8 @@ async function main() { return new ethers.FeeData( null, ((feeData.maxFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n, - ((feeData.maxPriorityFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / 1000n + ((feeData.maxPriorityFeePerGas as bigint) * BigInt(addRollupTypeParameters.multiplierGas)) / + 1000n ); } currentProvider.getFeeData = overrideFeeData; @@ -134,16 +136,18 @@ async function main() { // get bridge address in genesis file let genesisBridgeAddress = ethers.ZeroAddress; + let bridgeContractName = ""; for (let i = 0; i < genesis.genesis.length; i++) { - if (genesis.genesis[i].contractName === "PolygonZkEVMBridge proxy") { + if (supportedBridgeContracts.includes(genesis.genesis[i].contractName)) { genesisBridgeAddress = genesis.genesis[i].address; + bridgeContractName = genesis.genesis[i].contractName; break; } } if (polygonZkEVMBridgeAddress.toLowerCase() !== genesisBridgeAddress.toLowerCase()) { throw new Error( - `'PolygonZkEVMBridge proxy' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` + `'${bridgeContractName}' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` ); } } @@ -173,16 +177,30 @@ async function main() { console.log(`new consensus name: ${consensusContract}`); console.log(`new PolygonConsensusContract impl: ${PolygonConsensusContractAddress}`); - console.log("you can verify the new impl address with:"); - console.log( - `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonConsensusContractAddress} --network ${process.env.HARDHAT_NETWORK}\n` - ); - console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", [ - polygonZkEVMGlobalExitRootAddress, - polTokenAddress, - polygonZkEVMBridgeAddress, - polygonRollupManagerAddress, - ]); + try { + console.log("Verifying contract..."); + await run("verify:verify", { + address: PolygonConsensusContract.target, + constructorArguments: [ + polygonZkEVMGlobalExitRootAddress, + polTokenAddress, + polygonZkEVMBridgeAddress, + polygonRollupManagerAddress, + ], + }); + } catch (e) { + console.log("Automatic verification failed. Please verify the contract manually."); + console.log("you can verify the new impl address with:"); + console.log( + `npx hardhat verify --constructor-args upgrade/arguments.js ${PolygonConsensusContract.target} --network ${process.env.HARDHAT_NETWORK}\n` + ); + console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", [ + polygonZkEVMGlobalExitRootAddress, + polTokenAddress, + polygonZkEVMBridgeAddress, + polygonRollupManagerAddress, + ]); + } } // load timelock diff --git a/tools/createNewRollup/README.md b/tools/createNewRollup/README.md index 353a282ae..c81a31ce9 100644 --- a/tools/createNewRollup/README.md +++ b/tools/createNewRollup/README.md @@ -1,13 +1,9 @@ # Create new Rollup - Script to call `createNewRollup` function. - -- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, this new sovereign genesis will be appended at the output file +- This script needs of a genesis as input only if we are trying to deploy a sovereign chain. The genesis will only be updated in case of trying to deploy a sovereign chain. In this case, this new sovereign genesis will be appended at the output file ## Setup - - install packages - ``` npm i ``` @@ -17,28 +13,23 @@ npm i cp .env.example .env ```` - Fill `.env` with your `INFURA_PROJECT_ID` and `ETHERSCAN_API_KEY` - Copy configuration files: - ``` cp ./tools/createNewRollup/create_new_rollup.json.example ./tools/createNewRollup/create_new_rollup.json ``` - Copy genesis file (only for sovereign chains) - ``` cp ./tools/createNewRollup/genesis.json.example ./tools/createNewRollup/genesis.json ``` -- Set your parameters -> create_new_rollup.json - - +- Set your parameters -> create_new_rollup.json - `type`: Specify the type of rollup creation, only available: - - EOA: If creating the rollup from a wallet, the script will execute the creation of the rollup on the specified network - - Multisig: If creating the rollup from a multisig, the script will output the calldata of the transaction to execute for creating the rollup - - Timelock: If creating the rollup through a timelock, the script will output the execute and schedule data to send to the timelock contract + - `EOA`: If creating the rollup from a wallet, the script will execute the creation of the rollup on the specified network + - `Multisig`: If creating the rollup from a multisig, the script will output the calldata of the transaction to execute for creating the rollup + - `Timelock`: If creating the rollup through a timelock, the script will output the execute and schedule data to send to the timelock contract - `trustedSequencerURL`: Sequencer URL of the new created rollup - `networkName`: Network name of the new created rollup - `trustedSequencer`: Sequencer address of the new created rollup @@ -62,22 +53,17 @@ cp ./tools/createNewRollup/genesis.json.example ./tools/createNewRollup/genesis. - `globalExitRootUpdater`: Address of globalExitRootUpdater for sovereign chains - `globalExitRootRemover`: Address of globalExitRootRemover for sovereign chains -- Set your parameters -> genesis.json - - Is the genesis used to create the rollupType - - It is only necessary in case you want to create a sovereign/vanilla chain because it will be updated - -- Run tool: +- Set your parameters -> genesis.json + - Is the genesis used to create the rollupType + - It is only necessary in case you want to create a sovereign/vanilla chain because it will be updated +- Run tool: ``` npx hardhat run ./tools/createNewRollup/createNewRollup.ts --network sepolia ``` ### More Info -- All commands are done from root repository. +- All commands are done from root repository - The output files will be saved at `./tools/createNewRollup/create_new_rollup_output_{type}_{date}.json` - In case is a sovereign chain, the updated genesis is saved inside the output file, the original `genesis.json` is not modified -- If the script fails, check the logs, most of the errors are handled and are auto explanatory - - - -Recommendation: run the tool from the interactive rollup manager cli -> https://github.com/0xPolygonHermez/rollup-manager-cli +- If the script fails, check the logs, most of the errors are handled and are auto explanatory \ No newline at end of file diff --git a/tools/createNewRollup/createNewRollup.ts b/tools/createNewRollup/createNewRollup.ts index 3f5647027..89a126344 100644 --- a/tools/createNewRollup/createNewRollup.ts +++ b/tools/createNewRollup/createNewRollup.ts @@ -207,11 +207,15 @@ async function main() { consensusContractName === ConsensusContracts.PolygonPessimisticConsensus && verifierType !== VerifierType.Pessimistic ) { - throw new Error(`Verifier type should be ${VerifierType.StateTransition} for ${consensusContractName}`); + throw new Error( + `Mismatch RollupTypeID: Verifier type should be ${VerifierType.StateTransition} for ${consensusContractName}` + ); } if (consensusContractName !== ConsensusContracts.PolygonPessimisticConsensus) { if (verifierType !== VerifierType.StateTransition) { - throw new Error(`Verifier type should be ${VerifierType.Pessimistic} for ${consensusContractName}`); + throw new Error( + `Mismatch RollupTypeID: Verifier type should be ${VerifierType.Pessimistic} for ${consensusContractName}` + ); } const polygonValidiumConsensusFactory = (await ethers.getContractFactory( ConsensusContracts.PolygonValidiumEtrog, @@ -220,22 +224,32 @@ async function main() { const polygonValidiumConsensusContract = polygonValidiumConsensusFactory.attach( consensusContractAddress ) as PolygonValidiumEtrog; + + let hasMethodImplemented; + try { - await polygonValidiumConsensusContract.isSequenceWithDataAvailabilityAllowed(); - if (consensusContractName === ConsensusContracts.PolygonZkEVMEtrog) { + hasMethodImplemented = await polygonValidiumConsensusContract.isSequenceWithDataAvailabilityAllowed(); + } catch (error) { + console.log("RollupTypeID selected "); + } + + // Consensus PolygonZkEVMEtrog: if 'hasMethodImplemented' does not have any value + if (typeof hasMethodImplemented === "undefined") { + if (consensusContractName === ConsensusContracts.PolygonValidiumEtrog) { throw new Error( - `The consensus contract at ${consensusContractAddress} does not have the public var isSequenceWithDataAvailabilityAllowed, this means is a validium and you are trying to create a rollup` + `The consensus contract at ${consensusContractAddress} does not have the public method "isSequenceWithDataAvailabilityAllowed", this means is a rollup and you are trying to create a validium` ); } - } catch (e) { - // If it reverts means that the function is not in the contract so the deployed consensus is a PolygonZKEVMEtrog, else is Validium - if (consensusContractName === ConsensusContracts.PolygonValidiumEtrog) { + } else { + // Consensus PolygonValidiumEtrog: if 'hasMethodImplemented' does not have any value + if (consensusContractName === ConsensusContracts.PolygonZkEVMEtrog) { throw new Error( - `The consensus contract at ${consensusContractAddress} does not have the public var isSequenceWithDataAvailabilityAllowed, this means is a rollup and you are trying to create a validium` + `The consensus contract at ${consensusContractAddress} does have the public var "isSequenceWithDataAvailabilityAllowed", this means is a validium and you are trying to create a rollup` ); } } } + // Grant role CREATE_ROLLUP_ROLE to deployer const CREATE_ROLLUP_ROLE = ethers.id("CREATE_ROLLUP_ROLE"); if ((await rollupManagerContract.hasRole(CREATE_ROLLUP_ROLE, deployer.address)) == false) diff --git a/tools/createNewRollup/create_new_rollup.json.example b/tools/createNewRollup/create_new_rollup.json.example index bd666a349..6528a9361 100644 --- a/tools/createNewRollup/create_new_rollup.json.example +++ b/tools/createNewRollup/create_new_rollup.json.example @@ -17,10 +17,10 @@ "rollupTypeId": 1, "isVanillaClient": false, "sovereignParams": { - "bridgeManager": "0xC7899Ff6A3aC2FF59261bD960A8C880DF06E1041", + "bridgeManager": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "sovereignWETHAddress": "0x0000000000000000000000000000000000000000", "sovereignWETHAddressIsNotMintable": false, - "globalExitRootUpdater": "0xB55B27Cca633A73108893985350bc26B8A00C43a", - "globalExitRootRemover": "0xB55B27Cca633A73108893985350bc26B8A00C43a" + "globalExitRootUpdater": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "globalExitRootRemover": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" } } \ No newline at end of file diff --git a/tools/utils.js b/tools/utils.js index 69766503b..0f3edd271 100644 --- a/tools/utils.js +++ b/tools/utils.js @@ -28,6 +28,9 @@ const createNewRollupTypes = { // Function to recursively convert BigInts to Numbers function convertBigIntsToNumbers(obj) { if (typeof obj === 'bigint') { + if (obj > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error(`convertBigIntsToNumbers: BigInt exceeds maximum safe integer: ${obj}`); + } return Number(obj); // Convert BigInt to Number }