diff --git a/contracts/v2/periphery/BatchL2DataCreatedRollup.sol b/contracts/v2/periphery/BatchL2DataCreatedRollup.sol new file mode 100644 index 00000000..f56928b7 --- /dev/null +++ b/contracts/v2/periphery/BatchL2DataCreatedRollup.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.20; + +import "../lib/PolygonRollupBaseEtrog.sol"; + + +// This contract is only used for a specific tool: zkevm-contracts/tools/batchL2DataCreatedRollup. +// This contract is part of the zkevm-contracts/contracts/v2/lib/PolygonRollupBaseEtrog.sol contract. +contract BatchL2DataCreatedRollup { + + uint8 public constant INITIALIZE_TX_BRIDGE_LIST_LEN_LEN = 0xf9; + bytes public constant INITIALIZE_TX_BRIDGE_PARAMS = hex"80808401c9c38094"; + uint16 public constant INITIALIZE_TX_CONSTANT_BYTES = 32; + bytes public constant INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS = + hex"80b9"; + uint16 public constant INITIALIZE_TX_CONSTANT_BYTES_EMPTY_METADATA = 31; + uint8 public constant INITIALIZE_TX_DATA_LEN_EMPTY_METADATA = 228; + bytes + public constant INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS_EMPTY_METADATA = + hex"80b8"; + + uint8 public constant SIGNATURE_INITIALIZE_TX_V = 27; + bytes32 public constant SIGNATURE_INITIALIZE_TX_R = + 0x00000000000000000000000000000000000000000000000000000005ca1ab1e0; + bytes32 public constant SIGNATURE_INITIALIZE_TX_S = + 0x000000000000000000000000000000000000000000000000000000005ca1ab1e; + bytes1 public constant INITIALIZE_TX_EFFECTIVE_PERCENTAGE = 0xFF; + IBasePolygonZkEVMGlobalExitRoot + public constant GLOBAL_EXIT_ROOT_MANAGER_L2 = + IBasePolygonZkEVMGlobalExitRoot( + 0xa40D5f56745a118D0906a34E69aeC8C0Db1cB8fA + ); + + /** + * @notice Generate Initialize transaction for hte bridge on L2 + * @param networkID Indicates the network identifier that will be used in the bridge + * @param bridgeAddress Indicates the bridge address + * @param _gasTokenAddress Indicates the token address that will be used to pay gas fees in the new rollup + * @param _gasTokenNetwork Indicates the native network of the token address + * @param _gasTokenMetadata Abi encoded gas token metadata + */ + function generateInitializeTransaction( + uint32 networkID, + address bridgeAddress, + address _gasTokenAddress, + uint32 _gasTokenNetwork, + bytes memory _gasTokenMetadata + ) public view returns (bytes memory) { + bytes memory initializeBrigeData = abi.encodeCall( + IPolygonZkEVMBridgeV2.initialize, + ( + networkID, + _gasTokenAddress, + _gasTokenNetwork, + GLOBAL_EXIT_ROOT_MANAGER_L2, + address(0), // Rollup manager on L2 does not exist + _gasTokenMetadata + ) + ); + + bytes memory bytesToSign; + uint16 initializeBrigeDataLen = uint16(initializeBrigeData.length); + + if (_gasTokenMetadata.length == 0) { + bytesToSign = abi.encodePacked( + INITIALIZE_TX_BRIDGE_LIST_LEN_LEN, + initializeBrigeDataLen + + INITIALIZE_TX_CONSTANT_BYTES_EMPTY_METADATA, // do not support more than 2 bytes of length, intended to revert on overflow + INITIALIZE_TX_BRIDGE_PARAMS, + bridgeAddress, + INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS_EMPTY_METADATA, + INITIALIZE_TX_DATA_LEN_EMPTY_METADATA, + initializeBrigeData + ); + } else { + bytesToSign = abi.encodePacked( + INITIALIZE_TX_BRIDGE_LIST_LEN_LEN, + initializeBrigeDataLen + + INITIALIZE_TX_CONSTANT_BYTES, // do not support more than 2 bytes of length, intended to revert on overflow + INITIALIZE_TX_BRIDGE_PARAMS, + bridgeAddress, + INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS, + initializeBrigeDataLen, + initializeBrigeData + ); + } + + // Sanity check that the ecrecover will work + // Should never happen that giving a valid signature, ecrecover "breaks" + address signer = ecrecover( + keccak256(bytesToSign), + SIGNATURE_INITIALIZE_TX_V, + SIGNATURE_INITIALIZE_TX_R, + SIGNATURE_INITIALIZE_TX_S + ); + + bytes memory transaction = abi.encodePacked( + bytesToSign, + SIGNATURE_INITIALIZE_TX_R, + SIGNATURE_INITIALIZE_TX_S, + SIGNATURE_INITIALIZE_TX_V, + INITIALIZE_TX_EFFECTIVE_PERCENTAGE + ); + + return transaction; + } +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 8b79a2eb..0d104c53 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -2,6 +2,7 @@ import "dotenv/config"; import "@nomicfoundation/hardhat-toolbox"; import "@openzeppelin/hardhat-upgrades"; import "hardhat-dependency-compiler"; +import "hardhat-switch-network"; import {HardhatUserConfig} from "hardhat/config"; diff --git a/package-lock.json b/package-lock.json index 2151aa41..d383966c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "ffjavascript": "^0.2.60", "hardhat": "^2.22.3", "hardhat-dependency-compiler": "^1.1.3", + "hardhat-switch-network": "^1.2.0", "lodash": "^4.17.21", "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.4.1", @@ -17135,6 +17136,18 @@ "hardhat": "^2.0.2" } }, + "node_modules/hardhat-switch-network": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hardhat-switch-network/-/hardhat-switch-network-1.2.0.tgz", + "integrity": "sha512-z7YubwwQCBiZ+zwx6cnSQ+KryFxzOjOhRhBVFP8KEfEcJh8dhCcM8zuUb05j4m3GGSCSIpQSH98gAqoFlts+og==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "hardhat": "^2.0.0" + } + }, "node_modules/hardhat/node_modules/@noble/hashes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", diff --git a/package.json b/package.json index 01897399..47e4bb8e 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "ffjavascript": "^0.2.60", "hardhat": "^2.22.3", "hardhat-dependency-compiler": "^1.1.3", + "hardhat-switch-network": "^1.2.0", "lodash": "^4.17.21", "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.4.1", @@ -115,4 +116,4 @@ "verify:upgradeV2:mainnet": "npx hardhat run upgrade/upgradeToV2/verifyContracts.ts --network mainnet", "saveUpgradeV2:mainnet": "mkdir -p upgrade/upgradeToV2/mainnet_$(date +%s) && cp -r upgrade/upgradeToV2/upgrade_*.json upgrade/upgradeToV2/mainnet_$(date +%s) && cp -r upgrade/upgradeToV2/deploy_*.json upgrade/upgradeToV2/mainnet_$(date +%s) && cp .openzeppelin/mainnet.json upgrade/upgradeToV2/mainnet_$(date +%s)" } -} +} \ No newline at end of file diff --git a/tools/batchL2DataCreatedRollup/.gitignore b/tools/batchL2DataCreatedRollup/.gitignore new file mode 100644 index 00000000..e1239ebe --- /dev/null +++ b/tools/batchL2DataCreatedRollup/.gitignore @@ -0,0 +1,2 @@ +input.json +tx.json \ No newline at end of file diff --git a/tools/batchL2DataCreatedRollup/generateBatchL2DataCreatedRollup.ts b/tools/batchL2DataCreatedRollup/generateBatchL2DataCreatedRollup.ts new file mode 100644 index 00000000..58840e05 --- /dev/null +++ b/tools/batchL2DataCreatedRollup/generateBatchL2DataCreatedRollup.ts @@ -0,0 +1,37 @@ +import hre from "hardhat"; +import fs from "fs"; +import input from "./input.json"; +import { + PolygonZkEVMBridgeV2, +} from "../../typechain-types"; + +async function main() { + + // --network + const bridgeFactory = await hre.ethers.getContractFactory("PolygonZkEVMBridgeV2"); + const polygonZkEVMBridgeContract = bridgeFactory.attach(input.bridgeAddress) as PolygonZkEVMBridgeV2; + const gasTokenMetadata = await polygonZkEVMBridgeContract.getTokenMetadata(input.gasTokenAddress); + + // switch network hardhat + await hre.switchNetwork("hardhat"); + + const toolFactory = await hre.ethers.getContractFactory("BatchL2DataCreatedRollup"); + const toolContract = await toolFactory.deploy(); + await toolContract.waitForDeployment() + const tx = await toolContract.generateInitializeTransaction(input.networkID, input.bridgeAddress, input.gasTokenAddress, input.gasTokenNetwork, gasTokenMetadata) + const output = { + networkID: input.networkID, + tx: tx, + } + + // write tx.json + const txPath = "./tx.json" + fs.writeFileSync(txPath, JSON.stringify(output, null, 1)) +} +main().then(() => { + process.exit(0); +}, (err) => { + console.log(err.message); + console.log(err.stack); + process.exit(1); +}); \ No newline at end of file diff --git a/tools/batchL2DataCreatedRollup/input.json.example b/tools/batchL2DataCreatedRollup/input.json.example new file mode 100644 index 00000000..5e69a0d3 --- /dev/null +++ b/tools/batchL2DataCreatedRollup/input.json.example @@ -0,0 +1,6 @@ +{ + "networkID": 0, + "bridgeAddress": "0x9b28F436039654F8b948dd32599032F684899cF0", + "gasTokenAddress": "0x0000000000000000000000000000000000000000", + "gasTokenNetwork": 0 +} \ No newline at end of file