From ec8e9daec4f4228d04f76ac21d81c962369a6a44 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 10 Sep 2024 15:10:39 +0200 Subject: [PATCH 01/54] Deploy legacy bridge inside foundry (#787) Signed-off-by: Danil Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> --- .../deploy-scripts/DeployL2Contracts.sol | 54 ++++-- .../dev/SetupLegacyBridge.s.sol | 155 ++++++++++++++++++ 2 files changed, 197 insertions(+), 12 deletions(-) create mode 100644 l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index b22c091ae..dddd26b25 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -43,12 +43,20 @@ contract DeployL2Script is Script { } function run() public { + deploy(false); + } + + function runWithLegacyBridge() public { + deploy(true); + } + + function deploy(bool legacyBridge) public { initializeConfig(); - loadContracts(); + loadContracts(legacyBridge); deployFactoryDeps(); deploySharedBridge(); - deploySharedBridgeProxy(); + deploySharedBridgeProxy(legacyBridge); initializeChain(); deployForceDeployer(); deployConsensusRegistry(); @@ -57,13 +65,21 @@ contract DeployL2Script is Script { saveOutput(); } + function runDeployLegacySharedBridge() public { + deploySharedBridge(true); + } + function runDeploySharedBridge() public { + deploySharedBridge(false); + } + + function deploySharedBridge(bool legacyBridge) internal { initializeConfig(); - loadContracts(); + loadContracts(legacyBridge); deployFactoryDeps(); deploySharedBridge(); - deploySharedBridgeProxy(); + deploySharedBridgeProxy(legacyBridge); initializeChain(); saveOutput(); @@ -71,7 +87,7 @@ contract DeployL2Script is Script { function runDefaultUpgrader() public { initializeConfig(); - loadContracts(); + loadContracts(false); deployForceDeployer(); @@ -80,7 +96,7 @@ contract DeployL2Script is Script { function runDeployConsensusRegistry() public { initializeConfig(); - loadContracts(); + loadContracts(false); deployConsensusRegistry(); deployConsensusRegistryProxy(); @@ -88,7 +104,7 @@ contract DeployL2Script is Script { saveOutput(); } - function loadContracts() internal { + function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat contracts.l2StandardErc20FactoryBytecode = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" @@ -100,9 +116,16 @@ contract DeployL2Script is Script { "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" ); - contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2SharedBridge.sol/L2SharedBridge.json" - ); + if (legacyBridge) { + contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/dev-contracts/DevL2SharedBridge.sol/DevL2SharedBridge.json" + ); + } else { + contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/bridge/L2SharedBridge.sol/L2SharedBridge.json" + ); + } + contracts.l2SharedBridgeProxyBytecode = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); @@ -183,13 +206,20 @@ contract DeployL2Script is Script { }); } - function deploySharedBridgeProxy() internal { + function deploySharedBridgeProxy(bool legacyBridge) internal { address l2GovernorAddress = AddressAliasHelper.applyL1ToL2Alias(config.governance); bytes32 l2StandardErc20BytecodeHash = L2ContractHelper.hashL2Bytecode(contracts.beaconProxy); + string memory functionSignature; + + if (legacyBridge) { + functionSignature = "initializeDevBridge(address,address,bytes32,address)"; + } else { + functionSignature = "initialize(address,address,bytes32,address)"; + } // solhint-disable-next-line func-named-parameters bytes memory proxyInitializationParams = abi.encodeWithSignature( - "initialize(address,address,bytes32,address)", + functionSignature, config.l1SharedBridgeProxy, config.erc20BridgeProxy, l2StandardErc20BytecodeHash, diff --git a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol new file mode 100644 index 000000000..301bfd2c8 --- /dev/null +++ b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; +import {Utils} from "./../Utils.sol"; +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {DummyL1ERC20Bridge} from "contracts/dev-contracts/DummyL1ERC20Bridge.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; + +/// This scripts is only for developer +contract SetupLegacyBridge is Script { + using stdToml for string; + + Config internal config; + Addresses internal addresses; + + struct Config { + uint256 chainId; + address l2SharedBridgeAddress; + bytes32 create2FactorySalt; + } + + struct Addresses { + address create2FactoryAddr; + address bridgehub; + address diamondProxy; + address sharedBridgeProxy; + address transparentProxyAdmin; + address erc20BridgeProxy; + address tokenWethAddress; + address erc20BridgeProxyImpl; + address sharedBridgeProxyImpl; + } + + function run() public { + initializeConfig(); + deploySharedBridgeImplementation(); + upgradeImplementation(addresses.sharedBridgeProxy, addresses.sharedBridgeProxyImpl); + deployDummyErc20Bridge(); + upgradeImplementation(addresses.erc20BridgeProxy, addresses.erc20BridgeProxyImpl); + setParamsForDummyBridge(); + } + + function initializeConfig() internal { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-config/setup-legacy-bridge.toml"); + string memory toml = vm.readFile(path); + + addresses.bridgehub = toml.readAddress("$.bridgehub"); + addresses.diamondProxy = toml.readAddress("$.diamond_proxy"); + addresses.sharedBridgeProxy = toml.readAddress("$.shared_bridge_proxy"); + addresses.transparentProxyAdmin = toml.readAddress("$.transparent_proxy_admin"); + addresses.erc20BridgeProxy = toml.readAddress("$.erc20bridge_proxy"); + addresses.tokenWethAddress = toml.readAddress("$.token_weth_address"); + addresses.create2FactoryAddr = toml.readAddress("$.create2factory_addr"); + config.chainId = toml.readUint("$.chain_id"); + config.l2SharedBridgeAddress = toml.readAddress("$.l2shared_bridge_address"); + config.create2FactorySalt = toml.readBytes32("$.create2factory_salt"); + } + + // We need to deploy new shared bridge for changing chain id and diamond proxy address + function deploySharedBridgeImplementation() internal { + bytes memory bytecode = abi.encodePacked( + type(L1SharedBridge).creationCode, + // solhint-disable-next-line func-named-parameters + abi.encode(addresses.tokenWethAddress, addresses.bridgehub, config.chainId, addresses.diamondProxy) + ); + + address contractAddress = deployViaCreate2(bytecode); + addresses.sharedBridgeProxyImpl = contractAddress; + } + + function deployDummyErc20Bridge() internal { + bytes memory bytecode = abi.encodePacked( + type(DummyL1ERC20Bridge).creationCode, + // solhint-disable-next-line func-named-parameters + abi.encode(addresses.sharedBridgeProxy) + ); + address contractAddress = deployViaCreate2(bytecode); + addresses.erc20BridgeProxyImpl = contractAddress; + } + + function upgradeImplementation(address proxy, address implementation) internal { + bytes memory proxyAdminUpgradeData = abi.encodeCall( + ProxyAdmin.upgrade, + (ITransparentUpgradeableProxy(proxy), implementation) + ); + ProxyAdmin _proxyAdmin = ProxyAdmin(addresses.transparentProxyAdmin); + address governance = _proxyAdmin.owner(); + + Utils.executeUpgrade({ + _governor: address(governance), + _salt: bytes32(0), + _target: address(addresses.transparentProxyAdmin), + _data: proxyAdminUpgradeData, + _value: 0, + _delay: 0 + }); + } + + function setParamsForDummyBridge() internal { + (address l2TokenBeacon, bytes32 l2TokenBeaconHash) = calculateTokenBeaconAddress(); + DummyL1ERC20Bridge bridge = DummyL1ERC20Bridge(addresses.erc20BridgeProxy); + bridge.setValues(config.l2SharedBridgeAddress, l2TokenBeacon, l2TokenBeaconHash); + } + + function calculateTokenBeaconAddress() + internal + returns (address tokenBeaconAddress, bytes32 tokenBeaconBytecodeHash) + { + bytes memory l2StandardTokenCode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" + ); + (address l2StandardToken, ) = calculateL2Create2Address( + config.l2SharedBridgeAddress, + l2StandardTokenCode, + bytes32(0), + "" + ); + + bytes memory beaconProxy = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" + ); + + (tokenBeaconAddress, tokenBeaconBytecodeHash) = calculateL2Create2Address( + config.l2SharedBridgeAddress, + beaconProxy, + bytes32(0), + abi.encode(l2StandardToken) + ); + } + + function calculateL2Create2Address( + address sender, + bytes memory bytecode, + bytes32 create2salt, + bytes memory constructorargs + ) internal returns (address create2Address, bytes32 bytecodeHash) { + bytecodeHash = L2ContractHelper.hashL2Bytecode(bytecode); + + create2Address = L2ContractHelper.computeCreate2Address( + sender, + create2salt, + bytecodeHash, + keccak256(constructorargs) + ); + } + + function deployViaCreate2(bytes memory _bytecode) internal returns (address) { + return Utils.deployViaCreate2(_bytecode, config.create2FactorySalt, addresses.create2FactoryAddr); + } +} From 73b20c4b972f575613b4054d238332f93f2685cc Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 12 Sep 2024 10:36:06 +0200 Subject: [PATCH 02/54] deploy legacy bridge (#795) Signed-off-by: Danil Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> --- .../deploy-scripts/dev/SetupLegacyBridge.s.sol | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol index 301bfd2c8..e178824b1 100644 --- a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol +++ b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol @@ -104,6 +104,7 @@ contract SetupLegacyBridge is Script { function setParamsForDummyBridge() internal { (address l2TokenBeacon, bytes32 l2TokenBeaconHash) = calculateTokenBeaconAddress(); DummyL1ERC20Bridge bridge = DummyL1ERC20Bridge(addresses.erc20BridgeProxy); + vm.broadcast(); bridge.setValues(config.l2SharedBridgeAddress, l2TokenBeacon, l2TokenBeaconHash); } @@ -124,10 +125,15 @@ contract SetupLegacyBridge is Script { bytes memory beaconProxy = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" ); + tokenBeaconBytecodeHash = L2ContractHelper.hashL2Bytecode(beaconProxy); - (tokenBeaconAddress, tokenBeaconBytecodeHash) = calculateL2Create2Address( + bytes memory upgradableBeacon = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" + ); + + (tokenBeaconAddress, ) = calculateL2Create2Address( config.l2SharedBridgeAddress, - beaconProxy, + upgradableBeacon, bytes32(0), abi.encode(l2StandardToken) ); From 3a1b5d4b94ffb00f03d436a7db7e48589eb74d39 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 12 Sep 2024 14:44:04 +0200 Subject: [PATCH 03/54] use chain admin for bridgehub manipulations (#799) Signed-off-by: Danil Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> --- l1-contracts/deploy-scripts/DeployL1.s.sol | 4 +++ .../deploy-scripts/RegisterHyperchain.s.sol | 26 +++++-------------- l1-contracts/deploy-scripts/Utils.sol | 10 +++++++ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 8c071090b..f4de831a8 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -586,12 +586,15 @@ contract DeployL1Script is Script { Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); bridgehub.transferOwnership(addresses.governance); + bridgehub.setPendingAdmin(addresses.chainAdmin); L1SharedBridge sharedBridge = L1SharedBridge(addresses.bridges.sharedBridgeProxy); sharedBridge.transferOwnership(addresses.governance); + sharedBridge.setPendingAdmin(addresses.chainAdmin); StateTransitionManager stm = StateTransitionManager(addresses.stateTransition.stateTransitionProxy); stm.transferOwnership(addresses.governance); + stm.setPendingAdmin(addresses.chainAdmin); vm.stopBroadcast(); console.log("Owners updated"); @@ -702,6 +705,7 @@ contract DeployL1Script is Script { addresses.blobVersionedHashRetriever ); vm.serializeAddress("deployed_addresses", "validator_timelock_addr", addresses.validatorTimelock); + vm.serializeAddress("deployed_addresses", "chain_admin", addresses.chainAdmin); vm.serializeString("deployed_addresses", "bridgehub", bridgehub); vm.serializeString("deployed_addresses", "state_transition", stateTransition); string memory deployedAddresses = vm.serializeString("deployed_addresses", "bridges", bridges); diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index e7615b598..f5e23cf8d 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -7,8 +7,7 @@ import {Script, console2 as console} from "forge-std/Script.sol"; import {Vm} from "forge-std/Vm.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; +import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; import {Governance} from "contracts/governance/Governance.sol"; @@ -118,20 +117,17 @@ contract RegisterHyperchainScript is Script { } function registerTokenOnBridgehub() internal { - IBridgehub bridgehub = IBridgehub(config.bridgehub); - Ownable ownable = Ownable(config.bridgehub); + Bridgehub bridgehub = Bridgehub(config.bridgehub); if (bridgehub.tokenIsRegistered(config.baseToken)) { console.log("Token already registered on Bridgehub"); } else { bytes memory data = abi.encodeCall(bridgehub.addToken, (config.baseToken)); - Utils.executeUpgrade({ - _governor: ownable.owner(), - _salt: bytes32(config.bridgehubCreateNewChainSalt), + Utils.chainAdminMulticall({ + _chainAdmin: bridgehub.admin(), _target: config.bridgehub, _data: data, - _value: 0, - _delay: 0 + _value: 0 }); console.log("Token registered on Bridgehub"); } @@ -156,8 +152,7 @@ contract RegisterHyperchainScript is Script { } function registerHyperchain() internal { - IBridgehub bridgehub = IBridgehub(config.bridgehub); - Ownable ownable = Ownable(config.bridgehub); + Bridgehub bridgehub = Bridgehub(config.bridgehub); vm.recordLogs(); bytes memory data = abi.encodeCall( @@ -172,14 +167,7 @@ contract RegisterHyperchainScript is Script { ) ); - Utils.executeUpgrade({ - _governor: ownable.owner(), - _salt: bytes32(config.bridgehubCreateNewChainSalt), - _target: config.bridgehub, - _data: data, - _value: 0, - _delay: 0 - }); + Utils.chainAdminMulticall({_chainAdmin: bridgehub.admin(), _target: config.bridgehub, _data: data, _value: 0}); console.log("Hyperchain registered"); // Get new diamond proxy address from emitted events diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index 23bcf0ff8..fb56bce08 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -10,6 +10,7 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; +import {IChainAdmin} from "contracts/governance/IChainAdmin.sol"; library Utils { // Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. @@ -288,6 +289,15 @@ library Utils { return bytecode; } + function chainAdminMulticall(address _chainAdmin, address _target, bytes memory _data, uint256 _value) internal { + IChainAdmin chainAdmin = IChainAdmin(_chainAdmin); + + IChainAdmin.Call[] memory calls = new IChainAdmin.Call[](1); + calls[0] = IChainAdmin.Call({target: _target, value: _value, data: _data}); + vm.broadcast(); + chainAdmin.multicall(calls, true); + } + function executeUpgrade( address _governor, bytes32 _salt, From 9ebf9be53bb3629585a55cd524fb78936817d77a Mon Sep 17 00:00:00 2001 From: Danil Date: Fri, 13 Sep 2024 16:12:47 +0200 Subject: [PATCH 04/54] fix(deploy): Initilize chain using ChainAdmin (#807) Signed-off-by: Danil --- l1-contracts/deploy-scripts/DeployL2Contracts.sol | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index dddd26b25..b361e221d 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -295,13 +295,11 @@ contract DeployL2Script is Script { function initializeChain() internal { L1SharedBridge bridge = L1SharedBridge(config.l1SharedBridgeProxy); - Utils.executeUpgrade({ - _governor: bridge.owner(), - _salt: bytes32(0), + Utils.chainAdminMulticall({ + _chainAdmin: bridge.admin(), _target: config.l1SharedBridgeProxy, _data: abi.encodeCall(bridge.initializeChainGovernance, (config.chainId, config.l2SharedBridgeProxy)), - _value: 0, - _delay: 0 + _value: 0 }); } } From bce4b2d0f34bd87f1aaadd291772935afb1c3bd6 Mon Sep 17 00:00:00 2001 From: Grzegorz Prusak Date: Sat, 14 Sep 2024 10:52:47 +0200 Subject: [PATCH 05/54] feat: multicall3 on L2 (#805) --- .../deploy-scripts/DeployL2Contracts.sol | 24 ++ .../contracts/dev-contracts/Multicall3.sol | 237 ++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 l2-contracts/contracts/dev-contracts/Multicall3.sol diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index b361e221d..9e78f05e5 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -28,6 +28,7 @@ contract DeployL2Script is Script { address l2SharedBridgeProxy; address consensusRegistryImplementation; address consensusRegistryProxy; + address multicall3; address forceDeployUpgraderAddress; } @@ -39,6 +40,7 @@ contract DeployL2Script is Script { bytes l2SharedBridgeProxyBytecode; bytes consensusRegistryBytecode; bytes consensusRegistryProxyBytecode; + bytes multicall3Bytecode; bytes forceDeployUpgrader; } @@ -61,6 +63,7 @@ contract DeployL2Script is Script { deployForceDeployer(); deployConsensusRegistry(); deployConsensusRegistryProxy(); + deployMulticall3(); saveOutput(); } @@ -137,6 +140,10 @@ contract DeployL2Script is Script { "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); + contracts.multicall3Bytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/dev-contracts/Multicall3.sol/Multicall3.json" + ); + contracts.forceDeployUpgrader = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/contracts/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" ); @@ -160,6 +167,7 @@ contract DeployL2Script is Script { vm.serializeAddress("root", "l2_shared_bridge_proxy", config.l2SharedBridgeProxy); vm.serializeAddress("root", "consensus_registry_implementation", config.consensusRegistryImplementation); vm.serializeAddress("root", "consensus_registry_proxy", config.consensusRegistryProxy); + vm.serializeAddress("root", "multicall3", config.multicall3); string memory toml = vm.serializeAddress("root", "l2_default_upgrader", config.forceDeployUpgraderAddress); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-deploy-l2-contracts.toml"); @@ -261,6 +269,22 @@ contract DeployL2Script is Script { }); } + function deployMulticall3() internal { + // Multicall3 doesn't have a constructor. + bytes memory constructorData = ""; + + config.multicall3 = Utils.deployThroughL1({ + bytecode: contracts.multicall3Bytecode, + constructorargs: constructorData, + create2salt: "", + l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, + factoryDeps: new bytes[](0), + chainId: config.chainId, + bridgehubAddress: config.bridgehubAddress, + l1SharedBridgeProxy: config.l1SharedBridgeProxy + }); + } + // Deploy a transparent upgradable proxy for the already deployed consensus registry // implementation and save its address into the config. function deployConsensusRegistryProxy() internal { diff --git a/l2-contracts/contracts/dev-contracts/Multicall3.sol b/l2-contracts/contracts/dev-contracts/Multicall3.sol new file mode 100644 index 000000000..9a6c69340 --- /dev/null +++ b/l2-contracts/contracts/dev-contracts/Multicall3.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +/// @title Multicall3 +/// @notice Aggregate results from multiple function calls +/// @dev Multicall & Multicall2 backwards-compatible +/// @dev Aggregate methods are marked `payable` to save 24 gas per call +/// @author Michael Elliot +/// @author Joshua Levine +/// @author Nick Johnson +/// @author Andreas Bigger +/// @author Matt Solomon +contract Multicall3 { + // add this to be excluded from coverage report + function test() internal virtual {} + + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + /// @notice Backwards-compatible call aggregation with Multicall + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return returnData An array of bytes containing the responses + function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) { + blockNumber = block.number; + uint256 length = calls.length; + returnData = new bytes[](length); + Call calldata call; + for (uint256 i = 0; i < length; ) { + bool success; + call = calls[i]; + (success, returnData[i]) = call.target.call(call.callData); + require(success, "Multicall3: call failed"); + unchecked { + ++i; + } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls without requiring success + /// @param requireSuccess If true, require all calls to succeed + /// @param calls An array of Call structs + /// @return returnData An array of Result structs + function tryAggregate( + bool requireSuccess, + Call[] calldata calls + ) public payable returns (Result[] memory returnData) { + uint256 length = calls.length; + returnData = new Result[](length); + Call calldata call; + for (uint256 i = 0; i < length; ) { + Result memory result = returnData[i]; + call = calls[i]; + (result.success, result.returnData) = call.target.call(call.callData); + if (requireSuccess) require(result.success, "Multicall3: call failed"); + unchecked { + ++i; + } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function tryBlockAndAggregate( + bool requireSuccess, + Call[] calldata calls + ) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { + blockNumber = block.number; + blockHash = blockhash(block.number); + returnData = tryAggregate(requireSuccess, calls); + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function blockAndAggregate( + Call[] calldata calls + ) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { + (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); + } + + /// @notice Aggregate calls, ensuring each returns success if required + /// @param calls An array of Call3 structs + /// @return returnData An array of Result structs + function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 length = calls.length; + returnData = new Result[](length); + Call3 calldata calli; + for (uint256 i = 0; i < length; ) { + Result memory result = returnData[i]; + calli = calls[i]; + (result.success, result.returnData) = calli.target.call(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x64) + } + } + unchecked { + ++i; + } + } + } + + /// @notice Aggregate calls with a msg value + /// @notice Reverts if msg.value is less than the sum of the call values + /// @param calls An array of Call3Value structs + /// @return returnData An array of Result structs + function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 valAccumulator; + uint256 length = calls.length; + returnData = new Result[](length); + Call3Value calldata calli; + for (uint256 i = 0; i < length; ) { + Result memory result = returnData[i]; + calli = calls[i]; + uint256 val = calli.value; + // Humanity will be a Type V Kardashev Civilization before this overflows - andreas + // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256 + unchecked { + valAccumulator += val; + } + (result.success, result.returnData) = calli.target.call{value: val}(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x84) + } + } + unchecked { + ++i; + } + } + // Finally, make sure the msg.value = SUM(call[0...i].value) + require(msg.value == valAccumulator, "Multicall3: value mismatch"); + } + + /// @notice Returns the block hash for the given block number + /// @param blockNumber The block number + function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { + blockHash = blockhash(blockNumber); + } + + /// @notice Returns the block number + function getBlockNumber() public view returns (uint256 blockNumber) { + blockNumber = block.number; + } + + /// @notice Returns the block coinbase + function getCurrentBlockCoinbase() public view returns (address coinbase) { + coinbase = block.coinbase; + } + + /// @notice Returns the block difficulty + function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { + difficulty = block.prevrandao; + } + + /// @notice Returns the block gas limit + function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { + gaslimit = block.gaslimit; + } + + /// @notice Returns the block timestamp + function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { + timestamp = block.timestamp; + } + + /// @notice Returns the (ETH) balance of a given address + function getEthBalance(address addr) public view returns (uint256 balance) { + balance = addr.balance; + } + + /// @notice Returns the block hash of the last block + function getLastBlockHash() public view returns (bytes32 blockHash) { + unchecked { + blockHash = blockhash(block.number - 1); + } + } + + /// @notice Gets the base fee of the given block + /// @notice Can revert if the BASEFEE opcode is not implemented by the given chain + function getBasefee() public view returns (uint256 basefee) { + basefee = block.basefee; + } + + /// @notice Returns the chain id + function getChainId() public view returns (uint256 chainid) { + chainid = block.chainid; + } +} From 1fba03d3c6c5e3412f19b9960c1931efc6b17380 Mon Sep 17 00:00:00 2001 From: koloz193 Date: Fri, 27 Sep 2024 12:21:02 -0400 Subject: [PATCH 06/54] merging main (#824) --- gas-bound-caller/package.json | 3 +- .../contracts/bridge/L1SharedBridge.sol | 53 +- .../bridge/interfaces/IL1SharedBridge.sol | 15 + .../contracts/bridgehub/Bridgehub.sol | 2 +- .../config-deploy-l2-config.toml | 1 + l1-contracts/deploy-scripts/DeployL1.s.sol | 4 + .../deploy-scripts/DeployL2Contracts.sol | 165 +++++- .../deploy-scripts/RegisterHyperchain.s.sol | 26 +- l1-contracts/deploy-scripts/Utils.sol | 10 + .../dev/SetupLegacyBridge.s.sol | 161 ++++++ .../Bridgehub/experimental_bridge.t.sol | 17 +- .../L1SharedBridge/L1SharedBridgeAdmin.t.sol | 26 + .../L1SharedBridge/L1SharedBridgeFails.t.sol | 6 +- .../_L1SharedBridge_Shared.t.sol | 8 +- l2-contracts/contracts/ConsensusRegistry.sol | 486 +++++++++++++++++ .../contracts/dev-contracts/Multicall3.sol | 237 +++++++++ .../interfaces/IConsensusRegistry.sol | 161 ++++++ l2-contracts/package.json | 3 +- l2-contracts/src/deploy-consensus-registry.ts | 90 ++++ l2-contracts/src/utils.ts | 21 + l2-contracts/test/consensusRegistry.test.ts | 499 ++++++++++++++++++ system-contracts/package.json | 3 +- .../scripts/verify-on-explorer.ts | 2 +- yarn.lock | 6 +- 24 files changed, 1945 insertions(+), 60 deletions(-) create mode 100644 l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol create mode 100644 l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeAdmin.t.sol create mode 100644 l2-contracts/contracts/ConsensusRegistry.sol create mode 100644 l2-contracts/contracts/dev-contracts/Multicall3.sol create mode 100644 l2-contracts/contracts/interfaces/IConsensusRegistry.sol create mode 100644 l2-contracts/src/deploy-consensus-registry.ts create mode 100644 l2-contracts/test/consensusRegistry.test.ts diff --git a/gas-bound-caller/package.json b/gas-bound-caller/package.json index af91e7593..96593e37a 100644 --- a/gas-bound-caller/package.json +++ b/gas-bound-caller/package.json @@ -14,7 +14,8 @@ "ethers": "^5.7.0", "fast-glob": "^3.3.2", "hardhat": "=2.22.2", - "preprocess": "^3.2.0" + "preprocess": "^3.2.0", + "zksync-ethers": "^5.9.0" }, "devDependencies": { "@matterlabs/hardhat-zksync-chai-matchers": "^0.2.0", diff --git a/l1-contracts/contracts/bridge/L1SharedBridge.sol b/l1-contracts/contracts/bridge/L1SharedBridge.sol index 56b621c18..eaddcccc7 100644 --- a/l1-contracts/contracts/bridge/L1SharedBridge.sol +++ b/l1-contracts/contracts/bridge/L1SharedBridge.sol @@ -90,6 +90,12 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// NOTE: this function may be removed in the future, don't rely on it! mapping(uint256 chainId => mapping(address l1Token => uint256 balance)) public chainBalance; + /// @dev Admin has the ability to register new chains within the shared bridge. + address public admin; + + /// @dev The pending admin, i.e. the candidate to the admin role. + address public pendingAdmin; + /// @notice Checks that the message sender is the bridgehub. modifier onlyBridgehub() { if (msg.sender != address(BRIDGE_HUB)) { @@ -122,6 +128,12 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade _; } + /// @notice Checks that the message sender is either the owner or admin. + modifier onlyOwnerOrAdmin() { + require(msg.sender == owner() || msg.sender == admin, "ShB not owner or admin"); + _; + } + /// @dev Contract is expected to be used as proxy implementation. /// @dev Initialize the implementation to prevent Parity hack. constructor( @@ -147,6 +159,31 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade _transferOwnership(_owner); } + /// @inheritdoc IL1SharedBridge + /// @dev Please note, if the owner wants to enforce the admin change it must execute both `setPendingAdmin` and + /// `acceptAdmin` atomically. Otherwise `admin` can set different pending admin and so fail to accept the admin rights. + function setPendingAdmin(address _newPendingAdmin) external onlyOwnerOrAdmin { + // Save previous value into the stack to put it into the event later + address oldPendingAdmin = pendingAdmin; + // Change pending admin + pendingAdmin = _newPendingAdmin; + emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin); + } + + /// @inheritdoc IL1SharedBridge + /// @notice Accepts transfer of admin rights. Only pending admin can accept the role. + function acceptAdmin() external { + address currentPendingAdmin = pendingAdmin; + require(msg.sender == currentPendingAdmin, "ShB not pending admin"); // Only proposed by current admin address can claim the admin rights + + address previousAdmin = admin; + admin = currentPendingAdmin; + delete pendingAdmin; + + emit NewPendingAdmin(currentPendingAdmin, address(0)); + emit NewAdmin(previousAdmin, currentPendingAdmin); + } + /// @dev This sets the first post diamond upgrade batch for era, used to check old eth withdrawals /// @param _eraPostDiamondUpgradeFirstBatch The first batch number on the ZKsync Era Diamond Proxy that was settled after diamond proxy upgrade. function setEraPostDiamondUpgradeFirstBatch(uint256 _eraPostDiamondUpgradeFirstBatch) external onlyOwner { @@ -236,7 +273,21 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade } /// @dev Initializes the l2Bridge address by governance for a specific chain. - function initializeChainGovernance(uint256 _chainId, address _l2BridgeAddress) external onlyOwner { + /// @param _chainId The chain ID for which the l2Bridge address is being initialized. + /// @param _l2BridgeAddress The address of the L2 bridge contract. + function initializeChainGovernance(uint256 _chainId, address _l2BridgeAddress) external onlyOwnerOrAdmin { + require(l2BridgeAddress[_chainId] == address(0), "ShB: l2 bridge already set"); + require(_l2BridgeAddress != address(0), "ShB: l2 bridge 0"); + l2BridgeAddress[_chainId] = _l2BridgeAddress; + } + + /// @dev Reinitializes the l2Bridge address by governance for a specific chain. + /// @dev Only accessible to the owner of the bridge to prevent malicious admin from changing the bridge address for + /// an existing chain. + /// @param _chainId The chain ID for which the l2Bridge address is being initialized. + /// @param _l2BridgeAddress The address of the L2 bridge contract. + function reinitializeChainGovernance(uint256 _chainId, address _l2BridgeAddress) external onlyOwner { + require(l2BridgeAddress[_chainId] != address(0), "ShB: l2 bridge not yet set"); l2BridgeAddress[_chainId] = _l2BridgeAddress; } diff --git a/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol b/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol index 8038d6bdb..cc58d160f 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol @@ -10,6 +10,13 @@ import {IL1ERC20Bridge} from "./IL1ERC20Bridge.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev interface IL1SharedBridge { + /// @notice pendingAdmin is changed + /// @dev Also emitted when new admin is accepted and in this case, `newPendingAdmin` would be zero address + event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin); + + /// @notice Admin changed + event NewAdmin(address indexed oldAdmin, address indexed newAdmin); + event LegacyDepositInitiated( uint256 indexed chainId, bytes32 indexed l2DepositTxHash, @@ -151,4 +158,12 @@ interface IL1SharedBridge { function bridgehubConfirmL2Transaction(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external; function receiveEth(uint256 _chainId) external payable; + + /// @notice Starts the transfer of admin rights. Only the current admin can propose a new pending one. + /// @notice New admin can accept admin rights by calling `acceptAdmin` function. + /// @param _newPendingAdmin Address of the new admin + function setPendingAdmin(address _newPendingAdmin) external; + + /// @notice Accepts transfer of admin rights. Only pending admin can accept the role. + function acceptAdmin() external; } diff --git a/l1-contracts/contracts/bridgehub/Bridgehub.sol b/l1-contracts/contracts/bridgehub/Bridgehub.sol index 0f1ccbfab..89001c2cd 100644 --- a/l1-contracts/contracts/bridgehub/Bridgehub.sol +++ b/l1-contracts/contracts/bridgehub/Bridgehub.sol @@ -119,7 +119,7 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus } /// @notice token can be any contract with the appropriate interface/functionality - function addToken(address _token) external onlyOwner { + function addToken(address _token) external onlyOwnerOrAdmin { if (tokenIsRegistered[_token]) { revert TokenAlreadyRegistered(_token); } diff --git a/l1-contracts/deploy-script-config-template/config-deploy-l2-config.toml b/l1-contracts/deploy-script-config-template/config-deploy-l2-config.toml index 67e46ae38..fae9cc907 100644 --- a/l1-contracts/deploy-script-config-template/config-deploy-l2-config.toml +++ b/l1-contracts/deploy-script-config-template/config-deploy-l2-config.toml @@ -4,3 +4,4 @@ l1_shared_bridge = "0x2ae37d8130b82c7e79b3863a39027178e073eedb" bridgehub = "0xea785a9c91a07ed69b83eb165f4ce2c30ecb4c0b" governance = "0x6a08d69675af7755569a1a25ef37e795493473a1" erc20_bridge = "0x84fbda16bd5f2d66d7fbaec5e8d816e7b7014595" +consensus_registry_owner = "0xD64e136566a9E04eb05B30184fF577F52682D182" diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 098aee5bc..416ffd6a3 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -593,12 +593,15 @@ contract DeployL1Script is Script { Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); bridgehub.transferOwnership(addresses.governance); + bridgehub.setPendingAdmin(addresses.chainAdmin); L1SharedBridge sharedBridge = L1SharedBridge(addresses.bridges.sharedBridgeProxy); sharedBridge.transferOwnership(addresses.governance); + sharedBridge.setPendingAdmin(addresses.chainAdmin); StateTransitionManager stm = StateTransitionManager(addresses.stateTransition.stateTransitionProxy); stm.transferOwnership(addresses.governance); + stm.setPendingAdmin(addresses.chainAdmin); vm.stopBroadcast(); console.log("Owners updated"); @@ -709,6 +712,7 @@ contract DeployL1Script is Script { addresses.blobVersionedHashRetriever ); vm.serializeAddress("deployed_addresses", "validator_timelock_addr", addresses.validatorTimelock); + vm.serializeAddress("deployed_addresses", "chain_admin", addresses.chainAdmin); vm.serializeString("deployed_addresses", "bridgehub", bridgehub); vm.serializeString("deployed_addresses", "state_transition", stateTransition); string memory deployedAddresses = vm.serializeString("deployed_addresses", "bridges", bridges); diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 6e3b5248b..554ed940c 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -22,10 +22,16 @@ contract DeployL2Script is Script { address l1SharedBridgeProxy; address governance; address erc20BridgeProxy; + // The owner of the contract sets the validator/attester weights. + // Can be the developer multisig wallet on mainnet. + address consensusRegistryOwner; uint256 chainId; uint256 eraChainId; address l2SharedBridgeImplementation; address l2SharedBridgeProxy; + address consensusRegistryImplementation; + address consensusRegistryProxy; + address multicall3; address forceDeployUpgraderAddress; } @@ -35,29 +41,51 @@ contract DeployL2Script is Script { bytes l2StandardErc20Bytecode; bytes l2SharedBridgeBytecode; bytes l2SharedBridgeProxyBytecode; + bytes consensusRegistryBytecode; + bytes consensusRegistryProxyBytecode; + bytes multicall3Bytecode; bytes forceDeployUpgrader; } function run() public { + deploy(false); + } + + function runWithLegacyBridge() public { + deploy(true); + } + + function deploy(bool legacyBridge) public { initializeConfig(); - loadContracts(); + loadContracts(legacyBridge); deployFactoryDeps(); deploySharedBridge(); - deploySharedBridgeProxy(); + deploySharedBridgeProxy(legacyBridge); initializeChain(); deployForceDeployer(); + deployConsensusRegistry(); + deployConsensusRegistryProxy(); + deployMulticall3(); saveOutput(); } + function runDeployLegacySharedBridge() public { + deploySharedBridge(true); + } + function runDeploySharedBridge() public { + deploySharedBridge(false); + } + + function deploySharedBridge(bool legacyBridge) internal { initializeConfig(); - loadContracts(); + loadContracts(legacyBridge); deployFactoryDeps(); deploySharedBridge(); - deploySharedBridgeProxy(); + deploySharedBridgeProxy(legacyBridge); initializeChain(); saveOutput(); @@ -65,14 +93,24 @@ contract DeployL2Script is Script { function runDefaultUpgrader() public { initializeConfig(); - loadContracts(); + loadContracts(false); deployForceDeployer(); saveOutput(); } - function loadContracts() internal { + function runDeployConsensusRegistry() public { + initializeConfig(); + loadContracts(false); + + deployConsensusRegistry(); + deployConsensusRegistryProxy(); + + saveOutput(); + } + + function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat contracts.l2StandardErc20FactoryBytecode = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" @@ -84,15 +122,33 @@ contract DeployL2Script is Script { "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" ); - contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/L2SharedBridge.sol/L2SharedBridge.json" - ); + if (legacyBridge) { + contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/dev-contracts/DevL2SharedBridge.sol/DevL2SharedBridge.json" + ); + } else { + contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/bridge/L2SharedBridge.sol/L2SharedBridge.json" + ); + } contracts.l2SharedBridgeProxyBytecode = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); - contracts.forceDeployUpgrader = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" + + contracts.consensusRegistryBytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/ConsensusRegistry.sol/ConsensusRegistry.json" + ); + contracts.consensusRegistryProxyBytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" + ); + + contracts.multicall3Bytecode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/dev-contracts/Multicall3.sol/Multicall3.json" + ); + + contracts.forceDeployUpgrader = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" ); } @@ -104,6 +160,7 @@ contract DeployL2Script is Script { config.governance = toml.readAddress("$.governance"); config.l1SharedBridgeProxy = toml.readAddress("$.l1_shared_bridge"); config.erc20BridgeProxy = toml.readAddress("$.erc20_bridge"); + config.consensusRegistryOwner = toml.readAddress("$.consensus_registry_owner"); config.chainId = toml.readUint("$.chain_id"); config.eraChainId = toml.readUint("$.era_chain_id"); } @@ -111,6 +168,9 @@ contract DeployL2Script is Script { function saveOutput() internal { vm.serializeAddress("root", "l2_shared_bridge_implementation", config.l2SharedBridgeImplementation); vm.serializeAddress("root", "l2_shared_bridge_proxy", config.l2SharedBridgeProxy); + vm.serializeAddress("root", "consensus_registry_implementation", config.consensusRegistryImplementation); + vm.serializeAddress("root", "consensus_registry_proxy", config.consensusRegistryProxy); + vm.serializeAddress("root", "multicall3", config.multicall3); string memory toml = vm.serializeAddress("root", "l2_default_upgrader", config.forceDeployUpgraderAddress); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-deploy-l2-contracts.toml"); @@ -157,13 +217,20 @@ contract DeployL2Script is Script { }); } - function deploySharedBridgeProxy() internal { + function deploySharedBridgeProxy(bool legacyBridge) internal { address l2GovernorAddress = AddressAliasHelper.applyL1ToL2Alias(config.governance); bytes32 l2StandardErc20BytecodeHash = L2ContractHelper.hashL2Bytecode(contracts.beaconProxy); + string memory functionSignature; + + if (legacyBridge) { + functionSignature = "initializeDevBridge(address,address,bytes32,address)"; + } else { + functionSignature = "initialize(address,address,bytes32,address)"; + } // solhint-disable-next-line func-named-parameters bytes memory proxyInitializationParams = abi.encodeWithSignature( - "initialize(address,address,bytes32,address)", + functionSignature, config.l1SharedBridgeProxy, config.erc20BridgeProxy, l2StandardErc20BytecodeHash, @@ -188,16 +255,78 @@ contract DeployL2Script is Script { }); } + // Deploy the ConsensusRegistry implementation and save its address into the config. + function deployConsensusRegistry() internal { + // ConsensusRegistry.sol doesn't have a constructor, just an initializer. + bytes memory constructorData = ""; + + config.consensusRegistryImplementation = Utils.deployThroughL1({ + bytecode: contracts.consensusRegistryBytecode, + constructorargs: constructorData, + create2salt: "", + l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, + factoryDeps: new bytes[](0), + chainId: config.chainId, + bridgehubAddress: config.bridgehubAddress, + l1SharedBridgeProxy: config.l1SharedBridgeProxy + }); + } + + function deployMulticall3() internal { + // Multicall3 doesn't have a constructor. + bytes memory constructorData = ""; + + config.multicall3 = Utils.deployThroughL1({ + bytecode: contracts.multicall3Bytecode, + constructorargs: constructorData, + create2salt: "", + l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, + factoryDeps: new bytes[](0), + chainId: config.chainId, + bridgehubAddress: config.bridgehubAddress, + l1SharedBridgeProxy: config.l1SharedBridgeProxy + }); + } + + // Deploy a transparent upgradable proxy for the already deployed consensus registry + // implementation and save its address into the config. + function deployConsensusRegistryProxy() internal { + // Admin for the proxy + address l2GovernorAddress = AddressAliasHelper.applyL1ToL2Alias(config.governance); + + // Call ConsensusRegistry::initialize with the initial owner. + // solhint-disable-next-line func-named-parameters + bytes memory proxyInitializationParams = abi.encodeWithSignature( + "initialize(address)", + config.consensusRegistryOwner + ); + + bytes memory consensusRegistryProxyConstructorData = abi.encode( + config.consensusRegistryImplementation, // _logic + l2GovernorAddress, // admin_ + proxyInitializationParams // _data + ); + + config.consensusRegistryProxy = Utils.deployThroughL1({ + bytecode: contracts.consensusRegistryProxyBytecode, + constructorargs: consensusRegistryProxyConstructorData, + create2salt: "", + l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, + factoryDeps: new bytes[](0), + chainId: config.chainId, + bridgehubAddress: config.bridgehubAddress, + l1SharedBridgeProxy: config.l1SharedBridgeProxy + }); + } + function initializeChain() internal { L1SharedBridge bridge = L1SharedBridge(config.l1SharedBridgeProxy); - Utils.executeUpgrade({ - _governor: bridge.owner(), - _salt: bytes32(0), + Utils.chainAdminMulticall({ + _chainAdmin: bridge.admin(), _target: config.l1SharedBridgeProxy, _data: abi.encodeCall(bridge.initializeChainGovernance, (config.chainId, config.l2SharedBridgeProxy)), - _value: 0, - _delay: 0 + _value: 0 }); } } diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index e0039b969..bbc01226d 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -7,8 +7,7 @@ import {Script, console2 as console} from "forge-std/Script.sol"; import {Vm} from "forge-std/Vm.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; -import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; +import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; import {Governance} from "contracts/governance/Governance.sol"; @@ -119,20 +118,17 @@ contract RegisterHyperchainScript is Script { } function registerTokenOnBridgehub() internal { - IBridgehub bridgehub = IBridgehub(config.bridgehub); - Ownable ownable = Ownable(config.bridgehub); + Bridgehub bridgehub = Bridgehub(config.bridgehub); if (bridgehub.tokenIsRegistered(config.baseToken)) { console.log("Token already registered on Bridgehub"); } else { bytes memory data = abi.encodeCall(bridgehub.addToken, (config.baseToken)); - Utils.executeUpgrade({ - _governor: ownable.owner(), - _salt: bytes32(config.bridgehubCreateNewChainSalt), + Utils.chainAdminMulticall({ + _chainAdmin: bridgehub.admin(), _target: config.bridgehub, _data: data, - _value: 0, - _delay: 0 + _value: 0 }); console.log("Token registered on Bridgehub"); } @@ -157,8 +153,7 @@ contract RegisterHyperchainScript is Script { } function registerHyperchain() internal { - IBridgehub bridgehub = IBridgehub(config.bridgehub); - Ownable ownable = Ownable(config.bridgehub); + Bridgehub bridgehub = Bridgehub(config.bridgehub); vm.recordLogs(); bytes memory data = abi.encodeCall( @@ -173,14 +168,7 @@ contract RegisterHyperchainScript is Script { ) ); - Utils.executeUpgrade({ - _governor: ownable.owner(), - _salt: bytes32(config.bridgehubCreateNewChainSalt), - _target: config.bridgehub, - _data: data, - _value: 0, - _delay: 0 - }); + Utils.chainAdminMulticall({_chainAdmin: bridgehub.admin(), _target: config.bridgehub, _data: data, _value: 0}); console.log("Hyperchain registered"); // Get new diamond proxy address from emitted events diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index 17449da7e..fa2bb194c 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -12,6 +12,7 @@ import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; +import {IChainAdmin} from "contracts/governance/IChainAdmin.sol"; library Utils { // Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. @@ -306,6 +307,15 @@ library Utils { return bytecode; } + function chainAdminMulticall(address _chainAdmin, address _target, bytes memory _data, uint256 _value) internal { + IChainAdmin chainAdmin = IChainAdmin(_chainAdmin); + + IChainAdmin.Call[] memory calls = new IChainAdmin.Call[](1); + calls[0] = IChainAdmin.Call({target: _target, value: _value, data: _data}); + vm.broadcast(); + chainAdmin.multicall(calls, true); + } + function executeUpgrade( address _governor, bytes32 _salt, diff --git a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol new file mode 100644 index 000000000..e178824b1 --- /dev/null +++ b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; +import {Utils} from "./../Utils.sol"; +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {DummyL1ERC20Bridge} from "contracts/dev-contracts/DummyL1ERC20Bridge.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; + +/// This scripts is only for developer +contract SetupLegacyBridge is Script { + using stdToml for string; + + Config internal config; + Addresses internal addresses; + + struct Config { + uint256 chainId; + address l2SharedBridgeAddress; + bytes32 create2FactorySalt; + } + + struct Addresses { + address create2FactoryAddr; + address bridgehub; + address diamondProxy; + address sharedBridgeProxy; + address transparentProxyAdmin; + address erc20BridgeProxy; + address tokenWethAddress; + address erc20BridgeProxyImpl; + address sharedBridgeProxyImpl; + } + + function run() public { + initializeConfig(); + deploySharedBridgeImplementation(); + upgradeImplementation(addresses.sharedBridgeProxy, addresses.sharedBridgeProxyImpl); + deployDummyErc20Bridge(); + upgradeImplementation(addresses.erc20BridgeProxy, addresses.erc20BridgeProxyImpl); + setParamsForDummyBridge(); + } + + function initializeConfig() internal { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-config/setup-legacy-bridge.toml"); + string memory toml = vm.readFile(path); + + addresses.bridgehub = toml.readAddress("$.bridgehub"); + addresses.diamondProxy = toml.readAddress("$.diamond_proxy"); + addresses.sharedBridgeProxy = toml.readAddress("$.shared_bridge_proxy"); + addresses.transparentProxyAdmin = toml.readAddress("$.transparent_proxy_admin"); + addresses.erc20BridgeProxy = toml.readAddress("$.erc20bridge_proxy"); + addresses.tokenWethAddress = toml.readAddress("$.token_weth_address"); + addresses.create2FactoryAddr = toml.readAddress("$.create2factory_addr"); + config.chainId = toml.readUint("$.chain_id"); + config.l2SharedBridgeAddress = toml.readAddress("$.l2shared_bridge_address"); + config.create2FactorySalt = toml.readBytes32("$.create2factory_salt"); + } + + // We need to deploy new shared bridge for changing chain id and diamond proxy address + function deploySharedBridgeImplementation() internal { + bytes memory bytecode = abi.encodePacked( + type(L1SharedBridge).creationCode, + // solhint-disable-next-line func-named-parameters + abi.encode(addresses.tokenWethAddress, addresses.bridgehub, config.chainId, addresses.diamondProxy) + ); + + address contractAddress = deployViaCreate2(bytecode); + addresses.sharedBridgeProxyImpl = contractAddress; + } + + function deployDummyErc20Bridge() internal { + bytes memory bytecode = abi.encodePacked( + type(DummyL1ERC20Bridge).creationCode, + // solhint-disable-next-line func-named-parameters + abi.encode(addresses.sharedBridgeProxy) + ); + address contractAddress = deployViaCreate2(bytecode); + addresses.erc20BridgeProxyImpl = contractAddress; + } + + function upgradeImplementation(address proxy, address implementation) internal { + bytes memory proxyAdminUpgradeData = abi.encodeCall( + ProxyAdmin.upgrade, + (ITransparentUpgradeableProxy(proxy), implementation) + ); + ProxyAdmin _proxyAdmin = ProxyAdmin(addresses.transparentProxyAdmin); + address governance = _proxyAdmin.owner(); + + Utils.executeUpgrade({ + _governor: address(governance), + _salt: bytes32(0), + _target: address(addresses.transparentProxyAdmin), + _data: proxyAdminUpgradeData, + _value: 0, + _delay: 0 + }); + } + + function setParamsForDummyBridge() internal { + (address l2TokenBeacon, bytes32 l2TokenBeaconHash) = calculateTokenBeaconAddress(); + DummyL1ERC20Bridge bridge = DummyL1ERC20Bridge(addresses.erc20BridgeProxy); + vm.broadcast(); + bridge.setValues(config.l2SharedBridgeAddress, l2TokenBeacon, l2TokenBeaconHash); + } + + function calculateTokenBeaconAddress() + internal + returns (address tokenBeaconAddress, bytes32 tokenBeaconBytecodeHash) + { + bytes memory l2StandardTokenCode = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" + ); + (address l2StandardToken, ) = calculateL2Create2Address( + config.l2SharedBridgeAddress, + l2StandardTokenCode, + bytes32(0), + "" + ); + + bytes memory beaconProxy = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" + ); + tokenBeaconBytecodeHash = L2ContractHelper.hashL2Bytecode(beaconProxy); + + bytes memory upgradableBeacon = Utils.readHardhatBytecode( + "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" + ); + + (tokenBeaconAddress, ) = calculateL2Create2Address( + config.l2SharedBridgeAddress, + upgradableBeacon, + bytes32(0), + abi.encode(l2StandardToken) + ); + } + + function calculateL2Create2Address( + address sender, + bytes memory bytecode, + bytes32 create2salt, + bytes memory constructorargs + ) internal returns (address create2Address, bytes32 bytecodeHash) { + bytecodeHash = L2ContractHelper.hashL2Bytecode(bytecode); + + create2Address = L2ContractHelper.computeCreate2Address( + sender, + create2salt, + bytecodeHash, + keccak256(constructorargs) + ); + } + + function deployViaCreate2(bytes memory _bytecode) internal returns (address) { + return Utils.deployViaCreate2(_bytecode, config.create2FactorySalt, addresses.create2FactoryAddr); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol index b454a5299..43826e6ac 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol @@ -339,16 +339,13 @@ contract ExperimentalBridgeTest is Test { bridgeHub.addToken(randomAddress); } - function test_addToken_cannotBeCalledByRandomAddress( - address randomAddress, - address randomCaller, - uint256 randomValue - ) public useRandomToken(randomValue) { - if (randomCaller != bridgeOwner) { - vm.prank(randomCaller); - vm.expectRevert(bytes("Ownable: caller is not the owner")); - bridgeHub.addToken(randomAddress); - } + function test_addToken_cannotBeCalledByRandomAddress(address randomAddress, address randomCaller) public { + vm.assume(randomCaller != bridgeOwner); + vm.assume(randomCaller != bridgeHub.admin()); + + vm.prank(randomCaller); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); + bridgeHub.addToken(randomAddress); assertTrue(!bridgeHub.tokenIsRegistered(randomAddress), "This random address is not registered as a token"); diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeAdmin.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeAdmin.t.sol new file mode 100644 index 000000000..af97e3ed2 --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeAdmin.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {L1SharedBridgeTest} from "./_L1SharedBridge_Shared.t.sol"; + +/// We are testing all the specified revert and require cases. +contract L1SharedBridgeAdminTest is L1SharedBridgeTest { + uint256 internal randomChainId = 123456; + + function testAdminCanInitializeChainGovernance() public { + address randomL2Bridge = makeAddr("randomL2Bridge"); + + vm.prank(admin); + sharedBridge.initializeChainGovernance(randomChainId, randomL2Bridge); + + assertEq(sharedBridge.l2BridgeAddress(randomChainId), randomL2Bridge); + } + + function testAdminCanNotReinitializeChainGovernance() public { + address randomNewBridge = makeAddr("randomNewBridge"); + + vm.expectRevert("Ownable: caller is not the owner"); + vm.prank(admin); + sharedBridge.reinitializeChainGovernance(randomChainId, randomNewBridge); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol index 3c9272b46..63eb02aca 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol @@ -22,7 +22,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { vm.expectRevert(ZeroAddress.selector); new TransparentUpgradeableProxy( address(sharedBridgeImpl), - admin, + proxyAdmin, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector(L1SharedBridge.initialize.selector, address(0), eraPostUpgradeFirstBatch) ); @@ -59,7 +59,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { function test_bridgehubDeposit_Eth_l2BridgeNotDeployed() public { vm.prank(owner); - sharedBridge.initializeChainGovernance(chainId, address(0)); + sharedBridge.reinitializeChainGovernance(chainId, address(0)); vm.deal(bridgehubAddress, amount); vm.prank(bridgehubAddress); vm.mockCall( @@ -544,7 +544,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { address refundRecipient = address(0); vm.prank(owner); - sharedBridge.initializeChainGovernance(eraChainId, address(0)); + sharedBridge.reinitializeChainGovernance(eraChainId, address(0)); vm.expectRevert(abi.encodeWithSelector(L2BridgeNotSet.selector, eraChainId)); vm.prank(l1ERC20BridgeAddress); diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol index 0b917efca..1b785ae84 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol @@ -69,6 +69,7 @@ contract L1SharedBridgeTest is Test { address owner; address admin; + address proxyAdmin; address zkSync; address alice; address bob; @@ -90,6 +91,7 @@ contract L1SharedBridgeTest is Test { function setUp() public { owner = makeAddr("owner"); admin = makeAddr("admin"); + proxyAdmin = makeAddr("proxyAdmin"); // zkSync = makeAddr("zkSync"); bridgehubAddress = makeAddr("bridgehub"); alice = makeAddr("alice"); @@ -119,7 +121,7 @@ contract L1SharedBridgeTest is Test { }); TransparentUpgradeableProxy sharedBridgeProxy = new TransparentUpgradeableProxy( address(sharedBridgeImpl), - admin, + proxyAdmin, abi.encodeWithSelector(L1SharedBridge.initialize.selector, owner) ); sharedBridge = L1SharedBridge(payable(sharedBridgeProxy)); @@ -135,6 +137,10 @@ contract L1SharedBridgeTest is Test { sharedBridge.initializeChainGovernance(chainId, l2SharedBridge); vm.prank(owner); sharedBridge.initializeChainGovernance(eraChainId, l2SharedBridge); + vm.prank(owner); + sharedBridge.setPendingAdmin(admin); + vm.prank(admin); + sharedBridge.acceptAdmin(); } function _setSharedBridgeDepositHappened(uint256 _chainId, bytes32 _txHash, bytes32 _txDataHash) internal { diff --git a/l2-contracts/contracts/ConsensusRegistry.sol b/l2-contracts/contracts/ConsensusRegistry.sol new file mode 100644 index 000000000..de5af6340 --- /dev/null +++ b/l2-contracts/contracts/ConsensusRegistry.sol @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable-v4/proxy/utils/Initializable.sol"; +import {IConsensusRegistry} from "./interfaces/IConsensusRegistry.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @title ConsensusRegistry +/// @dev Manages consensus nodes and committees for the L2 consensus protocol, +/// owned by Matter Labs Multisig. Nodes act as both validators and attesters, +/// each playing a distinct role in the consensus process. This contract facilitates +/// the rotation of validator and attester committees, which represent a subset of nodes +/// expected to actively participate in the consensus process during a specific time window. +/// @dev Designed for use with a proxy for upgradability. +contract ConsensusRegistry is IConsensusRegistry, Initializable, Ownable2StepUpgradeable { + /// @dev An array to keep track of node owners. + address[] public nodeOwners; + /// @dev A mapping of node owners => nodes. + mapping(address => Node) public nodes; + /// @dev A mapping for enabling efficient lookups when checking whether a given attester public key exists. + mapping(bytes32 => bool) public attesterPubKeyHashes; + /// @dev A mapping for enabling efficient lookups when checking whether a given validator public key exists. + mapping(bytes32 => bool) public validatorPubKeyHashes; + /// @dev Counter that increments with each new commit to the attester committee. + uint32 public attestersCommit; + /// @dev Counter that increments with each new commit to the validator committee. + uint32 public validatorsCommit; + + modifier onlyOwnerOrNodeOwner(address _nodeOwner) { + if (owner() != msg.sender && _nodeOwner != msg.sender) { + revert UnauthorizedOnlyOwnerOrNodeOwner(); + } + _; + } + + function initialize(address _initialOwner) external initializer { + if (_initialOwner == address(0)) { + revert InvalidInputNodeOwnerAddress(); + } + _transferOwnership(_initialOwner); + } + + /// @notice Adds a new node to the registry. + /// @dev Fails if node owner already exists. + /// @dev Fails if a validator/attester with the same public key already exists. + /// @param _nodeOwner The address of the new node's owner. + /// @param _validatorWeight The voting weight of the validator. + /// @param _validatorPubKey The BLS12-381 public key of the validator. + /// @param _validatorPoP The proof-of-possession (PoP) of the validator's public key. + /// @param _attesterWeight The voting weight of the attester. + /// @param _attesterPubKey The ECDSA public key of the attester. + function add( + address _nodeOwner, + uint32 _validatorWeight, + BLS12_381PublicKey calldata _validatorPubKey, + BLS12_381Signature calldata _validatorPoP, + uint32 _attesterWeight, + Secp256k1PublicKey calldata _attesterPubKey + ) external onlyOwner { + // Verify input. + _verifyInputAddress(_nodeOwner); + _verifyInputBLS12_381PublicKey(_validatorPubKey); + _verifyInputBLS12_381Signature(_validatorPoP); + _verifyInputSecp256k1PublicKey(_attesterPubKey); + + // Verify storage. + _verifyNodeOwnerDoesNotExist(_nodeOwner); + bytes32 attesterPubKeyHash = _hashAttesterPubKey(_attesterPubKey); + _verifyAttesterPubKeyDoesNotExist(attesterPubKeyHash); + bytes32 validatorPubKeyHash = _hashValidatorPubKey(_validatorPubKey); + _verifyValidatorPubKeyDoesNotExist(validatorPubKeyHash); + + uint32 nodeOwnerIdx = uint32(nodeOwners.length); + nodeOwners.push(_nodeOwner); + nodes[_nodeOwner] = Node({ + attesterLatest: AttesterAttr({ + active: true, + removed: false, + weight: _attesterWeight, + pubKey: _attesterPubKey + }), + attesterSnapshot: AttesterAttr({ + active: false, + removed: false, + weight: 0, + pubKey: Secp256k1PublicKey({tag: bytes1(0), x: bytes32(0)}) + }), + attesterLastUpdateCommit: attestersCommit, + validatorLatest: ValidatorAttr({ + active: true, + removed: false, + weight: _validatorWeight, + pubKey: _validatorPubKey, + proofOfPossession: _validatorPoP + }), + validatorSnapshot: ValidatorAttr({ + active: false, + removed: false, + weight: 0, + pubKey: BLS12_381PublicKey({a: bytes32(0), b: bytes32(0), c: bytes32(0)}), + proofOfPossession: BLS12_381Signature({a: bytes32(0), b: bytes16(0)}) + }), + validatorLastUpdateCommit: validatorsCommit, + nodeOwnerIdx: nodeOwnerIdx + }); + attesterPubKeyHashes[attesterPubKeyHash] = true; + validatorPubKeyHashes[validatorPubKeyHash] = true; + + emit NodeAdded({ + nodeOwner: _nodeOwner, + validatorWeight: _validatorWeight, + validatorPubKey: _validatorPubKey, + validatorPoP: _validatorPoP, + attesterWeight: _attesterWeight, + attesterPubKey: _attesterPubKey + }); + } + + /// @notice Deactivates a node, preventing it from participating in committees. + /// @dev Only callable by the contract owner or the node owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner to be inactivated. + function deactivate(address _nodeOwner) external onlyOwnerOrNodeOwner(_nodeOwner) { + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + _ensureAttesterSnapshot(node); + node.attesterLatest.active = false; + _ensureValidatorSnapshot(node); + node.validatorLatest.active = false; + + emit NodeDeactivated(_nodeOwner); + } + + /// @notice Activates a previously inactive node, allowing it to participate in committees. + /// @dev Only callable by the contract owner or the node owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner to be activated. + function activate(address _nodeOwner) external onlyOwnerOrNodeOwner(_nodeOwner) { + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + _ensureAttesterSnapshot(node); + node.attesterLatest.active = true; + _ensureValidatorSnapshot(node); + node.validatorLatest.active = true; + + emit NodeActivated(_nodeOwner); + } + + /// @notice Removes a node from the registry. + /// @dev Only callable by the contract owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner to be removed. + function remove(address _nodeOwner) external onlyOwner { + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + _ensureAttesterSnapshot(node); + node.attesterLatest.removed = true; + _ensureValidatorSnapshot(node); + node.validatorLatest.removed = true; + + emit NodeRemoved(_nodeOwner); + } + + /// @notice Changes the validator weight of a node in the registry. + /// @dev Only callable by the contract owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner whose validator weight will be changed. + /// @param _weight The new validator weight to assign to the node. + function changeValidatorWeight(address _nodeOwner, uint32 _weight) external onlyOwner { + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + _ensureValidatorSnapshot(node); + node.validatorLatest.weight = _weight; + + emit NodeValidatorWeightChanged(_nodeOwner, _weight); + } + + /// @notice Changes the attester weight of a node in the registry. + /// @dev Only callable by the contract owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner whose attester weight will be changed. + /// @param _weight The new attester weight to assign to the node. + function changeAttesterWeight(address _nodeOwner, uint32 _weight) external onlyOwner { + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + _ensureAttesterSnapshot(node); + node.attesterLatest.weight = _weight; + + emit NodeAttesterWeightChanged(_nodeOwner, _weight); + } + + /// @notice Changes the validator's public key and proof-of-possession in the registry. + /// @dev Only callable by the contract owner or the node owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner whose validator key and PoP will be changed. + /// @param _pubKey The new BLS12-381 public key to assign to the node's validator. + /// @param _pop The new proof-of-possession (PoP) to assign to the node's validator. + function changeValidatorKey( + address _nodeOwner, + BLS12_381PublicKey calldata _pubKey, + BLS12_381Signature calldata _pop + ) external onlyOwnerOrNodeOwner(_nodeOwner) { + _verifyInputBLS12_381PublicKey(_pubKey); + _verifyInputBLS12_381Signature(_pop); + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + bytes32 prevHash = _hashValidatorPubKey(node.validatorLatest.pubKey); + delete validatorPubKeyHashes[prevHash]; + bytes32 newHash = _hashValidatorPubKey(_pubKey); + _verifyValidatorPubKeyDoesNotExist(newHash); + validatorPubKeyHashes[newHash] = true; + _ensureValidatorSnapshot(node); + node.validatorLatest.pubKey = _pubKey; + node.validatorLatest.proofOfPossession = _pop; + + emit NodeValidatorKeyChanged(_nodeOwner, _pubKey, _pop); + } + + /// @notice Changes the attester's public key of a node in the registry. + /// @dev Only callable by the contract owner or the node owner. + /// @dev Verifies that the node owner exists in the registry. + /// @param _nodeOwner The address of the node's owner whose attester public key will be changed. + /// @param _pubKey The new ECDSA public key to assign to the node's attester. + function changeAttesterKey( + address _nodeOwner, + Secp256k1PublicKey calldata _pubKey + ) external onlyOwnerOrNodeOwner(_nodeOwner) { + _verifyInputSecp256k1PublicKey(_pubKey); + _verifyNodeOwnerExists(_nodeOwner); + (Node storage node, bool deleted) = _getNodeAndDeleteIfRequired(_nodeOwner); + if (deleted) { + return; + } + + bytes32 prevHash = _hashAttesterPubKey(node.attesterLatest.pubKey); + delete attesterPubKeyHashes[prevHash]; + bytes32 newHash = _hashAttesterPubKey(_pubKey); + _verifyAttesterPubKeyDoesNotExist(newHash); + attesterPubKeyHashes[newHash] = true; + + _ensureAttesterSnapshot(node); + node.attesterLatest.pubKey = _pubKey; + + emit NodeAttesterKeyChanged(_nodeOwner, _pubKey); + } + + /// @notice Adds a new commit to the attester committee. + /// @dev Implicitly updates the attester committee by affecting readers based on the current state of a node's attester attributes: + /// - If "attestersCommit" > "node.attesterLastUpdateCommit", read "node.attesterLatest". + /// - If "attestersCommit" == "node.attesterLastUpdateCommit", read "node.attesterSnapshot". + /// @dev Only callable by the contract owner. + function commitAttesterCommittee() external onlyOwner { + ++attestersCommit; + + emit AttestersCommitted(attestersCommit); + } + + /// @notice Adds a new commit to the validator committee. + /// @dev Implicitly updates the validator committee by affecting readers based on the current state of a node's validator attributes: + /// - If "validatorsCommit" > "node.validatorLastUpdateCommit", read "node.validatorLatest". + /// - If "validatorsCommit" == "node.validatorLastUpdateCommit", read "node.validatorSnapshot". + /// @dev Only callable by the contract owner. + function commitValidatorCommittee() external onlyOwner { + ++validatorsCommit; + + emit ValidatorsCommitted(validatorsCommit); + } + + /// @notice Returns an array of `AttesterAttr` structs representing the current attester committee. + /// @dev Collects active and non-removed attesters based on the latest commit to the committee. + function getAttesterCommittee() public view returns (CommitteeAttester[] memory) { + uint256 len = nodeOwners.length; + CommitteeAttester[] memory committee = new CommitteeAttester[](len); + uint256 count = 0; + + for (uint256 i = 0; i < len; ++i) { + Node storage node = nodes[nodeOwners[i]]; + AttesterAttr memory attester = attestersCommit > node.attesterLastUpdateCommit + ? node.attesterLatest + : node.attesterSnapshot; + if (attester.active && !attester.removed) { + committee[count] = CommitteeAttester({weight: attester.weight, pubKey: attester.pubKey}); + ++count; + } + } + + // Resize the array. + assembly { + mstore(committee, count) + } + return committee; + } + + /// @notice Returns an array of `ValidatorAttr` structs representing the current attester committee. + /// @dev Collects active and non-removed validators based on the latest commit to the committee. + function getValidatorCommittee() public view returns (CommitteeValidator[] memory) { + uint256 len = nodeOwners.length; + CommitteeValidator[] memory committee = new CommitteeValidator[](len); + uint256 count = 0; + + for (uint256 i = 0; i < len; ++i) { + Node storage node = nodes[nodeOwners[i]]; + ValidatorAttr memory validator = validatorsCommit > node.validatorLastUpdateCommit + ? node.validatorLatest + : node.validatorSnapshot; + if (validator.active && !validator.removed) { + committee[count] = CommitteeValidator({ + weight: validator.weight, + pubKey: validator.pubKey, + proofOfPossession: validator.proofOfPossession + }); + ++count; + } + } + + // Resize the array. + assembly { + mstore(committee, count) + } + return committee; + } + + function numNodes() public view returns (uint256) { + return nodeOwners.length; + } + + function _getNodeAndDeleteIfRequired(address _nodeOwner) private returns (Node storage, bool) { + Node storage node = nodes[_nodeOwner]; + bool pendingDeletion = _isNodePendingDeletion(node); + if (pendingDeletion) { + _deleteNode(_nodeOwner, node); + } + return (node, pendingDeletion); + } + + function _isNodePendingDeletion(Node storage _node) private returns (bool) { + bool attesterRemoved = (attestersCommit > _node.attesterLastUpdateCommit) + ? _node.attesterLatest.removed + : _node.attesterSnapshot.removed; + bool validatorRemoved = (validatorsCommit > _node.validatorLastUpdateCommit) + ? _node.validatorLatest.removed + : _node.validatorSnapshot.removed; + return attesterRemoved && validatorRemoved; + } + + function _deleteNode(address _nodeOwner, Node storage _node) private { + // Delete from array by swapping the last node owner (gas-efficient, not preserving order). + address lastNodeOwner = nodeOwners[nodeOwners.length - 1]; + nodeOwners[_node.nodeOwnerIdx] = lastNodeOwner; + nodeOwners.pop(); + // Update the node owned by the last node owner. + nodes[lastNodeOwner].nodeOwnerIdx = _node.nodeOwnerIdx; + + // Delete from the remaining mapping. + delete attesterPubKeyHashes[_hashAttesterPubKey(_node.attesterLatest.pubKey)]; + delete validatorPubKeyHashes[_hashValidatorPubKey(_node.validatorLatest.pubKey)]; + delete nodes[_nodeOwner]; + + emit NodeDeleted(_nodeOwner); + } + + function _ensureAttesterSnapshot(Node storage _node) private { + if (_node.attesterLastUpdateCommit < attestersCommit) { + _node.attesterSnapshot = _node.attesterLatest; + _node.attesterLastUpdateCommit = attestersCommit; + } + } + + function _ensureValidatorSnapshot(Node storage _node) private { + if (_node.validatorLastUpdateCommit < validatorsCommit) { + _node.validatorSnapshot = _node.validatorLatest; + _node.validatorLastUpdateCommit = validatorsCommit; + } + } + + function _isNodeOwnerExists(address _nodeOwner) private view returns (bool) { + BLS12_381PublicKey storage pubKey = nodes[_nodeOwner].validatorLatest.pubKey; + if (pubKey.a == bytes32(0) && pubKey.b == bytes32(0) && pubKey.c == bytes32(0)) { + return false; + } + return true; + } + + function _verifyNodeOwnerExists(address _nodeOwner) private view { + if (!_isNodeOwnerExists(_nodeOwner)) { + revert NodeOwnerDoesNotExist(); + } + } + + function _verifyNodeOwnerDoesNotExist(address _nodeOwner) private view { + if (_isNodeOwnerExists(_nodeOwner)) { + revert NodeOwnerExists(); + } + } + + function _hashAttesterPubKey(Secp256k1PublicKey storage _pubKey) private view returns (bytes32) { + return keccak256(abi.encode(_pubKey.tag, _pubKey.x)); + } + + function _hashAttesterPubKey(Secp256k1PublicKey calldata _pubKey) private pure returns (bytes32) { + return keccak256(abi.encode(_pubKey.tag, _pubKey.x)); + } + + function _hashValidatorPubKey(BLS12_381PublicKey storage _pubKey) private view returns (bytes32) { + return keccak256(abi.encode(_pubKey.a, _pubKey.b, _pubKey.c)); + } + + function _hashValidatorPubKey(BLS12_381PublicKey calldata _pubKey) private pure returns (bytes32) { + return keccak256(abi.encode(_pubKey.a, _pubKey.b, _pubKey.c)); + } + + function _verifyInputAddress(address _nodeOwner) private pure { + if (_nodeOwner == address(0)) { + revert InvalidInputNodeOwnerAddress(); + } + } + + function _verifyAttesterPubKeyDoesNotExist(bytes32 _hash) private view { + if (attesterPubKeyHashes[_hash]) { + revert AttesterPubKeyExists(); + } + } + + function _verifyValidatorPubKeyDoesNotExist(bytes32 _hash) private { + if (validatorPubKeyHashes[_hash]) { + revert ValidatorPubKeyExists(); + } + } + + function _verifyInputBLS12_381PublicKey(BLS12_381PublicKey calldata _pubKey) private pure { + if (_isEmptyBLS12_381PublicKey(_pubKey)) { + revert InvalidInputBLS12_381PublicKey(); + } + } + + function _verifyInputBLS12_381Signature(BLS12_381Signature calldata _pop) private pure { + if (_isEmptyBLS12_381Signature(_pop)) { + revert InvalidInputBLS12_381Signature(); + } + } + + function _verifyInputSecp256k1PublicKey(Secp256k1PublicKey calldata _pubKey) private pure { + if (_isEmptySecp256k1PublicKey(_pubKey)) { + revert InvalidInputSecp256k1PublicKey(); + } + } + + function _isEmptyBLS12_381PublicKey(BLS12_381PublicKey calldata _pubKey) private pure returns (bool) { + return _pubKey.a == bytes32(0) && _pubKey.b == bytes32(0) && _pubKey.c == bytes32(0); + } + + function _isEmptyBLS12_381Signature(BLS12_381Signature calldata _pop) private pure returns (bool) { + return _pop.a == bytes32(0) && _pop.b == bytes16(0); + } + + function _isEmptySecp256k1PublicKey(Secp256k1PublicKey calldata _pubKey) private pure returns (bool) { + return _pubKey.tag == bytes1(0) && _pubKey.x == bytes32(0); + } +} diff --git a/l2-contracts/contracts/dev-contracts/Multicall3.sol b/l2-contracts/contracts/dev-contracts/Multicall3.sol new file mode 100644 index 000000000..aaa8b8012 --- /dev/null +++ b/l2-contracts/contracts/dev-contracts/Multicall3.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +/// @title Multicall3 +/// @notice Aggregate results from multiple function calls +/// @dev Multicall & Multicall2 backwards-compatible +/// @dev Aggregate methods are marked `payable` to save 24 gas per call +/// @author Michael Elliot +/// @author Joshua Levine +/// @author Nick Johnson +/// @author Andreas Bigger +/// @author Matt Solomon +contract Multicall3 { + // add this to be excluded from coverage report + function test() internal virtual {} + + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + /// @notice Backwards-compatible call aggregation with Multicall + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return returnData An array of bytes containing the responses + function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) { + blockNumber = block.number; + uint256 length = calls.length; + returnData = new bytes[](length); + Call calldata call; + for (uint256 i = 0; i < length; ) { + bool success; + call = calls[i]; + (success, returnData[i]) = call.target.call(call.callData); + require(success, "Multicall3: call failed"); + unchecked { + ++i; + } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls without requiring success + /// @param requireSuccess If true, require all calls to succeed + /// @param calls An array of Call structs + /// @return returnData An array of Result structs + function tryAggregate( + bool requireSuccess, + Call[] calldata calls + ) public payable returns (Result[] memory returnData) { + uint256 length = calls.length; + returnData = new Result[](length); + Call calldata call; + for (uint256 i = 0; i < length; ) { + Result memory result = returnData[i]; + call = calls[i]; + (result.success, result.returnData) = call.target.call(call.callData); + if (requireSuccess) require(result.success, "Multicall3: call failed"); + unchecked { + ++i; + } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function tryBlockAndAggregate( + bool requireSuccess, + Call[] calldata calls + ) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { + blockNumber = block.number; + blockHash = blockhash(block.number); + returnData = tryAggregate(requireSuccess, calls); + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function blockAndAggregate( + Call[] calldata calls + ) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { + (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); + } + + /// @notice Aggregate calls, ensuring each returns success if required + /// @param calls An array of Call3 structs + /// @return returnData An array of Result structs + function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 length = calls.length; + returnData = new Result[](length); + Call3 calldata calli; + for (uint256 i = 0; i < length; ) { + Result memory result = returnData[i]; + calli = calls[i]; + (result.success, result.returnData) = calli.target.call(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x64) + } + } + unchecked { + ++i; + } + } + } + + /// @notice Aggregate calls with a msg value + /// @notice Reverts if msg.value is less than the sum of the call values + /// @param calls An array of Call3Value structs + /// @return returnData An array of Result structs + function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 valAccumulator; + uint256 length = calls.length; + returnData = new Result[](length); + Call3Value calldata calli; + for (uint256 i = 0; i < length; ) { + Result memory result = returnData[i]; + calli = calls[i]; + uint256 val = calli.value; + // Humanity will be a Type V Kardashev Civilization before this overflows - andreas + // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256 + unchecked { + valAccumulator += val; + } + (result.success, result.returnData) = calli.target.call{value: val}(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x84) + } + } + unchecked { + ++i; + } + } + // Finally, make sure the msg.value = SUM(call[0...i].value) + require(msg.value == valAccumulator, "Multicall3: value mismatch"); + } + + /// @notice Returns the block hash for the given block number + /// @param blockNumber The block number + function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { + blockHash = blockhash(blockNumber); + } + + /// @notice Returns the block number + function getBlockNumber() public view returns (uint256 blockNumber) { + blockNumber = block.number; + } + + /// @notice Returns the block coinbase + function getCurrentBlockCoinbase() public view returns (address coinbase) { + coinbase = block.coinbase; + } + + /// @notice Returns the block difficulty + function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { + difficulty = block.prevrandao; + } + + /// @notice Returns the block gas limit + function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { + gaslimit = block.gaslimit; + } + + /// @notice Returns the block timestamp + function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { + timestamp = block.timestamp; + } + + /// @notice Returns the (ETH) balance of a given address + function getEthBalance(address addr) public view returns (uint256 balance) { + balance = addr.balance; + } + + /// @notice Returns the block hash of the last block + function getLastBlockHash() public view returns (bytes32 blockHash) { + unchecked { + blockHash = blockhash(block.number - 1); + } + } + + /// @notice Gets the base fee of the given block + /// @notice Can revert if the BASEFEE opcode is not implemented by the given chain + function getBasefee() public view returns (uint256 basefee) { + basefee = block.basefee; + } + + /// @notice Returns the chain id + function getChainId() public view returns (uint256 chainid) { + chainid = block.chainid; + } +} diff --git a/l2-contracts/contracts/interfaces/IConsensusRegistry.sol b/l2-contracts/contracts/interfaces/IConsensusRegistry.sol new file mode 100644 index 000000000..34afc0abe --- /dev/null +++ b/l2-contracts/contracts/interfaces/IConsensusRegistry.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @title ConsensusRegistry contract interface +interface IConsensusRegistry { + /// @dev Represents a consensus node. + /// @param attesterLastUpdateCommit The latest `attestersCommit` where the node's attester attributes were updated. + /// @param attesterLatest Attester attributes to read if `node.attesterLastUpdateCommit` < `attestersCommit`. + /// @param attesterSnapshot Attester attributes to read if `node.attesterLastUpdateCommit` == `attestersCommit`. + /// @param validatorLastUpdateCommit The latest `validatorsCommit` where the node's validator attributes were updated. + /// @param validatorLatest Validator attributes to read if `node.validatorLastUpdateCommit` < `validatorsCommit`. + /// @param validatorSnapshot Validator attributes to read if `node.validatorLastUpdateCommit` == `validatorsCommit`. + /// @param nodeOwnerIdx Index of the node owner within the array of node owners. + struct Node { + uint32 attesterLastUpdateCommit; + uint32 validatorLastUpdateCommit; + uint32 nodeOwnerIdx; + AttesterAttr attesterLatest; + AttesterAttr attesterSnapshot; + ValidatorAttr validatorLatest; + ValidatorAttr validatorSnapshot; + } + + /// @dev Represents the attester attributes of a consensus node. + /// @param active A flag stating if the attester is active. + /// @param removed A flag stating if the attester has been removed (and is pending a deletion). + /// @param weight Attester's voting weight. + /// @param pubKey Attester's Secp256k1 public key. + struct AttesterAttr { + bool active; + bool removed; + uint32 weight; + Secp256k1PublicKey pubKey; + } + + /// @dev Represents an attester within a committee. + /// @param weight Attester's voting weight. + /// @param pubKey Attester's Secp256k1 public key. + struct CommitteeAttester { + uint32 weight; + Secp256k1PublicKey pubKey; + } + + /// @dev Represents the validator attributes of a consensus node. + /// @param active A flag stating if the validator is active. + /// @param removed A flag stating if the validator has been removed (and is pending a deletion). + /// @param weight Validator's voting weight. + /// @param pubKey Validator's BLS12-381 public key. + /// @param proofOfPossession Validator's Proof-of-possession (a signature over the public key). + struct ValidatorAttr { + bool active; + bool removed; + uint32 weight; + BLS12_381PublicKey pubKey; + BLS12_381Signature proofOfPossession; + } + + /// @dev Represents a validator within a committee. + /// @param weight Validator's voting weight. + /// @param pubKey Validator's BLS12-381 public key. + /// @param proofOfPossession Validator's Proof-of-possession (a signature over the public key). + struct CommitteeValidator { + uint32 weight; + BLS12_381PublicKey pubKey; + BLS12_381Signature proofOfPossession; + } + + /// @dev Represents BLS12_381 public key. + /// @param a First component of the BLS12-381 public key. + /// @param b Second component of the BLS12-381 public key. + /// @param c Third component of the BLS12-381 public key. + struct BLS12_381PublicKey { + bytes32 a; + bytes32 b; + bytes32 c; + } + + /// @dev Represents BLS12_381 signature. + /// @param a First component of the BLS12-381 signature. + /// @param b Second component of the BLS12-381 signature. + struct BLS12_381Signature { + bytes32 a; + bytes16 b; + } + + /// @dev Represents Secp256k1 public key. + /// @param tag Y-coordinate's even/odd indicator of the Secp256k1 public key. + /// @param x X-coordinate component of the Secp256k1 public key. + struct Secp256k1PublicKey { + bytes1 tag; + bytes32 x; + } + + error UnauthorizedOnlyOwnerOrNodeOwner(); + error NodeOwnerExists(); + error NodeOwnerDoesNotExist(); + error NodeOwnerNotFound(); + error ValidatorPubKeyExists(); + error AttesterPubKeyExists(); + error InvalidInputNodeOwnerAddress(); + error InvalidInputBLS12_381PublicKey(); + error InvalidInputBLS12_381Signature(); + error InvalidInputSecp256k1PublicKey(); + + event NodeAdded( + address indexed nodeOwner, + uint32 validatorWeight, + BLS12_381PublicKey validatorPubKey, + BLS12_381Signature validatorPoP, + uint32 attesterWeight, + Secp256k1PublicKey attesterPubKey + ); + event NodeDeactivated(address indexed nodeOwner); + event NodeActivated(address indexed nodeOwner); + event NodeRemoved(address indexed nodeOwner); + event NodeDeleted(address indexed nodeOwner); + event NodeValidatorWeightChanged(address indexed nodeOwner, uint32 newWeight); + event NodeAttesterWeightChanged(address indexed nodeOwner, uint32 newWeight); + event NodeValidatorKeyChanged(address indexed nodeOwner, BLS12_381PublicKey newPubKey, BLS12_381Signature newPoP); + event NodeAttesterKeyChanged(address indexed nodeOwner, Secp256k1PublicKey newPubKey); + event ValidatorsCommitted(uint32 commit); + event AttestersCommitted(uint32 commit); + + function add( + address _nodeOwner, + uint32 _validatorWeight, + BLS12_381PublicKey calldata _validatorPubKey, + BLS12_381Signature calldata _validatorPoP, + uint32 _attesterWeight, + Secp256k1PublicKey calldata _attesterPubKey + ) external; + + function deactivate(address _nodeOwner) external; + + function activate(address _nodeOwner) external; + + function remove(address _nodeOwner) external; + + function changeValidatorWeight(address _nodeOwner, uint32 _weight) external; + + function changeAttesterWeight(address _nodeOwner, uint32 _weight) external; + + function changeValidatorKey( + address _nodeOwner, + BLS12_381PublicKey calldata _pubKey, + BLS12_381Signature calldata _pop + ) external; + + function changeAttesterKey(address _nodeOwner, Secp256k1PublicKey calldata _pubKey) external; + + function commitAttesterCommittee() external; + + function commitValidatorCommittee() external; + + function getAttesterCommittee() external view returns (CommitteeAttester[] memory); + + function getValidatorCommittee() external view returns (CommitteeValidator[] memory); +} diff --git a/l2-contracts/package.json b/l2-contracts/package.json index 474a5a25a..fdaa06327 100644 --- a/l2-contracts/package.json +++ b/l2-contracts/package.json @@ -42,7 +42,8 @@ "deploy-l2-weth": "ts-node src/deploy-l2-weth.ts", "upgrade-bridge-contracts": "ts-node src/upgrade-bridge-impl.ts", "update-l2-erc20-metadata": "ts-node src/update-l2-erc20-metadata.ts", - "upgrade-consistency-checker": "ts-node src/upgrade-consistency-checker.ts" + "upgrade-consistency-checker": "ts-node src/upgrade-consistency-checker.ts", + "deploy-consensus-registry": "ts-node src/deploy-consensus-registry.ts" }, "dependencies": { "dotenv": "^16.0.3" diff --git a/l2-contracts/src/deploy-consensus-registry.ts b/l2-contracts/src/deploy-consensus-registry.ts new file mode 100644 index 000000000..ffbf903f9 --- /dev/null +++ b/l2-contracts/src/deploy-consensus-registry.ts @@ -0,0 +1,90 @@ +import { Command } from "commander"; +import { ethers } from "ethers"; +import { computeL2Create2Address, create2DeployFromL2 } from "./utils"; +import { Interface } from "ethers/lib/utils"; +import { ethTestConfig } from "./deploy-utils"; + +import * as hre from "hardhat"; +import { Provider, Wallet } from "zksync-ethers"; + +const I_TRANSPARENT_UPGRADEABLE_PROXY_ARTIFACT = hre.artifacts.readArtifactSync("ITransparentUpgradeableProxy"); +const TRANSPARENT_UPGRADEABLE_PROXY_ARTIFACT = hre.artifacts.readArtifactSync("TransparentUpgradeableProxy"); +const CONSENSUS_REGISTRY_ARTIFACT = hre.artifacts.readArtifactSync("ConsensusRegistry"); +const PROXY_ADMIN_ARTIFACT = hre.artifacts.readArtifactSync("ConsensusRegistry"); + +const CONSENSUS_REGISTRY_INTERFACE = new Interface(CONSENSUS_REGISTRY_ARTIFACT.abi); +const I_TRANSPARENT_UPGRADEABLE_PROXY_INTERFACE = new Interface(I_TRANSPARENT_UPGRADEABLE_PROXY_ARTIFACT.abi); + +// Script to deploy the consensus registry contract and output its address. +// Note, that this script expects that the L2 contracts have been compiled PRIOR +// to running this script. +async function main() { + const program = new Command(); + + program + .version("0.1.0") + .name("deploy-consensus-registry") + .description("Deploys the consensus registry contract to L2"); + + program.option("--private-key ").action(async (cmd) => { + const zksProvider = new Provider(process.env.API_WEB3_JSON_RPC_HTTP_URL); + const deployWallet = cmd.privateKey + ? new Wallet(cmd.privateKey, zksProvider) + : Wallet.fromMnemonic( + process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic, + "m/44'/60'/0'/0/1" + ).connect(zksProvider); + console.log(`Using deployer wallet: ${deployWallet.address}`); + + // Deploy Consensus Registry contract + const consensusRegistryImplementation = await computeL2Create2Address( + deployWallet, + CONSENSUS_REGISTRY_ARTIFACT.bytecode, + "0x", + ethers.constants.HashZero + ); + await create2DeployFromL2(deployWallet, CONSENSUS_REGISTRY_ARTIFACT.bytecode, "0x", ethers.constants.HashZero); + + // Deploy Proxy Admin contract + const proxyAdminContract = await computeL2Create2Address( + deployWallet, + PROXY_ADMIN_ARTIFACT.bytecode, + "0x", + ethers.constants.HashZero + ); + await create2DeployFromL2(deployWallet, PROXY_ADMIN_ARTIFACT.bytecode, "0x", ethers.constants.HashZero); + + const proxyInitializationParams = CONSENSUS_REGISTRY_INTERFACE.encodeFunctionData("initialize", [ + deployWallet.address, + ]); + const proxyConstructor = I_TRANSPARENT_UPGRADEABLE_PROXY_INTERFACE.encodeDeploy([ + consensusRegistryImplementation, + proxyAdminContract, + proxyInitializationParams, + ]); + + await create2DeployFromL2( + deployWallet, + TRANSPARENT_UPGRADEABLE_PROXY_ARTIFACT.bytecode, + proxyConstructor, + ethers.constants.HashZero + ); + + const address = computeL2Create2Address( + deployWallet, + TRANSPARENT_UPGRADEABLE_PROXY_ARTIFACT.bytecode, + proxyConstructor, + ethers.constants.HashZero + ); + console.log(`CONTRACTS_L2_CONSENSUS_REGISTRY_ADDR=${address}`); + }); + + await program.parseAsync(process.argv); +} + +main() + .then(() => process.exit(0)) + .catch((err) => { + console.error("Error:", err); + process.exit(1); + }); diff --git a/l2-contracts/src/utils.ts b/l2-contracts/src/utils.ts index c77817a0b..0a479a540 100644 --- a/l2-contracts/src/utils.ts +++ b/l2-contracts/src/utils.ts @@ -143,6 +143,27 @@ export async function create2DeployFromL1( ); } +export async function create2DeployFromL2( + wallet: ethers.Wallet, + bytecode: ethers.BytesLike, + constructor: ethers.BytesLike, + create2Salt: ethers.BytesLike, + extraFactoryDeps?: ethers.BytesLike[] +) { + const deployerSystemContracts = new Interface(artifacts.readArtifactSync("IContractDeployer").abi); + const bytecodeHash = hashL2Bytecode(bytecode); + const calldata = deployerSystemContracts.encodeFunctionData("create2", [create2Salt, bytecodeHash, constructor]); + + const factoryDeps = extraFactoryDeps ? [bytecode, ...extraFactoryDeps] : [bytecode]; + return await wallet.call({ + to: DEPLOYER_SYSTEM_CONTRACT_ADDRESS, + data: calldata, + customData: { + factoryDeps, + }, + }); +} + export async function publishBytecodeFromL1( chainId: ethers.BigNumberish, wallet: ethers.Wallet, diff --git a/l2-contracts/test/consensusRegistry.test.ts b/l2-contracts/test/consensusRegistry.test.ts new file mode 100644 index 000000000..66c0309bd --- /dev/null +++ b/l2-contracts/test/consensusRegistry.test.ts @@ -0,0 +1,499 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import * as hre from "hardhat"; +import { Provider, Wallet } from "zksync-ethers"; +import type { ConsensusRegistry } from "../typechain"; +import { ConsensusRegistryFactory } from "../typechain"; +import { expect } from "chai"; +import { ethers } from "ethers"; +import { Interface } from "ethers/lib/utils"; + +const richAccount = { + address: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + privateKey: "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110", +}; + +const gasLimit = 100_000_000; + +const CONSENSUS_REGISTRY_ARTIFACT = hre.artifacts.readArtifactSync("ConsensusRegistry"); +const CONSENSUS_REGISTRY_INTERFACE = new Interface(CONSENSUS_REGISTRY_ARTIFACT.abi); + +describe("ConsensusRegistry", function () { + const provider = new Provider(hre.config.networks.localhost.url); + const owner = new Wallet(richAccount.privateKey, provider); + const nonOwner = new Wallet(Wallet.createRandom().privateKey, provider); + const nodes = []; + const nodeEntries = []; + let registry: ConsensusRegistry; + + before("Initialize", async function () { + // Deploy. + const deployer = new Deployer(hre, owner); + const registryInstance = await deployer.deploy(await deployer.loadArtifact("ConsensusRegistry"), []); + const proxyAdmin = await deployer.deploy(await deployer.loadArtifact("ProxyAdmin"), []); + const proxyInitializationParams = CONSENSUS_REGISTRY_INTERFACE.encodeFunctionData("initialize", [owner.address]); + const proxyInstance = await deployer.deploy(await deployer.loadArtifact("TransparentUpgradeableProxy"), [ + registryInstance.address, + proxyAdmin.address, + proxyInitializationParams, + ]); + registry = ConsensusRegistryFactory.connect(proxyInstance.address, owner); + + // Fund nonOwner. + await ( + await owner.sendTransaction({ + to: nonOwner.address, + value: ethers.utils.parseEther("100"), + }) + ).wait(); + + // Prepare the node list. + const numNodes = 10; + for (let i = 0; i < numNodes; i++) { + const node = makeRandomNode(provider); + const nodeEntry = makeRandomNodeEntry(node, i); + nodes.push(node); + nodeEntries.push(nodeEntry); + } + + // Fund the first node owner. + await ( + await owner.sendTransaction({ + to: nodes[0].ownerKey.address, + value: ethers.utils.parseEther("100"), + }) + ).wait(); + }); + + it("Should set the owner as provided in constructor", async function () { + expect(await registry.owner()).to.equal(owner.address); + }); + + it("Should add nodes to both registries", async function () { + for (let i = 0; i < nodes.length; i++) { + await ( + await registry.add( + nodeEntries[i].ownerAddr, + nodeEntries[i].validatorWeight, + nodeEntries[i].validatorPubKey, + nodeEntries[i].validatorPoP, + nodeEntries[i].attesterWeight, + nodeEntries[i].attesterPubKey + ) + ).wait(); + } + + expect(await registry.numNodes()).to.equal(nodes.length); + + for (let i = 0; i < nodes.length; i++) { + const nodeOwner = await registry.nodeOwners(i); + expect(nodeOwner).to.equal(nodeEntries[i].ownerAddr); + const node = await registry.nodes(nodeOwner); + expect(node.attesterLastUpdateCommit).to.equal(0); + expect(node.validatorLastUpdateCommit).to.equal(0); + + // 'Latest' is expected to match the added node's attributes. + expect(node.attesterLatest.active).to.equal(true); + expect(node.attesterLatest.removed).to.equal(false); + expect(node.attesterLatest.weight).to.equal(nodeEntries[i].attesterWeight); + expect(node.attesterLatest.pubKey.tag).to.equal(nodeEntries[i].attesterPubKey.tag); + expect(node.attesterLatest.pubKey.x).to.equal(nodeEntries[i].attesterPubKey.x); + expect(node.validatorLastUpdateCommit).to.equal(0); + expect(node.validatorLatest.active).to.equal(true); + expect(node.validatorLatest.removed).to.equal(false); + expect(node.validatorLatest.weight).to.equal(nodeEntries[i].attesterWeight); + expect(node.validatorLatest.pubKey.a).to.equal(nodeEntries[i].validatorPubKey.a); + expect(node.validatorLatest.pubKey.b).to.equal(nodeEntries[i].validatorPubKey.b); + expect(node.validatorLatest.pubKey.c).to.equal(nodeEntries[i].validatorPubKey.c); + expect(node.validatorLatest.proofOfPossession.a).to.equal(nodeEntries[i].validatorPoP.a); + expect(node.validatorLatest.proofOfPossession.b).to.equal(nodeEntries[i].validatorPoP.b); + + // 'Snapshot' is expected to have zero values. + expect(node.attesterSnapshot.active).to.equal(false); + expect(node.attesterSnapshot.removed).to.equal(false); + expect(node.attesterSnapshot.weight).to.equal(0); + expect(ethers.utils.arrayify(node.attesterSnapshot.pubKey.tag)).to.deep.equal(new Uint8Array(1)); + expect(ethers.utils.arrayify(node.attesterSnapshot.pubKey.x)).to.deep.equal(new Uint8Array(32)); + expect(node.validatorSnapshot.active).to.equal(false); + expect(node.validatorSnapshot.removed).to.equal(false); + expect(node.validatorSnapshot.weight).to.equal(0); + expect(ethers.utils.arrayify(node.validatorSnapshot.pubKey.a)).to.deep.equal(new Uint8Array(32)); + expect(ethers.utils.arrayify(node.validatorSnapshot.pubKey.b)).to.deep.equal(new Uint8Array(32)); + expect(ethers.utils.arrayify(node.validatorSnapshot.pubKey.c)).to.deep.equal(new Uint8Array(32)); + expect(ethers.utils.arrayify(node.validatorSnapshot.proofOfPossession.a)).to.deep.equal(new Uint8Array(32)); + expect(ethers.utils.arrayify(node.validatorSnapshot.proofOfPossession.b)).to.deep.equal(new Uint8Array(16)); + } + }); + + it("Should not allow nonOwner to add", async function () { + await expect( + registry + .connect(nonOwner) + .add( + ethers.Wallet.createRandom().address, + 0, + { a: new Uint8Array(32), b: new Uint8Array(32), c: new Uint8Array(32) }, + { a: new Uint8Array(32), b: new Uint8Array(16) }, + 0, + { tag: new Uint8Array(1), x: new Uint8Array(32) }, + { gasLimit } + ) + ).to.be.reverted; + }); + + it("Should allow owner to deactivate", async function () { + const nodeOwner = nodeEntries[0].ownerAddr; + expect((await registry.nodes(nodeOwner)).validatorLatest.active).to.equal(true); + + await (await registry.connect(owner).deactivate(nodeOwner, { gasLimit })).wait(); + expect((await registry.nodes(nodeOwner)).validatorLatest.active).to.equal(false); + + // Restore state. + await (await registry.connect(owner).activate(nodeOwner, { gasLimit })).wait(); + }); + + it("Should not allow nonOwner, nonNodeOwner to deactivate", async function () { + const nodeOwner = nodeEntries[0].ownerAddr; + await expect(registry.connect(nonOwner).deactivate(nodeOwner, { gasLimit })).to.be.reverted; + }); + + it("Should change validator weight", async function () { + const entry = nodeEntries[0]; + expect((await registry.nodes(entry.ownerAddr)).validatorLatest.weight).to.equal(entry.validatorWeight); + + const baseWeight = entry.validatorWeight; + const newWeight = getRandomNumber(100, 1000); + await (await registry.changeValidatorWeight(entry.ownerAddr, newWeight, { gasLimit })).wait(); + expect((await registry.nodes(entry.ownerAddr)).validatorLatest.weight).to.equal(newWeight); + expect((await registry.nodes(entry.ownerAddr)).attesterLatest.weight).to.equal(entry.attesterWeight); + + // Restore state. + await (await registry.changeValidatorWeight(entry.ownerAddr, baseWeight, { gasLimit })).wait(); + }); + + it("Should not allow nodeOwner to change validator weight", async function () { + const node = nodes[0]; + await expect(registry.connect(node.ownerKey).changeValidatorWeight(node.ownerKey.address, 0, { gasLimit })).to.be + .reverted; + }); + + it("Should not allow nonOwner to change validator weight", async function () { + const node = nodes[0]; + await expect(registry.connect(nonOwner).changeValidatorWeight(node.ownerKey.address, 0, { gasLimit })).to.be + .reverted; + }); + + it("Should change attester weight", async function () { + const entry = nodeEntries[0]; + expect((await registry.nodes(entry.ownerAddr)).attesterLatest.weight).to.equal(entry.attesterWeight); + + const baseWeight = entry.attesterWeight; + const newWeight = getRandomNumber(100, 1000); + await (await registry.changeAttesterWeight(entry.ownerAddr, newWeight, { gasLimit })).wait(); + expect((await registry.nodes(entry.ownerAddr)).attesterLatest.weight).to.equal(newWeight); + expect((await registry.nodes(entry.ownerAddr)).validatorLatest.weight).to.equal(entry.validatorWeight); + + // Restore state. + await (await registry.changeAttesterWeight(entry.ownerAddr, baseWeight, { gasLimit })).wait(); + }); + + it("Should not allow nodeOwner to change attester weight", async function () { + const node = nodes[0]; + await expect(registry.connect(node.ownerKey).changeAttesterWeight(node.ownerKey.address, 0, { gasLimit })).to.be + .reverted; + }); + + it("Should not allow nonOwner to change attester weight", async function () { + const node = nodes[0]; + await expect(registry.connect(nonOwner).changeAttesterWeight(node.ownerKey.address, 0, { gasLimit })).to.be + .reverted; + }); + + it("Should not allow to add a node with a validator public key which already exist", async function () { + const newEntry = makeRandomNodeEntry(makeRandomNode(), 0); + await expect( + registry.add( + newEntry.ownerAddr, + newEntry.validatorWeight, + nodeEntries[0].validatorPubKey, + newEntry.validatorPoP, + newEntry.attesterWeight, + newEntry.attesterPubKey, + { gasLimit } + ) + ).to.be.reverted; + }); + + it("Should not allow to add a node with an attester public key which already exist", async function () { + const newEntry = makeRandomNodeEntry(makeRandomNode(), 0); + await expect( + registry.add( + newEntry.ownerAddr, + newEntry.validatorWeight, + newEntry.validatorPubKey, + newEntry.validatorPoP, + newEntry.attesterWeight, + nodeEntries[0].attesterPubKey, + { gasLimit } + ) + ).to.be.reverted; + }); + + it("Should return attester committee once committed to", async function () { + // Verify that committee was not committed to. + expect((await registry.getAttesterCommittee()).length).to.equal(0); + + // Commit. + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + + // Read committee. + const attesterCommittee = await registry.getAttesterCommittee(); + expect(attesterCommittee.length).to.equal(nodes.length); + for (let i = 0; i < attesterCommittee.length; i++) { + const entry = nodeEntries[i]; + const attester = attesterCommittee[i]; + expect(attester.weight).to.equal(entry.attesterWeight); + expect(attester.pubKey.tag).to.equal(entry.attesterPubKey.tag); + expect(attester.pubKey.x).to.equal(entry.attesterPubKey.x); + } + }); + + it("Should return validator committee once committed to", async function () { + // Verify that committee was not committed to. + expect((await registry.getValidatorCommittee()).length).to.equal(0); + + // Commit. + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + + // Read committee. + const validatorCommittee = await registry.getValidatorCommittee(); + expect(validatorCommittee.length).to.equal(nodes.length); + for (let i = 0; i < validatorCommittee.length; i++) { + const entry = nodeEntries[i]; + const validator = validatorCommittee[i]; + expect(validator.weight).to.equal(entry.validatorWeight); + expect(validator.pubKey.a).to.equal(entry.validatorPubKey.a); + expect(validator.pubKey.b).to.equal(entry.validatorPubKey.b); + expect(validator.pubKey.c).to.equal(entry.validatorPubKey.c); + expect(validator.proofOfPossession.a).to.equal(entry.validatorPoP.a); + expect(validator.proofOfPossession.b).to.equal(entry.validatorPoP.b); + } + }); + + it("Should not include inactive nodes in attester and validator committees when committed to", async function () { + const idx = nodeEntries.length - 1; + const entry = nodeEntries[idx]; + + // Deactivate attribute. + await (await registry.deactivate(entry.ownerAddr, { gasLimit })).wait(); + + // Verify no change. + expect((await registry.getAttesterCommittee()).length).to.equal(nodes.length); + expect((await registry.getValidatorCommittee()).length).to.equal(nodes.length); + + // Commit attester committee and verify. + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + expect((await registry.getAttesterCommittee()).length).to.equal(nodes.length - 1); + expect((await registry.getValidatorCommittee()).length).to.equal(nodes.length); + + // Commit validator committee and verify. + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + expect((await registry.getAttesterCommittee()).length).to.equal(nodes.length - 1); + expect((await registry.getValidatorCommittee()).length).to.equal(nodes.length - 1); + + // Restore state. + await (await registry.activate(entry.ownerAddr, { gasLimit })).wait(); + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + }); + + it("Should not include removed nodes in attester and validator committees when committed to", async function () { + const idx = nodeEntries.length - 1; + const entry = nodeEntries[idx]; + + // Remove node. + await (await registry.remove(entry.ownerAddr, { gasLimit })).wait(); + + // Verify no change. + expect((await registry.getAttesterCommittee()).length).to.equal(nodes.length); + expect((await registry.getValidatorCommittee()).length).to.equal(nodes.length); + + // Commit attester committee and verify. + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + expect((await registry.getAttesterCommittee()).length).to.equal(nodes.length - 1); + expect((await registry.getValidatorCommittee()).length).to.equal(nodes.length); + + // Commit validator committee and verify. + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + expect((await registry.getAttesterCommittee()).length).to.equal(nodes.length - 1); + expect((await registry.getValidatorCommittee()).length).to.equal(nodes.length - 1); + + // Restore state. + await (await registry.remove(entry.ownerAddr, { gasLimit })).wait(); + await ( + await registry.add( + entry.ownerAddr, + entry.validatorWeight, + entry.validatorPubKey, + entry.validatorPoP, + entry.attesterWeight, + entry.attesterPubKey + ) + ).wait(); + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + }); + + it("Should not include node attribute change in attester committee before committed to", async function () { + const idx = nodeEntries.length - 1; + const entry = nodeEntries[idx]; + + // Change attribute. + await (await registry.changeAttesterWeight(entry.ownerAddr, entry.attesterWeight + 1, { gasLimit })).wait(); + + // Verify no change. + const attester = (await registry.getAttesterCommittee())[idx]; + expect(attester.weight).to.equal(entry.attesterWeight); + + // Commit. + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + + // Verify change. + const committedAttester = (await registry.getAttesterCommittee())[idx]; + expect(committedAttester.weight).to.equal(entry.attesterWeight + 1); + + // Restore state. + await (await registry.changeAttesterWeight(entry.ownerAddr, entry.attesterWeight, { gasLimit })).wait(); + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + }); + + it("Should not include node attribute change in validator committee before committed to", async function () { + const idx = nodeEntries.length - 1; + const entry = nodeEntries[idx]; + + // Change attribute. + await (await registry.changeValidatorWeight(entry.ownerAddr, entry.attesterWeight + 1, { gasLimit })).wait(); + + // Verify no change. + const validator = (await registry.getValidatorCommittee())[idx]; + expect(validator.weight).to.equal(entry.validatorWeight); + + // Commit. + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + + // Verify change. + const committedValidator = (await registry.getValidatorCommittee())[idx]; + expect(committedValidator.weight).to.equal(entry.validatorWeight + 1); + + // Restore state. + await (await registry.changeValidatorWeight(entry.ownerAddr, entry.validatorWeight, { gasLimit })).wait(); + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + }); + + it("Should finalize node removal by fully deleting it from storage", async function () { + const idx = nodeEntries.length - 1; + const entry = nodeEntries[idx]; + + // Remove. + expect((await registry.nodes(entry.ownerAddr)).attesterLatest.removed).to.equal(false); + expect((await registry.nodes(entry.ownerAddr)).validatorLatest.removed).to.equal(false); + await (await registry.remove(entry.ownerAddr, { gasLimit })).wait(); + expect((await registry.nodes(entry.ownerAddr)).attesterLatest.removed).to.equal(true); + expect((await registry.nodes(entry.ownerAddr)).validatorLatest.removed).to.equal(true); + + // Commit committees. + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + + // Verify node was not yet deleted. + expect(await registry.numNodes()).to.equal(nodes.length); + const attesterPubKeyHash = hashAttesterPubKey(entry.attesterPubKey); + expect(await registry.attesterPubKeyHashes(attesterPubKeyHash)).to.be.equal(true); + const validatorPubKeyHash = hashValidatorPubKey(entry.validatorPubKey); + expect(await registry.validatorPubKeyHashes(validatorPubKeyHash)).to.be.equal(true); + + // Trigger node deletion. + await (await registry.remove(entry.ownerAddr, { gasLimit })).wait(); + + // Verify the deletion. + expect(await registry.numNodes()).to.equal(nodes.length - 1); + expect(await registry.attesterPubKeyHashes(attesterPubKeyHash)).to.be.equal(false); + expect(await registry.validatorPubKeyHashes(attesterPubKeyHash)).to.be.equal(false); + const node = await registry.nodes(entry.ownerAddr, { gasLimit }); + expect(ethers.utils.arrayify(node.attesterLatest.pubKey.tag)).to.deep.equal(new Uint8Array(1)); + expect(ethers.utils.arrayify(node.attesterLatest.pubKey.x)).to.deep.equal(new Uint8Array(32)); + + // Restore state. + await ( + await registry.add( + entry.ownerAddr, + entry.validatorWeight, + entry.validatorPubKey, + entry.validatorPoP, + entry.attesterWeight, + entry.attesterPubKey + ) + ).wait(); + await (await registry.commitAttesterCommittee({ gasLimit })).wait(); + await (await registry.commitValidatorCommittee({ gasLimit })).wait(); + }); + + function makeRandomNode() { + return { + ownerKey: new Wallet(Wallet.createRandom().privateKey, provider), + validatorKey: Wallet.createRandom(), + attesterKey: Wallet.createRandom(), + }; + } + + function makeRandomNodeEntry(node, weight: number) { + return { + ownerAddr: node.ownerKey.address, + validatorWeight: weight, + validatorPubKey: getRandomValidatorPubKey(), + validatorPoP: getRandomValidatorPoP(), + attesterWeight: weight, + attesterPubKey: getRandomAttesterPubKey(), + }; + } +}); + +function getRandomNumber(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function getRandomValidatorPubKey() { + return { + a: ethers.utils.hexlify(ethers.utils.randomBytes(32)), + b: ethers.utils.hexlify(ethers.utils.randomBytes(32)), + c: ethers.utils.hexlify(ethers.utils.randomBytes(32)), + }; +} + +function getRandomValidatorPoP() { + return { + a: ethers.utils.hexlify(ethers.utils.randomBytes(32)), + b: ethers.utils.hexlify(ethers.utils.randomBytes(16)), + }; +} + +function getRandomAttesterPubKey() { + return { + tag: ethers.utils.hexlify(ethers.utils.randomBytes(1)), + x: ethers.utils.hexlify(ethers.utils.randomBytes(32)), + }; +} + +function hashAttesterPubKey(attesterPubKey) { + return ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode(["bytes1", "bytes32"], [attesterPubKey.tag, attesterPubKey.x]) + ); +} + +function hashValidatorPubKey(validatorPubKey) { + return ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode( + ["bytes32", "bytes32", "bytes32"], + [validatorPubKey.a, validatorPubKey.b, validatorPubKey.c] + ) + ); +} diff --git a/system-contracts/package.json b/system-contracts/package.json index bce80474f..ef53db110 100644 --- a/system-contracts/package.json +++ b/system-contracts/package.json @@ -14,7 +14,8 @@ "ethers": "^5.7.0", "fast-glob": "^3.3.2", "hardhat": "=2.22.2", - "preprocess": "^3.2.0" + "preprocess": "^3.2.0", + "zksync-ethers": "^5.9.0" }, "devDependencies": { "@matterlabs/hardhat-zksync-chai-matchers": "^0.2.0", diff --git a/system-contracts/scripts/verify-on-explorer.ts b/system-contracts/scripts/verify-on-explorer.ts index 95fa65218..9aa37e3e6 100644 --- a/system-contracts/scripts/verify-on-explorer.ts +++ b/system-contracts/scripts/verify-on-explorer.ts @@ -6,7 +6,7 @@ import { SYSTEM_CONTRACTS } from "./constants"; import { query } from "./utils"; import { Command } from "commander"; import * as fs from "fs"; -import { sleep } from "zksync-ethers/build/src/utils"; +import { sleep } from "zksync-ethers/build/utils"; const VERIFICATION_URL = hre.network?.config?.verifyURL; diff --git a/yarn.lock b/yarn.lock index 2dfdc5f28..6ab96b427 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7926,8 +7926,8 @@ zksync-ethers@^5.0.0: ethers "~5.7.0" zksync-ethers@^5.9.0: - version "5.9.0" - resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-5.9.0.tgz#96dc29e4eaaf0aa70d927886fd6e1e4c545786e3" - integrity sha512-VnRUesrBcPBmiTYTAp+WreIazK2qCIJEHE7j8BiK+cDApHzjAfIXX+x8SXXJpG1npGJANxiJKnPwA5wjGZtCRg== + version "5.9.2" + resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-5.9.2.tgz#1c5f34cb25ac0b040fd1a6118f2ba1c2c3bda090" + integrity sha512-Y2Mx6ovvxO6UdC2dePLguVzvNToOY8iLWeq5ne+jgGSJxAi/f4He/NF6FNsf6x1aWX0o8dy4Df8RcOQXAkj5qw== dependencies: ethers "~5.7.0" From 939151eb1ee74805abfc85e4a7e180da6fcb456a Mon Sep 17 00:00:00 2001 From: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> Date: Wed, 2 Oct 2024 19:34:48 +0400 Subject: [PATCH 07/54] Add utils for DecentralizeGovernance transaction (#829) --- l1-contracts/deploy-scripts/EIP712Utils.sol | 30 ++++ l1-contracts/deploy-scripts/Utils.sol | 133 ++++++++++++++++++ .../interfaces/IEmergencyUpgrageBoard.sol | 23 +++ .../deploy-scripts/interfaces/IMultisig.sol | 9 ++ .../interfaces/IProtocolUpgradeHandler.sol | 33 +++++ .../deploy-scripts/interfaces/ISafe.sol | 9 ++ 6 files changed, 237 insertions(+) create mode 100644 l1-contracts/deploy-scripts/EIP712Utils.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/IMultisig.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/ISafe.sol diff --git a/l1-contracts/deploy-scripts/EIP712Utils.sol b/l1-contracts/deploy-scripts/EIP712Utils.sol new file mode 100644 index 000000000..5f1aeb958 --- /dev/null +++ b/l1-contracts/deploy-scripts/EIP712Utils.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +library EIP712Utils { + bytes32 private constant TYPE_HASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + function buildDomainHash( + address _verifyingContract, + string memory _name, + string memory _version + ) internal view returns (bytes32) { + return + keccak256( + // solhint-disable-next-line func-named-parameters + abi.encode( + TYPE_HASH, + keccak256(bytes(_name)), + keccak256(bytes(_version)), + block.chainid, + _verifyingContract + ) + ); + } + + function buildDigest(bytes32 _domainHash, bytes32 _message) internal view returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", _domainHash, _message)); + } +} diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index fb56bce08..4f5892ef2 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -11,6 +11,26 @@ import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; import {IChainAdmin} from "contracts/governance/IChainAdmin.sol"; +import {EIP712Utils} from "./EIP712Utils.sol"; +import {IProtocolUpgradeHandler} from "./interfaces/IProtocolUpgradeHandler.sol"; +import {IEmergencyUpgrageBoard} from "./interfaces/IEmergencyUpgrageBoard.sol"; +import {IMultisig} from "./interfaces/IMultisig.sol"; +import {ISafe} from "./interfaces/ISafe.sol"; + +/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the guardians. +bytes32 constant EXECUTE_EMERGENCY_UPGRADE_GUARDIANS_TYPEHASH = keccak256( + "ExecuteEmergencyUpgradeGuardians(bytes32 id)" +); + +/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the Security Council. +bytes32 constant EXECUTE_EMERGENCY_UPGRADE_SECURITY_COUNCIL_TYPEHASH = keccak256( + "ExecuteEmergencyUpgradeSecurityCouncil(bytes32 id)" +); + +/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the ZK Foundation. +bytes32 constant EXECUTE_EMERGENCY_UPGRADE_ZK_FOUNDATION_TYPEHASH = keccak256( + "ExecuteEmergencyUpgradeZKFoundation(bytes32 id)" +); library Utils { // Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. @@ -324,4 +344,117 @@ library Utils { } vm.stopBroadcast(); } + + function executeEmergencyProtocolUpgrade( + IProtocolUpgradeHandler _protocolUpgradeHandler, + Vm.Wallet memory _governorWallet, + IProtocolUpgradeHandler.Call[] memory _calls, + bytes32 _salt + ) internal returns (bytes memory) { + bytes32 upgradeId; + bytes32 emergencyUpgradeBoardDigest; + { + address emergencyUpgradeBoard = _protocolUpgradeHandler.emergencyUpgradeBoard(); + IProtocolUpgradeHandler.UpgradeProposal memory upgradeProposal = IProtocolUpgradeHandler.UpgradeProposal({ + calls: _calls, + salt: _salt, + executor: emergencyUpgradeBoard + }); + upgradeId = keccak256(abi.encode(upgradeProposal)); + emergencyUpgradeBoardDigest = EIP712Utils.buildDomainHash( + emergencyUpgradeBoard, + "EmergencyUpgradeBoard", + "1" + ); + } + + bytes memory guardiansSignatures; + { + address[] memory guardiansMembers = new address[](8); + { + IMultisig guardians = IMultisig(_protocolUpgradeHandler.guardians()); + for (uint256 i = 0; i < 8; i++) { + guardiansMembers[i] = guardians.members(i); + } + } + bytes[] memory guardiansRawSignatures = new bytes[](8); + for (uint256 i = 0; i < 8; i++) { + bytes32 safeDigest; + { + bytes32 guardiansDigest = EIP712Utils.buildDigest( + emergencyUpgradeBoardDigest, + keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_GUARDIANS_TYPEHASH, upgradeId)) + ); + safeDigest = ISafe(guardiansMembers[i]).getMessageHash(abi.encode(guardiansDigest)); + } + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest); + guardiansRawSignatures[i] = abi.encodePacked(r, s, v); + } + guardiansSignatures = abi.encode(guardiansMembers, guardiansRawSignatures); + } + + bytes memory securityCouncilSignatures; + { + address[] memory securityCouncilMembers = new address[](12); + { + IMultisig securityCouncil = IMultisig(_protocolUpgradeHandler.securityCouncil()); + for (uint256 i = 0; i < 12; i++) { + securityCouncilMembers[i] = securityCouncil.members(i); + } + } + bytes[] memory securityCouncilRawSignatures = new bytes[](12); + for (uint256 i = 0; i < securityCouncilMembers.length; i++) { + bytes32 safeDigest; + { + bytes32 securityCouncilDigest = EIP712Utils.buildDigest( + emergencyUpgradeBoardDigest, + keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_SECURITY_COUNCIL_TYPEHASH, upgradeId)) + ); + safeDigest = ISafe(securityCouncilMembers[i]).getMessageHash(abi.encode(securityCouncilDigest)); + } + { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest); + securityCouncilRawSignatures[i] = abi.encodePacked(r, s, v); + } + } + securityCouncilSignatures = abi.encode(securityCouncilMembers, securityCouncilRawSignatures); + } + + bytes memory zkFoundationSignature; + { + ISafe zkFoundation; + { + IEmergencyUpgrageBoard emergencyUpgradeBoard = IEmergencyUpgrageBoard( + _protocolUpgradeHandler.emergencyUpgradeBoard() + ); + zkFoundation = ISafe(emergencyUpgradeBoard.ZK_FOUNDATION_SAFE()); + } + bytes32 zkFoundationDigest = EIP712Utils.buildDigest( + emergencyUpgradeBoardDigest, + keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_ZK_FOUNDATION_TYPEHASH, upgradeId)) + ); + bytes32 safeDigest = ISafe(zkFoundation).getMessageHash(abi.encode(zkFoundationDigest)); + { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest); + zkFoundationSignature = abi.encodePacked(r, s, v); + } + } + + { + vm.startBroadcast(); + IEmergencyUpgrageBoard emergencyUpgradeBoard = IEmergencyUpgrageBoard( + _protocolUpgradeHandler.emergencyUpgradeBoard() + ); + // solhint-disable-next-line func-named-parameters + emergencyUpgradeBoard.executeEmergencyUpgrade( + _calls, + _salt, + guardiansSignatures, + securityCouncilSignatures, + zkFoundationSignature + ); + vm.stopBroadcast(); + } + } } diff --git a/l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol b/l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol new file mode 100644 index 000000000..1f3d0d3d6 --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {IProtocolUpgradeHandler} from "./IProtocolUpgradeHandler.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IEmergencyUpgrageBoard { + function GUARDIANS() external view returns (address); + + function SECURITY_COUNCIL() external view returns (address); + + function ZK_FOUNDATION_SAFE() external view returns (address); + + function executeEmergencyUpgrade( + IProtocolUpgradeHandler.Call[] calldata _calls, + bytes32 _salt, + bytes calldata _guardiansSignatures, + bytes calldata _securityCouncilSignatures, + bytes calldata _zkFoundationSignatures + ) external; +} diff --git a/l1-contracts/deploy-scripts/interfaces/IMultisig.sol b/l1-contracts/deploy-scripts/interfaces/IMultisig.sol new file mode 100644 index 000000000..2a1dd955d --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/IMultisig.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IMultisig { + function members(uint256) external view returns (address); +} diff --git a/l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol b/l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol new file mode 100644 index 000000000..baa48f43f --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IProtocolUpgradeHandler { + /// @dev Represents a call to be made during an upgrade. + /// @param target The address to which the call will be made. + /// @param value The amount of Ether (in wei) to be sent along with the call. + /// @param data The calldata to be executed on the `target` address. + struct Call { + address target; + uint256 value; + bytes data; + } + + /// @dev Defines the structure of an upgrade that is executed by Protocol Upgrade Handler. + /// @param executor The L1 address that is authorized to perform the upgrade execution (if address(0) then anyone). + /// @param calls An array of `Call` structs, each representing a call to be made during the upgrade execution. + /// @param salt A bytes32 value used for creating unique upgrade proposal hashes. + struct UpgradeProposal { + Call[] calls; + address executor; + bytes32 salt; + } + + function emergencyUpgradeBoard() external view returns (address); + + function guardians() external view returns (address); + + function securityCouncil() external view returns (address); +} diff --git a/l1-contracts/deploy-scripts/interfaces/ISafe.sol b/l1-contracts/deploy-scripts/interfaces/ISafe.sol new file mode 100644 index 000000000..82877b3b3 --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/ISafe.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface ISafe { + function getMessageHash(bytes memory _message) external view returns (bytes32); +} From aafee035db892689df3f7afe4b89fd6467a39313 Mon Sep 17 00:00:00 2001 From: Grzegorz Prusak Date: Thu, 3 Oct 2024 11:56:45 +0200 Subject: [PATCH 08/54] feat(zk_toolbox): dedicated command for deploying multicall3 on L2 (#835) --- l1-contracts/deploy-scripts/DeployL2Contracts.sol | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 9e78f05e5..3525b66b4 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -107,6 +107,15 @@ contract DeployL2Script is Script { saveOutput(); } + function runDeployMulticall3() public { + initializeConfig(); + loadContracts(false); + + deployMulticall3(); + + saveOutput(); + } + function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat contracts.l2StandardErc20FactoryBytecode = Utils.readHardhatBytecode( From a7e892315793ec62dd240c510977064791fedad6 Mon Sep 17 00:00:00 2001 From: koloz193 Date: Fri, 4 Oct 2024 08:33:20 -0400 Subject: [PATCH 09/54] Merge main back into protocol defense (#839) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Danil Co-authored-by: Bence Haromi <56651250+benceharomi@users.noreply.github.com> Co-authored-by: Grzegorz Prusak Co-authored-by: Moshe Shababo <17073733+moshababo@users.noreply.github.com> Co-authored-by: Akosh Farkash Co-authored-by: Bruno França Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> Co-authored-by: Roman Brodetski Co-authored-by: vladbochok Co-authored-by: Stanislav Bezkorovainyi Co-authored-by: Danil --- .../deploy-scripts/DeployL2Contracts.sol | 9 ++ l1-contracts/deploy-scripts/EIP712Utils.sol | 30 ++++ l1-contracts/deploy-scripts/Utils.sol | 133 ++++++++++++++++++ .../interfaces/IEmergencyUpgrageBoard.sol | 23 +++ .../deploy-scripts/interfaces/IMultisig.sol | 9 ++ .../interfaces/IProtocolUpgradeHandler.sol | 33 +++++ .../deploy-scripts/interfaces/ISafe.sol | 9 ++ yarn.lock | 7 + 8 files changed, 253 insertions(+) create mode 100644 l1-contracts/deploy-scripts/EIP712Utils.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/IMultisig.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol create mode 100644 l1-contracts/deploy-scripts/interfaces/ISafe.sol diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 554ed940c..80b458f82 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -110,6 +110,15 @@ contract DeployL2Script is Script { saveOutput(); } + function runDeployMulticall3() public { + initializeConfig(); + loadContracts(false); + + deployMulticall3(); + + saveOutput(); + } + function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat contracts.l2StandardErc20FactoryBytecode = Utils.readHardhatBytecode( diff --git a/l1-contracts/deploy-scripts/EIP712Utils.sol b/l1-contracts/deploy-scripts/EIP712Utils.sol new file mode 100644 index 000000000..5f1aeb958 --- /dev/null +++ b/l1-contracts/deploy-scripts/EIP712Utils.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +library EIP712Utils { + bytes32 private constant TYPE_HASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + function buildDomainHash( + address _verifyingContract, + string memory _name, + string memory _version + ) internal view returns (bytes32) { + return + keccak256( + // solhint-disable-next-line func-named-parameters + abi.encode( + TYPE_HASH, + keccak256(bytes(_name)), + keccak256(bytes(_version)), + block.chainid, + _verifyingContract + ) + ); + } + + function buildDigest(bytes32 _domainHash, bytes32 _message) internal view returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", _domainHash, _message)); + } +} diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index fa2bb194c..5f509b0db 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -13,6 +13,26 @@ import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; import {IChainAdmin} from "contracts/governance/IChainAdmin.sol"; +import {EIP712Utils} from "./EIP712Utils.sol"; +import {IProtocolUpgradeHandler} from "./interfaces/IProtocolUpgradeHandler.sol"; +import {IEmergencyUpgrageBoard} from "./interfaces/IEmergencyUpgrageBoard.sol"; +import {IMultisig} from "./interfaces/IMultisig.sol"; +import {ISafe} from "./interfaces/ISafe.sol"; + +/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the guardians. +bytes32 constant EXECUTE_EMERGENCY_UPGRADE_GUARDIANS_TYPEHASH = keccak256( + "ExecuteEmergencyUpgradeGuardians(bytes32 id)" +); + +/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the Security Council. +bytes32 constant EXECUTE_EMERGENCY_UPGRADE_SECURITY_COUNCIL_TYPEHASH = keccak256( + "ExecuteEmergencyUpgradeSecurityCouncil(bytes32 id)" +); + +/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the ZK Foundation. +bytes32 constant EXECUTE_EMERGENCY_UPGRADE_ZK_FOUNDATION_TYPEHASH = keccak256( + "ExecuteEmergencyUpgradeZKFoundation(bytes32 id)" +); library Utils { // Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. @@ -342,4 +362,117 @@ library Utils { } vm.stopBroadcast(); } + + function executeEmergencyProtocolUpgrade( + IProtocolUpgradeHandler _protocolUpgradeHandler, + Vm.Wallet memory _governorWallet, + IProtocolUpgradeHandler.Call[] memory _calls, + bytes32 _salt + ) internal returns (bytes memory) { + bytes32 upgradeId; + bytes32 emergencyUpgradeBoardDigest; + { + address emergencyUpgradeBoard = _protocolUpgradeHandler.emergencyUpgradeBoard(); + IProtocolUpgradeHandler.UpgradeProposal memory upgradeProposal = IProtocolUpgradeHandler.UpgradeProposal({ + calls: _calls, + salt: _salt, + executor: emergencyUpgradeBoard + }); + upgradeId = keccak256(abi.encode(upgradeProposal)); + emergencyUpgradeBoardDigest = EIP712Utils.buildDomainHash( + emergencyUpgradeBoard, + "EmergencyUpgradeBoard", + "1" + ); + } + + bytes memory guardiansSignatures; + { + address[] memory guardiansMembers = new address[](8); + { + IMultisig guardians = IMultisig(_protocolUpgradeHandler.guardians()); + for (uint256 i = 0; i < 8; i++) { + guardiansMembers[i] = guardians.members(i); + } + } + bytes[] memory guardiansRawSignatures = new bytes[](8); + for (uint256 i = 0; i < 8; i++) { + bytes32 safeDigest; + { + bytes32 guardiansDigest = EIP712Utils.buildDigest( + emergencyUpgradeBoardDigest, + keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_GUARDIANS_TYPEHASH, upgradeId)) + ); + safeDigest = ISafe(guardiansMembers[i]).getMessageHash(abi.encode(guardiansDigest)); + } + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest); + guardiansRawSignatures[i] = abi.encodePacked(r, s, v); + } + guardiansSignatures = abi.encode(guardiansMembers, guardiansRawSignatures); + } + + bytes memory securityCouncilSignatures; + { + address[] memory securityCouncilMembers = new address[](12); + { + IMultisig securityCouncil = IMultisig(_protocolUpgradeHandler.securityCouncil()); + for (uint256 i = 0; i < 12; i++) { + securityCouncilMembers[i] = securityCouncil.members(i); + } + } + bytes[] memory securityCouncilRawSignatures = new bytes[](12); + for (uint256 i = 0; i < securityCouncilMembers.length; i++) { + bytes32 safeDigest; + { + bytes32 securityCouncilDigest = EIP712Utils.buildDigest( + emergencyUpgradeBoardDigest, + keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_SECURITY_COUNCIL_TYPEHASH, upgradeId)) + ); + safeDigest = ISafe(securityCouncilMembers[i]).getMessageHash(abi.encode(securityCouncilDigest)); + } + { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest); + securityCouncilRawSignatures[i] = abi.encodePacked(r, s, v); + } + } + securityCouncilSignatures = abi.encode(securityCouncilMembers, securityCouncilRawSignatures); + } + + bytes memory zkFoundationSignature; + { + ISafe zkFoundation; + { + IEmergencyUpgrageBoard emergencyUpgradeBoard = IEmergencyUpgrageBoard( + _protocolUpgradeHandler.emergencyUpgradeBoard() + ); + zkFoundation = ISafe(emergencyUpgradeBoard.ZK_FOUNDATION_SAFE()); + } + bytes32 zkFoundationDigest = EIP712Utils.buildDigest( + emergencyUpgradeBoardDigest, + keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_ZK_FOUNDATION_TYPEHASH, upgradeId)) + ); + bytes32 safeDigest = ISafe(zkFoundation).getMessageHash(abi.encode(zkFoundationDigest)); + { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest); + zkFoundationSignature = abi.encodePacked(r, s, v); + } + } + + { + vm.startBroadcast(); + IEmergencyUpgrageBoard emergencyUpgradeBoard = IEmergencyUpgrageBoard( + _protocolUpgradeHandler.emergencyUpgradeBoard() + ); + // solhint-disable-next-line func-named-parameters + emergencyUpgradeBoard.executeEmergencyUpgrade( + _calls, + _salt, + guardiansSignatures, + securityCouncilSignatures, + zkFoundationSignature + ); + vm.stopBroadcast(); + } + } } diff --git a/l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol b/l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol new file mode 100644 index 000000000..1f3d0d3d6 --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {IProtocolUpgradeHandler} from "./IProtocolUpgradeHandler.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IEmergencyUpgrageBoard { + function GUARDIANS() external view returns (address); + + function SECURITY_COUNCIL() external view returns (address); + + function ZK_FOUNDATION_SAFE() external view returns (address); + + function executeEmergencyUpgrade( + IProtocolUpgradeHandler.Call[] calldata _calls, + bytes32 _salt, + bytes calldata _guardiansSignatures, + bytes calldata _securityCouncilSignatures, + bytes calldata _zkFoundationSignatures + ) external; +} diff --git a/l1-contracts/deploy-scripts/interfaces/IMultisig.sol b/l1-contracts/deploy-scripts/interfaces/IMultisig.sol new file mode 100644 index 000000000..2a1dd955d --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/IMultisig.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IMultisig { + function members(uint256) external view returns (address); +} diff --git a/l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol b/l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol new file mode 100644 index 000000000..baa48f43f --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IProtocolUpgradeHandler { + /// @dev Represents a call to be made during an upgrade. + /// @param target The address to which the call will be made. + /// @param value The amount of Ether (in wei) to be sent along with the call. + /// @param data The calldata to be executed on the `target` address. + struct Call { + address target; + uint256 value; + bytes data; + } + + /// @dev Defines the structure of an upgrade that is executed by Protocol Upgrade Handler. + /// @param executor The L1 address that is authorized to perform the upgrade execution (if address(0) then anyone). + /// @param calls An array of `Call` structs, each representing a call to be made during the upgrade execution. + /// @param salt A bytes32 value used for creating unique upgrade proposal hashes. + struct UpgradeProposal { + Call[] calls; + address executor; + bytes32 salt; + } + + function emergencyUpgradeBoard() external view returns (address); + + function guardians() external view returns (address); + + function securityCouncil() external view returns (address); +} diff --git a/l1-contracts/deploy-scripts/interfaces/ISafe.sol b/l1-contracts/deploy-scripts/interfaces/ISafe.sol new file mode 100644 index 000000000..82877b3b3 --- /dev/null +++ b/l1-contracts/deploy-scripts/interfaces/ISafe.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface ISafe { + function getMessageHash(bytes memory _message) external view returns (bytes32); +} diff --git a/yarn.lock b/yarn.lock index 6ab96b427..66cd67b1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7931,3 +7931,10 @@ zksync-ethers@^5.9.0: integrity sha512-Y2Mx6ovvxO6UdC2dePLguVzvNToOY8iLWeq5ne+jgGSJxAi/f4He/NF6FNsf6x1aWX0o8dy4Df8RcOQXAkj5qw== dependencies: ethers "~5.7.0" + +zksync-web3@^0.15.4: + version "0.15.5" + resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.15.5.tgz#aabe379464963ab573e15948660a709f409b5316" + integrity sha512-97gB7OKJL4spegl8fGO54g6cvTd/75G6yFWZWEa2J09zhjTrfqabbwE/GwiUJkFQ5BbzoH4JaTlVz1hoYZI+DQ== + dependencies: + ethers "~5.7.0" From efa5d3b76d3cf7bb670ca13953787964cfa278a9 Mon Sep 17 00:00:00 2001 From: Zach Kolodny Date: Fri, 4 Oct 2024 10:25:56 -0400 Subject: [PATCH 10/54] remove whitespace from config --- l1-contracts/hardhat.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l1-contracts/hardhat.config.ts b/l1-contracts/hardhat.config.ts index 78208dd89..884dc43d3 100644 --- a/l1-contracts/hardhat.config.ts +++ b/l1-contracts/hardhat.config.ts @@ -5,7 +5,7 @@ import "hardhat-contract-sizer"; import "hardhat-gas-reporter"; import "hardhat-typechain"; import "solidity-coverage"; - + // If no network is specified, use the default config if (!process.env.CHAIN_ETH_NETWORK) { // eslint-disable-next-line @typescript-eslint/no-var-requires From 84d5e3716f645909e8144c7d50af9dd6dd9ded62 Mon Sep 17 00:00:00 2001 From: Danil Date: Fri, 4 Oct 2024 19:41:50 +0200 Subject: [PATCH 11/54] Update foundry bytecode (#764) Signed-off-by: Danil Co-authored-by: otani Co-authored-by: Zach Kolodny --- .github/workflows/build-release.yaml | 30 +- .github/workflows/l1-contracts-ci.yaml | 58 ++-- .github/workflows/l2-contracts-ci.yaml | 34 ++- .github/workflows/slither.yaml | 13 +- .github/workflows/system-contracts-ci.yaml | 66 ++--- l1-contracts/deploy-scripts/DeployErc20.s.sol | 2 +- .../deploy-scripts/DeployL2Contracts.sol | 40 ++- .../dev/SetupLegacyBridge.s.sol | 16 +- l1-contracts/script-config/.gitkeep | 0 .../script-config/artifacts/BeaconProxy.json | 81 ------ .../artifacts/L2SharedBridge.json | 262 ------------------ .../TransparentUpgradeableProxy.json | 86 ------ .../dev-contracts/DevL2SharedBridge.sol | 2 +- system-contracts/foundry.toml | 1 + system-contracts/scripts/calculate-hashes.ts | 8 +- .../scripts/preprocess-bootloader.ts | 34 ++- 16 files changed, 182 insertions(+), 551 deletions(-) create mode 100644 l1-contracts/script-config/.gitkeep delete mode 100644 l1-contracts/script-config/artifacts/BeaconProxy.json delete mode 100644 l1-contracts/script-config/artifacts/L2SharedBridge.json delete mode 100644 l1-contracts/script-config/artifacts/TransparentUpgradeableProxy.json diff --git a/.github/workflows/build-release.yaml b/.github/workflows/build-release.yaml index 2335b74fb..b4292e5e3 100644 --- a/.github/workflows/build-release.yaml +++ b/.github/workflows/build-release.yaml @@ -22,6 +22,15 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ inputs.commit }} + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -35,11 +44,24 @@ jobs: yarn echo "release_tag=${{ inputs.prefix }}-${{ inputs.commit }}" >> $GITHUB_OUTPUT - - name: Build contracts + - name: Build l1 contracts + working-directory: l1-contracts + run: | + forge build + + - name: Build l2 contracts + working-directory: l2-contracts + run: | + forge build --zksync --zk-enable-eravm-extensions + + - name: Build system-contracts + working-directory: system-contracts run: | - yarn l1 build - yarn l2 build - yarn sc build + yarn install + yarn preprocess:system-contracts + forge build --zksync --zk-enable-eravm-extensions + yarn preprocess:bootloader + forge build --zksync --zk-enable-eravm-extensions - name: Prepare artifacts run: | diff --git a/.github/workflows/l1-contracts-ci.yaml b/.github/workflows/l1-contracts-ci.yaml index fbf3cc770..5a27c65f8 100644 --- a/.github/workflows/l1-contracts-ci.yaml +++ b/.github/workflows/l1-contracts-ci.yaml @@ -15,6 +15,16 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -22,26 +32,25 @@ jobs: node-version: 18.18.0 cache: yarn - - name: Install dependencies - run: yarn - - - name: Build artifacts - run: yarn l1 build + - name: Build l1 contracts + working-directory: l1-contracts + run: | + forge build - - name: Build L2 artifacts - run: yarn l2 build + - name: Build l2 contracts + working-directory: l2-contracts + run: | + forge build --zksync --zk-enable-eravm-extensions - name: Create cache uses: actions/cache/save@v3 with: key: artifacts-l1-${{ github.sha }} path: | - l1-contracts/artifacts - l1-contracts/cache - l1-contracts/typechain - l2-contracts/artifacts-zk - l2-contracts/cache-zk - l2-contracts/typechain + l1-contracts/cache-forge + l1-contracts/out + l2-contracts/cache-forge + l2-contracts/zkout lint: runs-on: ubuntu-latest @@ -72,15 +81,19 @@ jobs: with: submodules: recursive - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - name: Use Node.js uses: actions/setup-node@v3 with: node-version: 18.18.0 cache: yarn + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Install dependencies run: yarn @@ -128,7 +141,7 @@ jobs: l2-contracts/typechain - name: Run tests - run: yarn l1 test --no-compile + run: yarn l1 test check-verifier-generator: runs-on: ubuntu-latest @@ -164,15 +177,20 @@ jobs: with: submodules: recursive - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - name: Use Node.js uses: actions/setup-node@v3 with: node-version: 18.18.0 cache: yarn + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH + - name: Install dependencies run: yarn diff --git a/.github/workflows/l2-contracts-ci.yaml b/.github/workflows/l2-contracts-ci.yaml index 20bb9583f..e19ac376b 100644 --- a/.github/workflows/l2-contracts-ci.yaml +++ b/.github/workflows/l2-contracts-ci.yaml @@ -10,6 +10,16 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -20,23 +30,25 @@ jobs: - name: Install dependencies run: yarn - - name: Build L1 artifacts - run: yarn l1 build + - name: Build l1 contracts + working-directory: l1-contracts + run: | + forge build - - name: Build L2 artifacts - run: yarn l2 build + - name: Build l2 contracts + working-directory: l2-contracts + run: | + forge build --zksync --zk-enable-eravm-extensions - name: Create cache uses: actions/cache/save@v3 with: - key: artifacts-l2-${{ github.sha }} + key: artifacts-l1-${{ github.sha }} path: | - l1-contracts/artifacts - l1-contracts/cache - l1-contracts/typechain - l2-contracts/artifacts-zk - l2-contracts/cache-zk - l2-contracts/typechain + l1-contracts/cache-forge + l1-contracts/out + l2-contracts/cache-forge + l2-contracts/zkout lint: runs-on: ubuntu-latest diff --git a/.github/workflows/slither.yaml b/.github/workflows/slither.yaml index fa253e159..50c9194dc 100644 --- a/.github/workflows/slither.yaml +++ b/.github/workflows/slither.yaml @@ -27,13 +27,18 @@ jobs: with: python-version: 3.8 + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH + - name: Install Slither run: | pip install slither-analyzer - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - name: Remove non-compiled files run: | rm -rf ./l1-contracts/contracts/state-transition/utils/ @@ -43,6 +48,6 @@ jobs: rm -rf ./l1-contracts/contracts/dev-contracts/test/VerifierRecursiveTest.sol - name: Run Slither + working-directory: l1-contracts run: | - cd l1-contracts slither --config ./slither.config.json . diff --git a/.github/workflows/system-contracts-ci.yaml b/.github/workflows/system-contracts-ci.yaml index f842214d6..d1338983e 100644 --- a/.github/workflows/system-contracts-ci.yaml +++ b/.github/workflows/system-contracts-ci.yaml @@ -10,6 +10,16 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -17,22 +27,28 @@ jobs: node-version: 18.18.0 cache: yarn - - name: Install dependencies - run: yarn - - name: Build artifacts - run: yarn sc build + working-directory: system-contracts + run: | + yarn install + yarn preprocess:system-contracts + forge build --zksync --zk-enable-eravm-extensions + yarn preprocess:bootloader + forge build --zksync --zk-enable-eravm-extensions + yarn build - name: Create cache uses: actions/cache/save@v3 with: key: artifacts-system-${{ github.sha }} path: | + system-contracts/zkout + system-contracts/cache-forge + system-contracts/bootloader/build system-contracts/artifacts-zk system-contracts/cache-zk system-contracts/typechain system-contracts/contracts-preprocessed - system-contracts/bootloader/build lint: runs-on: ubuntu-latest @@ -72,11 +88,13 @@ jobs: fail-on-cache-miss: true key: artifacts-system-${{ github.sha }} path: | + system-contracts/zkout + system-contracts/cache-forge + system-contracts/bootloader/build system-contracts/artifacts-zk system-contracts/cache-zk system-contracts/typechain system-contracts/contracts-preprocessed - system-contracts/bootloader/build - name: Run bootloader tests run: | @@ -111,11 +129,13 @@ jobs: fail-on-cache-miss: true key: artifacts-system-${{ github.sha }} path: | + system-contracts/zkout + system-contracts/cache-forge + system-contracts/bootloader/build system-contracts/artifacts-zk system-contracts/cache-zk system-contracts/typechain system-contracts/contracts-preprocessed - system-contracts/bootloader/build - name: Run tests run: yarn sc test @@ -123,35 +143,3 @@ jobs: - name: Print output logs of era_test_node if: always() run: cat era_test_node.log - - check-hashes: - needs: [build] - runs-on: ubuntu-latest - - steps: - - name: Checkout the repository - uses: actions/checkout@v4 - - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: 18.18.0 - cache: yarn - - - name: Install dependencies - run: yarn - - - name: Restore artifacts cache - uses: actions/cache/restore@v3 - with: - fail-on-cache-miss: true - key: artifacts-system-${{ github.sha }} - path: | - system-contracts/artifacts-zk - system-contracts/cache-zk - system-contracts/typechain - system-contracts/contracts-preprocessed - system-contracts/bootloader/build - - - name: Check hashes - run: yarn sc calculate-hashes:check diff --git a/l1-contracts/deploy-scripts/DeployErc20.s.sol b/l1-contracts/deploy-scripts/DeployErc20.s.sol index 60f34230a..9a7c9cfa9 100644 --- a/l1-contracts/deploy-scripts/DeployErc20.s.sol +++ b/l1-contracts/deploy-scripts/DeployErc20.s.sol @@ -83,7 +83,7 @@ contract DeployErc20Script is Script { function deployTokens() internal { uint256 tokensLength = config.tokens.length; for (uint256 i = 0; i < tokensLength; ++i) { - TokenDescription memory token = config.tokens[i]; + TokenDescription storage token = config.tokens[i]; console.log("Deploying token:", token.name); address tokenAddress = deployErc20({ name: token.name, diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 80b458f82..4578f1717 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -121,43 +121,41 @@ contract DeployL2Script is Script { function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat - contracts.l2StandardErc20FactoryBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" + contracts.l2StandardErc20FactoryBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/UpgradeableBeacon.sol/UpgradeableBeacon.json" ); - contracts.beaconProxy = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" - ); - contracts.l2StandardErc20Bytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" + contracts.beaconProxy = Utils.readFoundryBytecode("/../l2-contracts/zkout/BeaconProxy.sol/BeaconProxy.json"); + contracts.l2StandardErc20Bytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2StandardERC20.sol/L2StandardERC20.json" ); if (legacyBridge) { - contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/dev-contracts/DevL2SharedBridge.sol/DevL2SharedBridge.json" + contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/DevL2SharedBridge.sol/DevL2SharedBridge.json" ); } else { - contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2SharedBridge.sol/L2SharedBridge.json" + contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2SharedBridge.sol/L2SharedBridge.json" ); } - contracts.l2SharedBridgeProxyBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" + contracts.l2SharedBridgeProxyBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); - contracts.consensusRegistryBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/ConsensusRegistry.sol/ConsensusRegistry.json" + contracts.consensusRegistryBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/ConsensusRegistry.sol/ConsensusRegistry.json" ); - contracts.consensusRegistryProxyBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" + contracts.consensusRegistryProxyBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); - contracts.multicall3Bytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/dev-contracts/Multicall3.sol/Multicall3.json" + contracts.multicall3Bytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/Multicall3.sol/Multicall3.json" ); - contracts.forceDeployUpgrader = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" + contracts.forceDeployUpgrader = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" ); } diff --git a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol index e178824b1..518005915 100644 --- a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol +++ b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol @@ -6,8 +6,8 @@ import {stdToml} from "forge-std/StdToml.sol"; import {Utils} from "./../Utils.sol"; import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {DummyL1ERC20Bridge} from "contracts/dev-contracts/DummyL1ERC20Bridge.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; /// This scripts is only for developer @@ -112,8 +112,8 @@ contract SetupLegacyBridge is Script { internal returns (address tokenBeaconAddress, bytes32 tokenBeaconBytecodeHash) { - bytes memory l2StandardTokenCode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" + bytes memory l2StandardTokenCode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2StandardERC20.sol/L2StandardERC20.json" ); (address l2StandardToken, ) = calculateL2Create2Address( config.l2SharedBridgeAddress, @@ -122,13 +122,11 @@ contract SetupLegacyBridge is Script { "" ); - bytes memory beaconProxy = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" - ); + bytes memory beaconProxy = Utils.readFoundryBytecode("/../l2-contracts/zkout/BeaconProxy.sol/BeaconProxy.json"); tokenBeaconBytecodeHash = L2ContractHelper.hashL2Bytecode(beaconProxy); - bytes memory upgradableBeacon = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" + bytes memory upgradableBeacon = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/UpgradeableBeacon.sol/UpgradeableBeacon.json" ); (tokenBeaconAddress, ) = calculateL2Create2Address( diff --git a/l1-contracts/script-config/.gitkeep b/l1-contracts/script-config/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/l1-contracts/script-config/artifacts/BeaconProxy.json b/l1-contracts/script-config/artifacts/BeaconProxy.json deleted file mode 100644 index 258780377..000000000 --- a/l1-contracts/script-config/artifacts/BeaconProxy.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "_format": "hh-zksolc-artifact-1", - "contractName": "BeaconProxy", - "sourceName": "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "beacon", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x0004000000000002000700000000000200000000030100190000006003300270000001020030019d0000010203300197000300000031035500020000000103550000008008000039000000400080043f00000001022001900000001c0000c13d000000000131034f0000010d02000041000000000202041a0000010b04000041000000800040043f00000106022001970000000004000414000000000303004b000000250000c13d000000040320008c000000ab0000c13d0000000103000031000000200230008c00000000040300190000002004008039000000d60000013d0000010302300041000001040220009c0000002c0000213d0000011d0100004100000000001004350000004101000039000000040010043f0000011e010000410000040400010430000000040320008c000001160000c13d0000000103000031000000200230008c00000000040300190000002004008039000001410000013d0000009f023000390000010502200197000000400020043f0000001f0230018f00000005043002720000003b0000613d00000000050000190000000506500210000000000761034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000330000413d000000000502004b0000004a0000613d0000000504400210000000000141034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f00000000001404350000003f0130008c0000014a0000a13d000000800a00043d0000010601a0009c0000014a0000213d000000a00200043d000001070120009c0000014a0000213d0000001f012000390000010804000041000000000531004b000000000500001900000000050480190000010801100197000000000601004b0000000004008019000001080110009c000000000405c019000000000104004b0000014a0000c13d00000080012000390000000001010433000001070410009c0000001f0000213d0000003f04100039000000200700008a000000000474016f000000400900043d0000000004490019000000000594004b00000000050000190000000105004039000001070640009c0000001f0000213d00000001055001900000001f0000c13d0000008003300039000000400040043f0000000006190436000000a0022000390000000004210019000000000334004b0000014a0000213d000600000009001d000500000007001d000400000008001d000000000301004b000000820000613d000000000300001900000000046300190000000005230019000000000505043300000000005404350000002003300039000000000413004b0000007b0000413d000300000006001d000000000116001900000000000104350000010901000041000000000010043900070000000a001d0000000400a0044300000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010a011001c70000800202000039040203f80000040f0000000102200190000003db0000613d000000400a00043d000000000101043b000000000101004b000002200000c13d0000006401a000390000011b0200004100000000002104350000004401a000390000011c0200004100000000002104350000002401a0003900000025020000390000000000210435000001150100004100000000001a04350000000401a000390000002002000039000000000021043500000102010000410000010202a0009c000000000a0180190000004001a002100000011a011001c700000404000104300000010201000041000001020340009c0000000004018019000000c0014002100000011f011001c7040203f80000040f000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000000c30000613d00000000070000190000000508700210000000000981034f000000000909043b000000800880003900000000009804350000000107700039000000000867004b000000bb0000413d000000000705004b000000d20000613d0000000506600210000000000761034f00000003055002100000008006600039000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f000300000001035500000001022001900000014c0000613d0000009f02400039000000e00220018f000000400020043f000000200230008c0000014a0000413d000000800200043d000001060420009c0000014a0000213d000000020500036700000000040000310000001f0740018f0000000506400272000000eb0000613d00000000080000190000000509800210000000000a95034f000000000a0a043b0000000000a904350000000108800039000000000968004b000000e40000413d000000000807004b000000f90000613d00000003077002100000000506600210000000000806043300000000087801cf000000000878022f000000000565034f000000000505043b0000010007700089000000000575022f00000000057501cf000000000585019f00000000005604350000000005000414000000040620008c000001c40000c13d0000001f0430018f0000000502300272000001070000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000625004b000001000000413d000000000504004b000001ed0000613d00000003044002100000000502200210000000000502043300000000054501cf000000000545022f000000000121034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000001ed0000013d0000010201000041000001020340009c0000000004018019000000c0014002100000011f011001c7040203f80000040f000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f00000005064002720000012e0000613d00000000070000190000000508700210000000000981034f000000000909043b000000800880003900000000009804350000000107700039000000000867004b000001260000413d000000000705004b0000013d0000613d0000000506600210000000000761034f00000003055002100000008006600039000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000001690000613d0000001f02400039000000600220018f00000080022001bf000000400020043f000000200230008c0000014a0000413d000000800200043d000001060420009c0000018c0000a13d00000000010000190000040400010430000000400200043d0000001f0430018f0000000505300272000001590000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000001510000413d000000000604004b000001680000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001850000013d000000400200043d0000001f0430018f0000000505300272000001760000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000016e0000413d000000000604004b000001850000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000010201000041000001020420009c000000000201801900000040012002100000006002300210000000000121019f0000040400010430000000020500036700000000040000310000001f0740018f0000000506400272000001990000613d00000000080000190000000509800210000000000a95034f000000000a0a043b0000000000a904350000000108800039000000000968004b000001920000413d000000000807004b000001a70000613d00000003077002100000000506600210000000000806043300000000087801cf000000000878022f000000000565034f000000000505043b0000010007700089000000000575022f00000000057501cf000000000585019f00000000005604350000000005000414000000040620008c000001ee0000c13d0000001f0430018f0000000502300272000001b50000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000625004b000001ae0000413d000000000504004b000002170000613d00000003044002100000000502200210000000000502043300000000054501cf000000000545022f000000000121034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000002170000013d0000010201000041000001020350009c0000000005018019000001020340009c00000000040180190000006001400210000000c003500210000000000113019f040203fd0000040f0003000000010355000000000301001900000060033002700000001f0430018f000101020030019d00000102033001970000000505300272000001dd0000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b000001d60000413d000000000604004b000001eb0000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f000000000015043500000001012001900000021c0000613d000002170000013d0000010201000041000001020350009c0000000005018019000001020340009c00000000040180190000006001400210000000c003500210000000000113019f040203fd0000040f0003000000010355000000000301001900000060033002700000001f0430018f000101020030019d00000102033001970000000505300272000002070000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b000002000000413d000000000604004b000002150000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f000000000015043500000001012001900000021e0000613d0000010201000041000001020230009c00000000030180190000006001300210000004030001042e00000060013002100000040400010430000000600130021000000404000104300000010b0100004100000000001a0435000000000100041400000007020000290000010602200197000000040320008c000700000002001d0000022d0000c13d0000000103000031000000200130008c000000000403001900000020040080390000025e0000013d0000010204000041000001020310009c00000000010480190000010203a0009c00000000040a40190000004003400210000000c001100210000000000131019f0000010c011001c700020000000a001d040203f80000040f000000020a000029000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f00000005064002720000024b0000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000002430000413d000000000705004b0000025a0000613d0000000506600210000000000761034f00000000066a00190000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000002950000613d0000001f01400039000000600210018f0000000001a20019000000000221004b00000000020000190000000102004039000001070410009c0000001f0000213d00000001022001900000001f0000c13d000000400010043f000000200130008c0000014a0000413d00000000010a0433000001060210009c0000014a0000213d00000109020000410000000000200439000000040010044300000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010a011001c70000800202000039040203f80000040f0000000102200190000003db0000613d000000400200043d000200000002001d000000000101043b000000000101004b000002b20000c13d0000000203000029000000640130003900000118020000410000000000210435000000440130003900000119020000410000000000210435000000240130003900000030020000390000000000210435000001150100004100000000001304350000000401300039000000200200003900000000002104350000010201000041000001020230009c000000000301801900000040013002100000011a011001c70000040400010430000000400200043d0000001f0430018f0000000505300272000002a20000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000029a0000413d000000000604004b000001850000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001850000013d0000010d01000041000000000201041a0000010e022001970000000705000029000000000252019f000000000021041b00000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010f011001c70000800d0200003900000002030000390000011004000041040203f30000040f000000010120019000000006010000290000014a0000613d0000000001010433000000000101004b000002cd0000c13d0000002001000039000001000010044300000120000004430000011701000041000004030001042e0000010b010000410000000202000029000000000012043500000000010004140000000702000029000000040220008c000002d90000c13d0000000103000031000000200130008c000000000403001900000020040080390000030b0000013d0000010202000041000001020310009c00000000010280190000000204000029000001020340009c00000000020440190000004002200210000000c001100210000000000121019f0000010c011001c70000000702000029040203f80000040f000000020a000029000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000002f80000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000002f00000413d000000000705004b000003070000613d0000000506600210000000000761034f00000002066000290000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000003380000613d0000001f01400039000000600110018f0000000202100029000000000112004b00000000010000190000000101004039000700000002001d000001070220009c00000006040000290000001f0000213d00000001011001900000001f0000c13d0000000701000029000000400010043f000000200130008c0000014a0000413d00000002010000290000000001010433000200000001001d000001060110009c0000014a0000213d0000000701000029000001110110009c0000001f0000213d00000007050000290000006001500039000000400010043f000000400150003900000112020000410000000000210435000000270100003900000000021504360000011301000041000100000002001d0000000000120435000000000204043300000000010004140000000204000029000000040440008c000003550000c13d0000000102000039000001070130009c00000005050000290000001f0000213d0000036d0000013d000000400200043d0000001f0430018f0000000505300272000003450000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000033d0000413d000000000604004b000003540000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001850000013d00000102030000410000000305000029000001020450009c00000000050380190000004004500210000001020520009c00000000020380190000006002200210000000000242019f000001020410009c0000000001038019000000c001100210000000000121019f0000000202000029040203fd0000040f0000006004000039000000010220018f00030000000103550000006001100270000101020010019d000001020310019800000004090000290000000505000029000003960000613d0000003f01300039000000000151016f000000400400043d0000000001140019000000000541004b00000000050000190000000105004039000001070610009c0000001f0000213d00000001055001900000001f0000c13d000000400010043f0000001f0130018f000000000934043600000003050003670000000503300272000003870000613d000000000600001900000005076002100000000008790019000000000775034f000000000707043b00000000007804350000000106600039000000000736004b0000037f0000413d000000000601004b000003960000613d0000000503300210000000000535034f00000000033900190000000301100210000000000603043300000000061601cf000000000616022f000000000505043b0000010001100089000000000515022f00000000011501cf000000000161019f00000000001304350000000001040433000000000202004b000003b60000c13d000000000201004b000003dc0000c13d000000400400043d000600000004001d0000011501000041000000000014043500000004014000390000002002000039000000000021043500000007010000290000000003010433000700000003001d0000002401400039000000000031043500000044024000390000000101000029040203e50000040f00000007010000290000001f01100039000000050110017f00000044011000390000010202000041000001020310009c00000000010280190000000604000029000001020340009c00000000040280190000004002400210000003e20000013d000000000101004b000002c80000c13d000001090100004100000000001004390000000201000029000000040010044300000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010a011001c70000800202000039040203f80000040f0000000102200190000003db0000613d000000000101043b000000000101004b000002c80000c13d000000400100043d00000044021000390000011403000041000000000032043500000024021000390000001d030000390000000000320435000001150200004100000000002104350000000402100039000000200300003900000000003204350000010202000041000001020310009c0000000001028019000000400110021000000116011001c70000040400010430000000000001042f0000010202000041000001020310009c0000000001028019000001020390009c000000000902801900000040029002100000006001100210000000000121019f0000040400010430000000000403004b000003ef0000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000534004b000003e80000413d00000000012300190000000000010435000000000001042d000000000001042f000003f6002104210000000102000039000000000001042d0000000002000019000000000001042d000003fb002104230000000102000039000000000001042d0000000002000019000000000001042d00000400002104250000000102000039000000000001042d0000000002000019000000000001042d0000040200000432000004030001042e000004040001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009fffffffffffffffffffffffffffffffffffffffffffffffff000000000000007f00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff80000000000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8302000002000000000000000000000000000000240000000000000000000000005c60da1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000a3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e000000000000000000000000000000000000000000000000ffffffffffffff9f206661696c656400000000000000000000000000000000000000000000000000416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000008c379a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000020000000000000000000000000000004000000100000000000000000073206e6f74206120636f6e747261637400000000000000000000000000000000455243313936373a20626561636f6e20696d706c656d656e746174696f6e206900000000000000000000000000000000000000840000000000000000000000007472616374000000000000000000000000000000000000000000000000000000455243313936373a206e657720626561636f6e206973206e6f74206120636f6e4e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000004000000800000000000000000d32177e88b033622e0bc848f24ab73d0795ed87730981120fcdf94fbc134fa5d", - "deployedBytecode": "0x0004000000000002000700000000000200000000030100190000006003300270000001020030019d0000010203300197000300000031035500020000000103550000008008000039000000400080043f00000001022001900000001c0000c13d000000000131034f0000010d02000041000000000202041a0000010b04000041000000800040043f00000106022001970000000004000414000000000303004b000000250000c13d000000040320008c000000ab0000c13d0000000103000031000000200230008c00000000040300190000002004008039000000d60000013d0000010302300041000001040220009c0000002c0000213d0000011d0100004100000000001004350000004101000039000000040010043f0000011e010000410000040400010430000000040320008c000001160000c13d0000000103000031000000200230008c00000000040300190000002004008039000001410000013d0000009f023000390000010502200197000000400020043f0000001f0230018f00000005043002720000003b0000613d00000000050000190000000506500210000000000761034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000330000413d000000000502004b0000004a0000613d0000000504400210000000000141034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f00000000001404350000003f0130008c0000014a0000a13d000000800a00043d0000010601a0009c0000014a0000213d000000a00200043d000001070120009c0000014a0000213d0000001f012000390000010804000041000000000531004b000000000500001900000000050480190000010801100197000000000601004b0000000004008019000001080110009c000000000405c019000000000104004b0000014a0000c13d00000080012000390000000001010433000001070410009c0000001f0000213d0000003f04100039000000200700008a000000000474016f000000400900043d0000000004490019000000000594004b00000000050000190000000105004039000001070640009c0000001f0000213d00000001055001900000001f0000c13d0000008003300039000000400040043f0000000006190436000000a0022000390000000004210019000000000334004b0000014a0000213d000600000009001d000500000007001d000400000008001d000000000301004b000000820000613d000000000300001900000000046300190000000005230019000000000505043300000000005404350000002003300039000000000413004b0000007b0000413d000300000006001d000000000116001900000000000104350000010901000041000000000010043900070000000a001d0000000400a0044300000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010a011001c70000800202000039040203f80000040f0000000102200190000003db0000613d000000400a00043d000000000101043b000000000101004b000002200000c13d0000006401a000390000011b0200004100000000002104350000004401a000390000011c0200004100000000002104350000002401a0003900000025020000390000000000210435000001150100004100000000001a04350000000401a000390000002002000039000000000021043500000102010000410000010202a0009c000000000a0180190000004001a002100000011a011001c700000404000104300000010201000041000001020340009c0000000004018019000000c0014002100000011f011001c7040203f80000040f000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000000c30000613d00000000070000190000000508700210000000000981034f000000000909043b000000800880003900000000009804350000000107700039000000000867004b000000bb0000413d000000000705004b000000d20000613d0000000506600210000000000761034f00000003055002100000008006600039000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f000300000001035500000001022001900000014c0000613d0000009f02400039000000e00220018f000000400020043f000000200230008c0000014a0000413d000000800200043d000001060420009c0000014a0000213d000000020500036700000000040000310000001f0740018f0000000506400272000000eb0000613d00000000080000190000000509800210000000000a95034f000000000a0a043b0000000000a904350000000108800039000000000968004b000000e40000413d000000000807004b000000f90000613d00000003077002100000000506600210000000000806043300000000087801cf000000000878022f000000000565034f000000000505043b0000010007700089000000000575022f00000000057501cf000000000585019f00000000005604350000000005000414000000040620008c000001c40000c13d0000001f0430018f0000000502300272000001070000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000625004b000001000000413d000000000504004b000001ed0000613d00000003044002100000000502200210000000000502043300000000054501cf000000000545022f000000000121034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000001ed0000013d0000010201000041000001020340009c0000000004018019000000c0014002100000011f011001c7040203f80000040f000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f00000005064002720000012e0000613d00000000070000190000000508700210000000000981034f000000000909043b000000800880003900000000009804350000000107700039000000000867004b000001260000413d000000000705004b0000013d0000613d0000000506600210000000000761034f00000003055002100000008006600039000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000001690000613d0000001f02400039000000600220018f00000080022001bf000000400020043f000000200230008c0000014a0000413d000000800200043d000001060420009c0000018c0000a13d00000000010000190000040400010430000000400200043d0000001f0430018f0000000505300272000001590000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000001510000413d000000000604004b000001680000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001850000013d000000400200043d0000001f0430018f0000000505300272000001760000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000016e0000413d000000000604004b000001850000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000010201000041000001020420009c000000000201801900000040012002100000006002300210000000000121019f0000040400010430000000020500036700000000040000310000001f0740018f0000000506400272000001990000613d00000000080000190000000509800210000000000a95034f000000000a0a043b0000000000a904350000000108800039000000000968004b000001920000413d000000000807004b000001a70000613d00000003077002100000000506600210000000000806043300000000087801cf000000000878022f000000000565034f000000000505043b0000010007700089000000000575022f00000000057501cf000000000585019f00000000005604350000000005000414000000040620008c000001ee0000c13d0000001f0430018f0000000502300272000001b50000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000625004b000001ae0000413d000000000504004b000002170000613d00000003044002100000000502200210000000000502043300000000054501cf000000000545022f000000000121034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000002170000013d0000010201000041000001020350009c0000000005018019000001020340009c00000000040180190000006001400210000000c003500210000000000113019f040203fd0000040f0003000000010355000000000301001900000060033002700000001f0430018f000101020030019d00000102033001970000000505300272000001dd0000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b000001d60000413d000000000604004b000001eb0000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f000000000015043500000001012001900000021c0000613d000002170000013d0000010201000041000001020350009c0000000005018019000001020340009c00000000040180190000006001400210000000c003500210000000000113019f040203fd0000040f0003000000010355000000000301001900000060033002700000001f0430018f000101020030019d00000102033001970000000505300272000002070000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b000002000000413d000000000604004b000002150000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f000000000015043500000001012001900000021e0000613d0000010201000041000001020230009c00000000030180190000006001300210000004030001042e00000060013002100000040400010430000000600130021000000404000104300000010b0100004100000000001a0435000000000100041400000007020000290000010602200197000000040320008c000700000002001d0000022d0000c13d0000000103000031000000200130008c000000000403001900000020040080390000025e0000013d0000010204000041000001020310009c00000000010480190000010203a0009c00000000040a40190000004003400210000000c001100210000000000131019f0000010c011001c700020000000a001d040203f80000040f000000020a000029000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f00000005064002720000024b0000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000002430000413d000000000705004b0000025a0000613d0000000506600210000000000761034f00000000066a00190000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000002950000613d0000001f01400039000000600210018f0000000001a20019000000000221004b00000000020000190000000102004039000001070410009c0000001f0000213d00000001022001900000001f0000c13d000000400010043f000000200130008c0000014a0000413d00000000010a0433000001060210009c0000014a0000213d00000109020000410000000000200439000000040010044300000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010a011001c70000800202000039040203f80000040f0000000102200190000003db0000613d000000400200043d000200000002001d000000000101043b000000000101004b000002b20000c13d0000000203000029000000640130003900000118020000410000000000210435000000440130003900000119020000410000000000210435000000240130003900000030020000390000000000210435000001150100004100000000001304350000000401300039000000200200003900000000002104350000010201000041000001020230009c000000000301801900000040013002100000011a011001c70000040400010430000000400200043d0000001f0430018f0000000505300272000002a20000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000029a0000413d000000000604004b000001850000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001850000013d0000010d01000041000000000201041a0000010e022001970000000705000029000000000252019f000000000021041b00000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010f011001c70000800d0200003900000002030000390000011004000041040203f30000040f000000010120019000000006010000290000014a0000613d0000000001010433000000000101004b000002cd0000c13d0000002001000039000001000010044300000120000004430000011701000041000004030001042e0000010b010000410000000202000029000000000012043500000000010004140000000702000029000000040220008c000002d90000c13d0000000103000031000000200130008c000000000403001900000020040080390000030b0000013d0000010202000041000001020310009c00000000010280190000000204000029000001020340009c00000000020440190000004002200210000000c001100210000000000121019f0000010c011001c70000000702000029040203f80000040f000000020a000029000000000301001900000060033002700000010203300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000002f80000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000002f00000413d000000000705004b000003070000613d0000000506600210000000000761034f00000002066000290000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000003380000613d0000001f01400039000000600110018f0000000202100029000000000112004b00000000010000190000000101004039000700000002001d000001070220009c00000006040000290000001f0000213d00000001011001900000001f0000c13d0000000701000029000000400010043f000000200130008c0000014a0000413d00000002010000290000000001010433000200000001001d000001060110009c0000014a0000213d0000000701000029000001110110009c0000001f0000213d00000007050000290000006001500039000000400010043f000000400150003900000112020000410000000000210435000000270100003900000000021504360000011301000041000100000002001d0000000000120435000000000204043300000000010004140000000204000029000000040440008c000003550000c13d0000000102000039000001070130009c00000005050000290000001f0000213d0000036d0000013d000000400200043d0000001f0430018f0000000505300272000003450000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000033d0000413d000000000604004b000003540000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001850000013d00000102030000410000000305000029000001020450009c00000000050380190000004004500210000001020520009c00000000020380190000006002200210000000000242019f000001020410009c0000000001038019000000c001100210000000000121019f0000000202000029040203fd0000040f0000006004000039000000010220018f00030000000103550000006001100270000101020010019d000001020310019800000004090000290000000505000029000003960000613d0000003f01300039000000000151016f000000400400043d0000000001140019000000000541004b00000000050000190000000105004039000001070610009c0000001f0000213d00000001055001900000001f0000c13d000000400010043f0000001f0130018f000000000934043600000003050003670000000503300272000003870000613d000000000600001900000005076002100000000008790019000000000775034f000000000707043b00000000007804350000000106600039000000000736004b0000037f0000413d000000000601004b000003960000613d0000000503300210000000000535034f00000000033900190000000301100210000000000603043300000000061601cf000000000616022f000000000505043b0000010001100089000000000515022f00000000011501cf000000000161019f00000000001304350000000001040433000000000202004b000003b60000c13d000000000201004b000003dc0000c13d000000400400043d000600000004001d0000011501000041000000000014043500000004014000390000002002000039000000000021043500000007010000290000000003010433000700000003001d0000002401400039000000000031043500000044024000390000000101000029040203e50000040f00000007010000290000001f01100039000000050110017f00000044011000390000010202000041000001020310009c00000000010280190000000604000029000001020340009c00000000040280190000004002400210000003e20000013d000000000101004b000002c80000c13d000001090100004100000000001004390000000201000029000000040010044300000102010000410000000002000414000001020320009c0000000002018019000000c0012002100000010a011001c70000800202000039040203f80000040f0000000102200190000003db0000613d000000000101043b000000000101004b000002c80000c13d000000400100043d00000044021000390000011403000041000000000032043500000024021000390000001d030000390000000000320435000001150200004100000000002104350000000402100039000000200300003900000000003204350000010202000041000001020310009c0000000001028019000000400110021000000116011001c70000040400010430000000000001042f0000010202000041000001020310009c0000000001028019000001020390009c000000000902801900000040029002100000006001100210000000000121019f0000040400010430000000000403004b000003ef0000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000534004b000003e80000413d00000000012300190000000000010435000000000001042d000000000001042f000003f6002104210000000102000039000000000001042d0000000002000019000000000001042d000003fb002104230000000102000039000000000001042d0000000002000019000000000001042d00000400002104250000000102000039000000000001042d0000000002000019000000000001042d0000040200000432000004030001042e000004040001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009fffffffffffffffffffffffffffffffffffffffffffffffff000000000000007f00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff80000000000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8302000002000000000000000000000000000000240000000000000000000000005c60da1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000a3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e000000000000000000000000000000000000000000000000ffffffffffffff9f206661696c656400000000000000000000000000000000000000000000000000416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000008c379a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000020000000000000000000000000000004000000100000000000000000073206e6f74206120636f6e747261637400000000000000000000000000000000455243313936373a20626561636f6e20696d706c656d656e746174696f6e206900000000000000000000000000000000000000840000000000000000000000007472616374000000000000000000000000000000000000000000000000000000455243313936373a206e657720626561636f6e206973206e6f74206120636f6e4e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000004000000800000000000000000d32177e88b033622e0bc848f24ab73d0795ed87730981120fcdf94fbc134fa5d", - "linkReferences": {}, - "deployedLinkReferences": {}, - "factoryDeps": {} -} diff --git a/l1-contracts/script-config/artifacts/L2SharedBridge.json b/l1-contracts/script-config/artifacts/L2SharedBridge.json deleted file mode 100644 index a74e5c9ad..000000000 --- a/l1-contracts/script-config/artifacts/L2SharedBridge.json +++ /dev/null @@ -1,262 +0,0 @@ -{ - "_format": "hh-zksolc-artifact-1", - "contractName": "L2SharedBridge", - "sourceName": "contracts/bridge/L2SharedBridge.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_eraChainId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l1Sender", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "l2Receiver", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "l2Token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "FinalizeDeposit", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l2Sender", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "l1Receiver", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "l2Token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "WithdrawalInitiated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1Sender", - "type": "address" - }, - { - "internalType": "address", - "name": "_l2Receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "_l1Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "finalizeDeposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1SharedBridge", - "type": "address" - }, - { - "internalType": "address", - "name": "_l1Bridge", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "_l2TokenProxyBytecodeHash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "_aliasedOwner", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "l1Bridge", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1SharedBridge", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "l2TokenAddress", - "type": "address" - } - ], - "name": "l1TokenAddress", - "outputs": [ - { - "internalType": "address", - "name": "l1TokenAddress", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1Token", - "type": "address" - } - ], - "name": "l2TokenAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l2TokenBeacon", - "outputs": [ - { - "internalType": "contract UpgradeableBeacon", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1Receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "_l2Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x0004000000000002001000000000000200000000030100190000006004300270000001a20340019700030000003103550002000000010355000001a20040019d00000001022001900000001d0000c13d0000008002000039000000400020043f000000040230008c000000400000413d000000000201043b000000e002200270000001ab0420009c000000420000213d000001b10420009c0000008a0000213d000001b40120009c000000c10000613d000001b50120009c000000400000c13d0000000001000416000000000101004b000000400000c13d0000000401000039000001d90000013d0000000002000416000000000202004b000000400000c13d000000bf02300039000001a302200197000000400020043f0000001f0230018f00000005043002720000002f0000613d00000000050000190000000506500210000000000761034f000000000707043b000000a00660003900000000007604350000000105500039000000000645004b000000270000413d000000000502004b0000003e0000613d0000000504400210000000000141034f0000000302200210000000a004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f0000000000140435000000200130008c000000640000813d00000000010000190000068300010430000001ac0420009c000000940000213d000001af0420009c000000c60000613d000001b00220009c000000400000c13d0000000002000416000000000202004b000000400000c13d000000040230008a000000600220008c000000400000413d0000000402100370000000000402043b000001b60240009c000000400000213d0000002402100370000000000302043b000001b60230009c000000400000213d0000004401100370000000000201043b000000000102004b000001de0000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f000001c501000041000000c40010043f000001c6010000410000068300010430000000a00100043d000000800010043f000000000200041a0000ff0003200190000000ac0000c13d000000ff0320018f000000ff0330008c000000820000613d000000ff012001bf000000000010041b000000ff01000039000000400200043d0000000000120435000001a2010000410000000003000414000001a20430009c0000000003018019000001a20420009c00000000020180190000004001200210000000c002300210000000000112019f000001a8011001c70000800d020000390000000103000039000001a904000041068106770000040f0000000101200190000000400000613d000000800100043d000001400000044300000160001004430000002001000039000001000010044300000001010000390000012000100443000001aa01000041000006820001042e000001b20420009c000001a50000613d000001b30120009c000000400000c13d0000000001000416000000000101004b000000400000c13d000000000100041a0000001001100270000001da0000013d000001ad0420009c000001c90000613d000001ae0220009c000000400000c13d0000000002000416000000000202004b000000400000c13d000000040230008a000000200220008c000000400000413d0000000401100370000000000101043b000001b60210009c000000400000213d068106050000040f000001b601100197000000400200043d0000000000120435000001a201000041000001a20320009c00000000020180190000004001200210000001b7011001c7000006820001042e000000400100043d0000006402100039000001a40300004100000000003204350000004402100039000001a5030000410000000000320435000000240210003900000027030000390000000000320435000001a6020000410000000000210435000000040210003900000020030000390000000000320435000001a202000041000001a20310009c00000000010280190000004001100210000001a7011001c700000683000104300000000001000416000000000101004b000000400000c13d0000000101000039000001d90000013d0000000002000416000000000202004b000000400000c13d000000040230008a000000a00220008c000000400000413d0000000402100370000000000802043b000001b60280009c000000400000213d0000002402100370000000000902043b000001b60290009c000000400000213d0000004402100370000000000a02043b000001b602a0009c000000400000213d0000008402100370000000000202043b000001bd0420009c000000400000213d0000002304200039000001c705000041000000000634004b00000000060000190000000006058019000001c704400197000000000704004b0000000005008019000001c70440009c000000000506c019000000000405004b000000400000c13d0000000404200039000000000441034f000000000504043b000001bd0450009c000000400000213d001000240020003d0000001002500029000000000232004b000000400000213d000b00000005001d000f0000000a001d000e00000009001d000c00000008001d0000006401100370000000000101043b000d00000001001d0000000001000411000001c801100041000001b6011001970000000402000039000000000202041a000001b602200197000000000221004b000001050000613d000000000200041a0000001002200270000001b602200197000000000121004b000002c10000c13d0000000101000039000800000001001d000000000101041a000001b601100197000000a00010043f0000004001000039000900000001001d000000c00010043f000000e00000043f0000006001000039000a00000001001d000000800010043f0000010001000039000000400010043f000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ca011001c700008010020000390681067c0000040f00000001022001900000000f05000029000000400000613d0000000202000039000700000002001d000000000202041a000000000301043b000000400100043d000000a004100039000000000034043500000080031000390000000000230435000000600210003900000000005204350000004002100039000000000300041000000000003204350000002002100039000001cb030000410000000000320435000000a0030000390000000000310435000001cc0310009c000002170000213d000000c003100039000000400030043f000001a204000041000001a20320009c000000000204801900000040022002100000000001010433000001a20310009c00000000010480190000006001100210000000000121019f0000000002000414000001a20320009c0000000002048019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f0000000102200190000000400000613d000000000101043b000500000001001d000001b601100197000600000001001d00000000001004350000000301000039000400000001001d000000200010043f0000000001000414000001a20210009c000001a201008041000000c001100210000001be011001c700008010020000390681067c0000040f0000000102200190000000400000613d000000000101043b000000000101041a000001b601100198000003ad0000c13d00000000010004140000000702000029000000000402041a0000000802000029000000000202041a000000400300043d000000400530003900000009060000290000000000650435000001b602200197000000200530003900000000002504350000000a02000029000000000023043500000060023000390000000000020435000001c00230009c000002170000213d0000008002300039000000400020043f000000a005300039000001cf060000410000000000650435000000e4053000390000000a060000290000000000650435000000c4053000390000000000450435000000a4043000390000000f0500002900000000005404350000010405300039000000000403043300000000004504350000012405300039000000000604004b0000018a0000613d000000000600001900000000075600190000002006600039000000000836001900000000080804330000000000870435000000000746004b000001830000413d000000000354001900000000000304350000001f03400039000a0020000000920000000a0330017f00000084043000390000000000420435000000c3033000390000000a0430017f0000000003240019000000000443004b00000000040000190000000104004039000001bd0530009c000002170000213d0000000104400190000002170000c13d000000400030043f0000000004020433000001d00540009c0000045f0000413d0000004401300039000001dc02000041000000000021043500000024013000390000000802000039000002b50000013d0000000002000416000000000202004b000000400000c13d000000040230008a000000800220008c000000400000413d0000000402100370000000000202043b000001b60320009c000000400000213d0000002403100370000000000603043b000001b60360009c000000400000213d0000006403100370000000000503043b000001b60350009c000000400000213d000000000300041a0000fffe043001900000021d0000c13d000001e00330019700000102033001bf000000000030041b0000004401100370000000000401043b000000000102004b000002290000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001f501000041000000610000013d0000000002000416000000000202004b000000400000c13d000000040230008a000000200220008c000000400000413d0000000401100370000000000101043b000001b60210009c000000400000213d00000000001004350000000301000039000000200010043f00000040020000390000000001000019068106610000040f000000000101041a000001b601100197000000800010043f000001b801000041000006820001042e000f00000002001d000e00000004001d000001b9010000410000000000100439001000000003001d0000000400300443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000001004000029000000400000613d000000400500043d00000024015000390000000f020000290000000000210435000001bb0100004100000000001504350000000001000411000d00000001001d000001b601100197000000040250003900000000001204350000000001000414000000040240008c000002150000613d000001a202000041000001a20310009c0000000001028019000001a20350009c00000000020540190000004002200210000000c001100210000000000121019f000001bc011001c70000000002040019000c00000005001d068106770000040f0000000c05000029000000100400002900000000030100190000006003300270000101a20030019d000001a20330019700030000000103550000000102200190000002640000613d000001bd0150009c000002400000a13d000001f00100004100000000001004350000004101000039000000040010043f000001ef010000410000068300010430000001a601000041000000800010043f0000002001000039000000840010043f0000002e01000039000000a40010043f000001dd01000041000000c40010043f000001de01000041000000e40010043f000001df010000410000068300010430000000000104004b000002330000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001f401000041000000610000013d001000000006001d000f00000004001d000e00000005001d000000000105004b000002870000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001f301000041000000610000013d000000400050043f00000000004004350000000301000039000000200010043f000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001be011001c700008010020000390681067c0000040f0000000102200190000000400000613d000000400200043d0000002403200039000000000101043b000000000101041a000001b601100198000002c90000c13d000001a6010000410000000000120435000000040120003900000020040000390000000000410435000000020100003900000000001304350000004401200039000001c3030000410000000000310435000001a201000041000001a20320009c00000000020180190000004001200210000001c4011001c70000068300010430000000400200043d0000001f0430018f0000000505300272000002710000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002690000413d000000000604004b000002800000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001a201000041000001a20420009c000000000201801900000040012002100000006002300210000000000121019f0000068300010430000001e1013001970000001002200210000001e202200197000000000121019f000000000010041b000001e3010000410000000000100439000000000100041200000004001004430000002400000443000001a2030000410000000001000414000001a20210009c0000000001038019000000c001100210000001e4011001c700008005020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000d00000001001d000001e50100004100000000001004390000000001000414000001a20210009c000001a201008041000000c001100210000001e6011001c70000800b020000390681067c0000040f00000001022001900000059c0000613d000000400200043d000c00000002001d000000000101043b0000000d0110006c0000034d0000c13d000000100100006b0000038f0000c13d0000000c030000290000004401300039000001f2020000410000000000210435000000240130003900000003020000390000000000210435000001a6010000410000000000130435000000040130003900000020020000390000000000210435000001a201000041000001a20230009c00000000030180190000004001300210000001c4011001c70000068300010430000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001c901000041000000610000013d0000002004200039000001bf0500004100000000005404350000000e04000029000000600440021000000000004304350000006001100210000000380320003900000000001304350000004c012000390000000f0300002900000000003104350000004c010000390000000000120435000001c00120009c000002170000213d0000008003200039000000400030043f000001c101000041000c00000003001d0000000000130435000000840120003900000020030000390000000000310435000000a40320003900000000010204330000000000130435000000c403200039000000000401004b000002ef0000613d000000000400001900000000053400190000002004400039000000000624001900000000060604330000000000650435000000000514004b000002e80000413d000000000231001900000000000204350000001f01100039000000200200008a000000000121016f000001a2020000410000000c04000029000001a20340009c0000000003020019000000000304401900000040033002100000004401100039000001a20410009c00000000010280190000006001100210000000000131019f0000000003000414000001a20430009c0000000003028019000000c002300210000000000112019f0000800802000039068106770000040f0000000c0a00002900000000030100190000006003300270000001a203300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000003190000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000003110000413d000000000705004b000003280000613d0000000506600210000000000761034f0000000c066000290000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000003720000613d0000001f01400039000000600210018f0000000c01200029000000000221004b00000000020000190000000102004039000001bd0410009c00000010070000290000000e05000029000002170000213d0000000102200190000002170000c13d000000400010043f000000200230008c000000400000413d0000000f020000290000000000210435000001a2020000410000000003000414000001a20430009c0000000003028019000001a20410009c00000000010280190000004001100210000000c002300210000000000112019f000001a8011001c7000001b6065001970000800d020000390000000403000039000001c2040000410000000d05000029000003a80000013d0000000c01000029000001e70110009c000002170000813d0000000c040000290000002401400039000001e8020000410000000000210435000000440140003900000000020004140000006003000039001000000003001d0000000000310435000001e90100004100000000001404350000006401400039000000000001043500000004014000390000000000010435000001a201000041000001a20320009c0000000002018019000001a20340009c00000000040180190000004001400210000000c002200210000000000121019f000001ea011001c70000800602000039068106770000040f0000000102200190000003fc0000613d000000000201043b000000000102004b000004380000c13d00000003010003670000000102000031000004010000013d000000400200043d0000001f0430018f00000005053002720000037f0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000003770000413d000000000604004b0000038e0000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d0000000401000039000000000201041a000001d90220019700000010022001af000000000021041b000001f101000041000000000200041a000000000112016f000000000010041b00000002010000390000000c040000290000000000140435000001a2010000410000000002000414000001a20320009c0000000002018019000001a20340009c00000000040180190000004001400210000000c002200210000000000112019f000001a8011001c70000800d020000390000000103000039000001a904000041068106770000040f0000000101200190000000400000613d0000000001000019000006820001042e0000000f0110006c000004260000c13d000001b901000041000000000010043900000006010000290000000400100443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000000e02000029000000400000613d000000400400043d00000024014000390000000d030000290000000000310435000001da010000410000000000140435000001b602200197001000000004001d0000000401400039000f00000002001d000000000021043500000000010004140000000602000029000000040220008c000003e30000613d000001a202000041000001a20310009c00000000010280190000001004000029000001a20340009c00000000020440190000004002200210000000c001100210000000000121019f000001bc011001c70000000602000029068106770000040f00000000030100190000006003300270000101a20030019d000001a203300197000300000001035500000001022001900000059d0000613d0000001001000029000001bd0110009c000002170000213d0000001004000029000000400040043f0000000d010000290000000000140435000001a2010000410000000002000414000001a20320009c0000000002018019000001a20340009c00000000040180190000004001400210000000c002200210000000000112019f000001a8011001c70000000c02000029000001b6052001970000800d020000390000000403000039000001db040000410000000f060000290000000607000029000003a80000013d000300000001035500000000020100190000006002200270000101a20020019d000001a202200197000000400300043d0000001f0420018f00000005052002720000040e0000613d000000000600001900000005076002100000000008730019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000004060000413d000000000604004b0000041d0000613d0000000505500210000000000151034f00000000055300190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001a201000041000001a20430009c0000000003018019000001a20420009c000000000201801900000060012002100000004002300210000000000112019f0000068300010430000000400100043d0000004402100039000001ce030000410000000000320435000000240210003900000007030000290000000000320435000001a6020000410000000000210435000000040210003900000020030000390000000000320435000001a202000041000001a20310009c00000000010280190000004001100210000001c4011001c70000068300010430000000400100043d000001eb0310009c000002170000213d000001b602200197000000840310003900000000002304350000002402100039000001ec0300004100000000003204350000006402100039000000000300041400000020040000390000000000420435000000440210003900000010040000290000000000420435000001e902000041000000000021043500000004021000390000000000020435000001a202000041000001a20430009c0000000003028019000001a20410009c00000000010280190000004001100210000000c002300210000000000121019f000001ed011001c70000800602000039068106770000040f00000001022001900000053c0000613d000000000101043b000000000201004b0000055e0000c13d00000003010003670000000102000031000005410000013d000000c001100210000001d1011001970000004002200210000001d202200041000001d302200197000000000121019f0000006002400210000001d402200197000000000121019f000001d5011001c700008006020000390000000003000019000000000400001900000000050000190000000006000019068106770000040f000300000001035500000000030100190000006003300270000101a20030019d000001a2053001970000003f03500039000001a306300197000000400400043d0000000003460019000000000663004b00000000060000190000000106004039000001bd0730009c000002170000213d0000000106600190000002170000c13d000000400030043f00000000035404360000001f0650003900000005066002720000048f0000613d0000000007000031000000020770036700000000080000190000000509800210000000000a930019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000004870000413d000000000600004b000004910000613d0000001f0650018f00000005055002720000049d0000613d000000000700001900000005087002100000000009830019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b000004950000413d000000000706004b000004ac0000613d0000000505500210000000000151034f00000000055300190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000000101200190000005ba0000613d0000000001040433000001c702000041000000200410008c00000000040000190000000004024019000001c701100197000000000501004b000000000200a019000001c70110009c000000000204c019000000000102004b000000400000c13d0000000001030433000800000001001d000001b60110009c000000400000213d000001b901000041000000000010043900000008010000290000000400100443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000000f020000290000000b04000029000000400000613d000000400300043d000001d701000041000000000013043500000024053000390000000901000029000300000005001d00000000001504350000000401300039000200000001001d00000000002104350000001f0240018f0000006401300039000900000003001d0000004403300039000100000003001d0000000000430435000000100300002900000002033003670000000504400272000004ee0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000004e60000413d000000000502004b000004fd0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f00000000002404350000000b01100029000000000001043500000000010004140000000802000029000000040220008c0000051e0000613d0000000b020000290000001f022000390000000a0220017f000001a2030000410000000905000029000001a20450009c0000000004030019000000000405401900000040044002100000006402200039000001a20520009c00000000020380190000006002200210000000000224019f000001a20410009c0000000001038019000000c001100210000000000121019f0000000802000029068106770000040f00000000030100190000006003300270000101a20030019d000001a20330019700030000000103550000000102200190000005db0000613d0000000901000029000001bd0110009c000002170000213d0000000901000029000000400010043f0000000802000029000000050120014f000001b601100198000005f80000c13d000000060100002900000000001004350000000401000029000000200010043f000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001be011001c700008010020000390681067c0000040f00000001022001900000000f03000029000000400000613d000000000101043b000000000201041a000001d902200197000000000232019f000000000021041b000003af0000013d000300000001035500000000020100190000006002200270000101a20020019d000001a202200197000000400300043d0000001f0420018f00000005052002720000054e0000613d000000000600001900000005076002100000000008730019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005460000413d000000000604004b0000055d0000613d0000000505500210000000000151034f00000000055300190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000041d0000013d000001b6031001970000000101000039000000000201041a000001d902200197000000000232019f000000000021041b00000002010000390000000f02000029000000000021041b000001b9010000410000000000100439001000000003001d0000000400300443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000000e02000029000000400000613d000000400300043d000001ee010000410000000000130435000c00000003001d0000000401300039000000000021043500000000010004140000001002000029000000040220008c000005960000613d000001a202000041000001a20310009c00000000010280190000000c04000029000001a20340009c00000000020440190000004002200210000000c001100210000000000121019f000001ef011001c70000001002000029068106770000040f00000000030100190000006003300270000101a20030019d000001a20330019700030000000103550000000102200190000005be0000613d0000000c01000029000001bd0110009c000002170000213d0000000c01000029000000400010043f000003940000013d000000000001042f000000400200043d0000001f0430018f0000000505300272000005aa0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005a20000413d000000000604004b000005b90000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d000000400100043d0000004402100039000001d603000041000004290000013d000000400200043d0000001f0430018f0000000505300272000005cb0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005c30000413d000000000604004b000002800000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d000000400200043d0000001f0430018f0000000505300272000005e80000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005e00000413d000000000604004b000005f70000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d000001a60100004100000009030000290000000000130435000000200100003900000002020000290000000000120435000000070100002900000003020000290000000000120435000001d80100004100000001020000290000000000120435000002bb0000013d0001000000000002000100000001001d0000000101000039000000000301041a000000400100043d00000040021000390000004004000039000000000042043500000060020000390000000002210436000001b603300197000000000032043500000060031000390000000000030435000001f60310009c000006580000813d0000008003100039000000400030043f000001a203000041000001a20420009c000000000203801900000040022002100000000001010433000001a20410009c00000000010380190000006001100210000000000121019f0000000002000414000001a20420009c0000000002038019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f00000001022001900000065e0000613d0000000202000039000000000202041a000000000301043b000000400100043d000000a0041000390000000000340435000000800310003900000000002304350000000102000029000001b602200197000000600310003900000000002304350000004002100039000000000300041000000000003204350000002002100039000001cb030000410000000000320435000000a0030000390000000000310435000001cc0310009c000006580000213d000000c003100039000000400030043f000001a203000041000001a20420009c000000000203801900000040022002100000000001010433000001a20410009c00000000010380190000006001100210000000000121019f0000000002000414000001a20420009c0000000002038019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f00000001022001900000065e0000613d000000000101043b000001b601100197000000000001042d000001f00100004100000000001004350000004101000039000000040010043f000001ef01000041000006830001043000000000010000190000068300010430000000000001042f000001a203000041000001a20410009c00000000010380190000004001100210000001a20420009c00000000020380190000006002200210000000000112019f0000000002000414000001a20420009c0000000002038019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f0000000102200190000006750000613d000000000101043b000000000001042d000000000100001900000683000104300000067a002104210000000102000039000000000001042d0000000002000019000000000001042d0000067f002104230000000102000039000000000001042d0000000002000019000000000001042d0000068100000432000006820001042e0000068300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe0616c697a696e6700000000000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320696e69746908c379a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000000000000000000000002000000000000000000000000000000000000200000000000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498000000020000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000cfe7af7b00000000000000000000000000000000000000000000000000000000f54266a100000000000000000000000000000000000000000000000000000000f54266a200000000000000000000000000000000000000000000000000000000f5f1516800000000000000000000000000000000000000000000000000000000cfe7af7c00000000000000000000000000000000000000000000000000000000d9caed1200000000000000000000000000000000000000000000000000000000a31ee5af00000000000000000000000000000000000000000000000000000000a31ee5b000000000000000000000000000000000000000000000000000000000b852ad36000000000000000000000000000000000000000000000000000000006dde720900000000000000000000000000000000000000000000000000000000969b53da000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000008000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000074f4f547000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff020000000000000000000000000000000000004000000000000000000000000011a2ccc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f62f84b24000000000000000000000000000000000000000000000000000000002fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b079680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000416d6f756e742063616e6e6f74206265207a65726f000000000000000000000000000000000000000000000000000000000000640000008000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eeeeffffffffffffffffffffffffffffffffeeef6d710000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000a000000000000000002020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494000000000000000000000000000000000000000000000000ffffffffffffff3f020000000000000000000000000000000000000000000000000000000000000067670000000000000000000000000000000000000000000000000000000000003cda335100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000001000000000000000000000000000000000000000000000000000000000000006d6b00000000000000000000000000000000000000000000000000000000000095f11a40000000000000000000000000000000000000000000000000000000006d74000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000008c2a993e00000000000000000000000000000000000000000000000000000000b84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f634f766572666c6f77000000000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65640000000000000000000000000000000000000000000000000000000000000000000000000084000000800000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffff0000000000000000000000000000000000000000010200000000000000000000ffffffffffffffffffffffffffffffffffffffff0000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e02000002000000000000000000000000000000440000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7c010004751688ab9322961547058fd0f36d3edf69880b64cbb2857041d33f4a133cda33511d41a8a5431b1770c5bc0ddd62e1cd30555d16659b89c0d60f4f9f570200000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7b010000691fa4f751f8312bc555242f18ed78cdc9aabc0ea77d7d5a675ee8ac6f02000000000000000000000000000000000000a4000000000000000000000000f2fde38b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6266320000000000000000000000000000000000000000000000000000000000736600000000000000000000000000000000000000000000000000000000000064660000000000000000000000000000000000000000000000000000000000006266000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff800000000000000000000000000000000000000000000000000000000000000000f5cf0be6820df44d868e986d4d5cafabd5702ac45d181a5ac4eb5ed59a001b03", - "deployedBytecode": "0x0004000000000002001000000000000200000000030100190000006004300270000001a20340019700030000003103550002000000010355000001a20040019d00000001022001900000001d0000c13d0000008002000039000000400020043f000000040230008c000000400000413d000000000201043b000000e002200270000001ab0420009c000000420000213d000001b10420009c0000008a0000213d000001b40120009c000000c10000613d000001b50120009c000000400000c13d0000000001000416000000000101004b000000400000c13d0000000401000039000001d90000013d0000000002000416000000000202004b000000400000c13d000000bf02300039000001a302200197000000400020043f0000001f0230018f00000005043002720000002f0000613d00000000050000190000000506500210000000000761034f000000000707043b000000a00660003900000000007604350000000105500039000000000645004b000000270000413d000000000502004b0000003e0000613d0000000504400210000000000141034f0000000302200210000000a004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f0000000000140435000000200130008c000000640000813d00000000010000190000068300010430000001ac0420009c000000940000213d000001af0420009c000000c60000613d000001b00220009c000000400000c13d0000000002000416000000000202004b000000400000c13d000000040230008a000000600220008c000000400000413d0000000402100370000000000402043b000001b60240009c000000400000213d0000002402100370000000000302043b000001b60230009c000000400000213d0000004401100370000000000201043b000000000102004b000001de0000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f000001c501000041000000c40010043f000001c6010000410000068300010430000000a00100043d000000800010043f000000000200041a0000ff0003200190000000ac0000c13d000000ff0320018f000000ff0330008c000000820000613d000000ff012001bf000000000010041b000000ff01000039000000400200043d0000000000120435000001a2010000410000000003000414000001a20430009c0000000003018019000001a20420009c00000000020180190000004001200210000000c002300210000000000112019f000001a8011001c70000800d020000390000000103000039000001a904000041068106770000040f0000000101200190000000400000613d000000800100043d000001400000044300000160001004430000002001000039000001000010044300000001010000390000012000100443000001aa01000041000006820001042e000001b20420009c000001a50000613d000001b30120009c000000400000c13d0000000001000416000000000101004b000000400000c13d000000000100041a0000001001100270000001da0000013d000001ad0420009c000001c90000613d000001ae0220009c000000400000c13d0000000002000416000000000202004b000000400000c13d000000040230008a000000200220008c000000400000413d0000000401100370000000000101043b000001b60210009c000000400000213d068106050000040f000001b601100197000000400200043d0000000000120435000001a201000041000001a20320009c00000000020180190000004001200210000001b7011001c7000006820001042e000000400100043d0000006402100039000001a40300004100000000003204350000004402100039000001a5030000410000000000320435000000240210003900000027030000390000000000320435000001a6020000410000000000210435000000040210003900000020030000390000000000320435000001a202000041000001a20310009c00000000010280190000004001100210000001a7011001c700000683000104300000000001000416000000000101004b000000400000c13d0000000101000039000001d90000013d0000000002000416000000000202004b000000400000c13d000000040230008a000000a00220008c000000400000413d0000000402100370000000000802043b000001b60280009c000000400000213d0000002402100370000000000902043b000001b60290009c000000400000213d0000004402100370000000000a02043b000001b602a0009c000000400000213d0000008402100370000000000202043b000001bd0420009c000000400000213d0000002304200039000001c705000041000000000634004b00000000060000190000000006058019000001c704400197000000000704004b0000000005008019000001c70440009c000000000506c019000000000405004b000000400000c13d0000000404200039000000000441034f000000000504043b000001bd0450009c000000400000213d001000240020003d0000001002500029000000000232004b000000400000213d000b00000005001d000f0000000a001d000e00000009001d000c00000008001d0000006401100370000000000101043b000d00000001001d0000000001000411000001c801100041000001b6011001970000000402000039000000000202041a000001b602200197000000000221004b000001050000613d000000000200041a0000001002200270000001b602200197000000000121004b000002c10000c13d0000000101000039000800000001001d000000000101041a000001b601100197000000a00010043f0000004001000039000900000001001d000000c00010043f000000e00000043f0000006001000039000a00000001001d000000800010043f0000010001000039000000400010043f000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ca011001c700008010020000390681067c0000040f00000001022001900000000f05000029000000400000613d0000000202000039000700000002001d000000000202041a000000000301043b000000400100043d000000a004100039000000000034043500000080031000390000000000230435000000600210003900000000005204350000004002100039000000000300041000000000003204350000002002100039000001cb030000410000000000320435000000a0030000390000000000310435000001cc0310009c000002170000213d000000c003100039000000400030043f000001a204000041000001a20320009c000000000204801900000040022002100000000001010433000001a20310009c00000000010480190000006001100210000000000121019f0000000002000414000001a20320009c0000000002048019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f0000000102200190000000400000613d000000000101043b000500000001001d000001b601100197000600000001001d00000000001004350000000301000039000400000001001d000000200010043f0000000001000414000001a20210009c000001a201008041000000c001100210000001be011001c700008010020000390681067c0000040f0000000102200190000000400000613d000000000101043b000000000101041a000001b601100198000003ad0000c13d00000000010004140000000702000029000000000402041a0000000802000029000000000202041a000000400300043d000000400530003900000009060000290000000000650435000001b602200197000000200530003900000000002504350000000a02000029000000000023043500000060023000390000000000020435000001c00230009c000002170000213d0000008002300039000000400020043f000000a005300039000001cf060000410000000000650435000000e4053000390000000a060000290000000000650435000000c4053000390000000000450435000000a4043000390000000f0500002900000000005404350000010405300039000000000403043300000000004504350000012405300039000000000604004b0000018a0000613d000000000600001900000000075600190000002006600039000000000836001900000000080804330000000000870435000000000746004b000001830000413d000000000354001900000000000304350000001f03400039000a0020000000920000000a0330017f00000084043000390000000000420435000000c3033000390000000a0430017f0000000003240019000000000443004b00000000040000190000000104004039000001bd0530009c000002170000213d0000000104400190000002170000c13d000000400030043f0000000004020433000001d00540009c0000045f0000413d0000004401300039000001dc02000041000000000021043500000024013000390000000802000039000002b50000013d0000000002000416000000000202004b000000400000c13d000000040230008a000000800220008c000000400000413d0000000402100370000000000202043b000001b60320009c000000400000213d0000002403100370000000000603043b000001b60360009c000000400000213d0000006403100370000000000503043b000001b60350009c000000400000213d000000000300041a0000fffe043001900000021d0000c13d000001e00330019700000102033001bf000000000030041b0000004401100370000000000401043b000000000102004b000002290000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001f501000041000000610000013d0000000002000416000000000202004b000000400000c13d000000040230008a000000200220008c000000400000413d0000000401100370000000000101043b000001b60210009c000000400000213d00000000001004350000000301000039000000200010043f00000040020000390000000001000019068106610000040f000000000101041a000001b601100197000000800010043f000001b801000041000006820001042e000f00000002001d000e00000004001d000001b9010000410000000000100439001000000003001d0000000400300443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000001004000029000000400000613d000000400500043d00000024015000390000000f020000290000000000210435000001bb0100004100000000001504350000000001000411000d00000001001d000001b601100197000000040250003900000000001204350000000001000414000000040240008c000002150000613d000001a202000041000001a20310009c0000000001028019000001a20350009c00000000020540190000004002200210000000c001100210000000000121019f000001bc011001c70000000002040019000c00000005001d068106770000040f0000000c05000029000000100400002900000000030100190000006003300270000101a20030019d000001a20330019700030000000103550000000102200190000002640000613d000001bd0150009c000002400000a13d000001f00100004100000000001004350000004101000039000000040010043f000001ef010000410000068300010430000001a601000041000000800010043f0000002001000039000000840010043f0000002e01000039000000a40010043f000001dd01000041000000c40010043f000001de01000041000000e40010043f000001df010000410000068300010430000000000104004b000002330000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001f401000041000000610000013d001000000006001d000f00000004001d000e00000005001d000000000105004b000002870000c13d000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001f301000041000000610000013d000000400050043f00000000004004350000000301000039000000200010043f000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001be011001c700008010020000390681067c0000040f0000000102200190000000400000613d000000400200043d0000002403200039000000000101043b000000000101041a000001b601100198000002c90000c13d000001a6010000410000000000120435000000040120003900000020040000390000000000410435000000020100003900000000001304350000004401200039000001c3030000410000000000310435000001a201000041000001a20320009c00000000020180190000004001200210000001c4011001c70000068300010430000000400200043d0000001f0430018f0000000505300272000002710000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002690000413d000000000604004b000002800000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001a201000041000001a20420009c000000000201801900000040012002100000006002300210000000000121019f0000068300010430000001e1013001970000001002200210000001e202200197000000000121019f000000000010041b000001e3010000410000000000100439000000000100041200000004001004430000002400000443000001a2030000410000000001000414000001a20210009c0000000001038019000000c001100210000001e4011001c700008005020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000d00000001001d000001e50100004100000000001004390000000001000414000001a20210009c000001a201008041000000c001100210000001e6011001c70000800b020000390681067c0000040f00000001022001900000059c0000613d000000400200043d000c00000002001d000000000101043b0000000d0110006c0000034d0000c13d000000100100006b0000038f0000c13d0000000c030000290000004401300039000001f2020000410000000000210435000000240130003900000003020000390000000000210435000001a6010000410000000000130435000000040130003900000020020000390000000000210435000001a201000041000001a20230009c00000000030180190000004001300210000001c4011001c70000068300010430000001a601000041000000800010043f0000002001000039000000840010043f0000000201000039000000a40010043f000001c901000041000000610000013d0000002004200039000001bf0500004100000000005404350000000e04000029000000600440021000000000004304350000006001100210000000380320003900000000001304350000004c012000390000000f0300002900000000003104350000004c010000390000000000120435000001c00120009c000002170000213d0000008003200039000000400030043f000001c101000041000c00000003001d0000000000130435000000840120003900000020030000390000000000310435000000a40320003900000000010204330000000000130435000000c403200039000000000401004b000002ef0000613d000000000400001900000000053400190000002004400039000000000624001900000000060604330000000000650435000000000514004b000002e80000413d000000000231001900000000000204350000001f01100039000000200200008a000000000121016f000001a2020000410000000c04000029000001a20340009c0000000003020019000000000304401900000040033002100000004401100039000001a20410009c00000000010280190000006001100210000000000131019f0000000003000414000001a20430009c0000000003028019000000c002300210000000000112019f0000800802000039068106770000040f0000000c0a00002900000000030100190000006003300270000001a203300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000003190000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000003110000413d000000000705004b000003280000613d0000000506600210000000000761034f0000000c066000290000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000003720000613d0000001f01400039000000600210018f0000000c01200029000000000221004b00000000020000190000000102004039000001bd0410009c00000010070000290000000e05000029000002170000213d0000000102200190000002170000c13d000000400010043f000000200230008c000000400000413d0000000f020000290000000000210435000001a2020000410000000003000414000001a20430009c0000000003028019000001a20410009c00000000010280190000004001100210000000c002300210000000000112019f000001a8011001c7000001b6065001970000800d020000390000000403000039000001c2040000410000000d05000029000003a80000013d0000000c01000029000001e70110009c000002170000813d0000000c040000290000002401400039000001e8020000410000000000210435000000440140003900000000020004140000006003000039001000000003001d0000000000310435000001e90100004100000000001404350000006401400039000000000001043500000004014000390000000000010435000001a201000041000001a20320009c0000000002018019000001a20340009c00000000040180190000004001400210000000c002200210000000000121019f000001ea011001c70000800602000039068106770000040f0000000102200190000003fc0000613d000000000201043b000000000102004b000004380000c13d00000003010003670000000102000031000004010000013d000000400200043d0000001f0430018f00000005053002720000037f0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000003770000413d000000000604004b0000038e0000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d0000000401000039000000000201041a000001d90220019700000010022001af000000000021041b000001f101000041000000000200041a000000000112016f000000000010041b00000002010000390000000c040000290000000000140435000001a2010000410000000002000414000001a20320009c0000000002018019000001a20340009c00000000040180190000004001400210000000c002200210000000000112019f000001a8011001c70000800d020000390000000103000039000001a904000041068106770000040f0000000101200190000000400000613d0000000001000019000006820001042e0000000f0110006c000004260000c13d000001b901000041000000000010043900000006010000290000000400100443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000000e02000029000000400000613d000000400400043d00000024014000390000000d030000290000000000310435000001da010000410000000000140435000001b602200197001000000004001d0000000401400039000f00000002001d000000000021043500000000010004140000000602000029000000040220008c000003e30000613d000001a202000041000001a20310009c00000000010280190000001004000029000001a20340009c00000000020440190000004002200210000000c001100210000000000121019f000001bc011001c70000000602000029068106770000040f00000000030100190000006003300270000101a20030019d000001a203300197000300000001035500000001022001900000059d0000613d0000001001000029000001bd0110009c000002170000213d0000001004000029000000400040043f0000000d010000290000000000140435000001a2010000410000000002000414000001a20320009c0000000002018019000001a20340009c00000000040180190000004001400210000000c002200210000000000112019f000001a8011001c70000000c02000029000001b6052001970000800d020000390000000403000039000001db040000410000000f060000290000000607000029000003a80000013d000300000001035500000000020100190000006002200270000101a20020019d000001a202200197000000400300043d0000001f0420018f00000005052002720000040e0000613d000000000600001900000005076002100000000008730019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000004060000413d000000000604004b0000041d0000613d0000000505500210000000000151034f00000000055300190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000001a201000041000001a20430009c0000000003018019000001a20420009c000000000201801900000060012002100000004002300210000000000112019f0000068300010430000000400100043d0000004402100039000001ce030000410000000000320435000000240210003900000007030000290000000000320435000001a6020000410000000000210435000000040210003900000020030000390000000000320435000001a202000041000001a20310009c00000000010280190000004001100210000001c4011001c70000068300010430000000400100043d000001eb0310009c000002170000213d000001b602200197000000840310003900000000002304350000002402100039000001ec0300004100000000003204350000006402100039000000000300041400000020040000390000000000420435000000440210003900000010040000290000000000420435000001e902000041000000000021043500000004021000390000000000020435000001a202000041000001a20430009c0000000003028019000001a20410009c00000000010280190000004001100210000000c002300210000000000121019f000001ed011001c70000800602000039068106770000040f00000001022001900000053c0000613d000000000101043b000000000201004b0000055e0000c13d00000003010003670000000102000031000005410000013d000000c001100210000001d1011001970000004002200210000001d202200041000001d302200197000000000121019f0000006002400210000001d402200197000000000121019f000001d5011001c700008006020000390000000003000019000000000400001900000000050000190000000006000019068106770000040f000300000001035500000000030100190000006003300270000101a20030019d000001a2053001970000003f03500039000001a306300197000000400400043d0000000003460019000000000663004b00000000060000190000000106004039000001bd0730009c000002170000213d0000000106600190000002170000c13d000000400030043f00000000035404360000001f0650003900000005066002720000048f0000613d0000000007000031000000020770036700000000080000190000000509800210000000000a930019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000004870000413d000000000600004b000004910000613d0000001f0650018f00000005055002720000049d0000613d000000000700001900000005087002100000000009830019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b000004950000413d000000000706004b000004ac0000613d0000000505500210000000000151034f00000000055300190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000000101200190000005ba0000613d0000000001040433000001c702000041000000200410008c00000000040000190000000004024019000001c701100197000000000501004b000000000200a019000001c70110009c000000000204c019000000000102004b000000400000c13d0000000001030433000800000001001d000001b60110009c000000400000213d000001b901000041000000000010043900000008010000290000000400100443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000000f020000290000000b04000029000000400000613d000000400300043d000001d701000041000000000013043500000024053000390000000901000029000300000005001d00000000001504350000000401300039000200000001001d00000000002104350000001f0240018f0000006401300039000900000003001d0000004403300039000100000003001d0000000000430435000000100300002900000002033003670000000504400272000004ee0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000004e60000413d000000000502004b000004fd0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f00000000002404350000000b01100029000000000001043500000000010004140000000802000029000000040220008c0000051e0000613d0000000b020000290000001f022000390000000a0220017f000001a2030000410000000905000029000001a20450009c0000000004030019000000000405401900000040044002100000006402200039000001a20520009c00000000020380190000006002200210000000000224019f000001a20410009c0000000001038019000000c001100210000000000121019f0000000802000029068106770000040f00000000030100190000006003300270000101a20030019d000001a20330019700030000000103550000000102200190000005db0000613d0000000901000029000001bd0110009c000002170000213d0000000901000029000000400010043f0000000802000029000000050120014f000001b601100198000005f80000c13d000000060100002900000000001004350000000401000029000000200010043f000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001be011001c700008010020000390681067c0000040f00000001022001900000000f03000029000000400000613d000000000101043b000000000201041a000001d902200197000000000232019f000000000021041b000003af0000013d000300000001035500000000020100190000006002200270000101a20020019d000001a202200197000000400300043d0000001f0420018f00000005052002720000054e0000613d000000000600001900000005076002100000000008730019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005460000413d000000000604004b0000055d0000613d0000000505500210000000000151034f00000000055300190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000041d0000013d000001b6031001970000000101000039000000000201041a000001d902200197000000000232019f000000000021041b00000002010000390000000f02000029000000000021041b000001b9010000410000000000100439001000000003001d0000000400300443000001a2010000410000000002000414000001a20320009c0000000002018019000000c001200210000001ba011001c700008002020000390681067c0000040f00000001022001900000059c0000613d000000000101043b000000000101004b0000000e02000029000000400000613d000000400300043d000001ee010000410000000000130435000c00000003001d0000000401300039000000000021043500000000010004140000001002000029000000040220008c000005960000613d000001a202000041000001a20310009c00000000010280190000000c04000029000001a20340009c00000000020440190000004002200210000000c001100210000000000121019f000001ef011001c70000001002000029068106770000040f00000000030100190000006003300270000101a20030019d000001a20330019700030000000103550000000102200190000005be0000613d0000000c01000029000001bd0110009c000002170000213d0000000c01000029000000400010043f000003940000013d000000000001042f000000400200043d0000001f0430018f0000000505300272000005aa0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005a20000413d000000000604004b000005b90000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d000000400100043d0000004402100039000001d603000041000004290000013d000000400200043d0000001f0430018f0000000505300272000005cb0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005c30000413d000000000604004b000002800000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d000000400200043d0000001f0430018f0000000505300272000005e80000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000005e00000413d000000000604004b000005f70000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000002800000013d000001a60100004100000009030000290000000000130435000000200100003900000002020000290000000000120435000000070100002900000003020000290000000000120435000001d80100004100000001020000290000000000120435000002bb0000013d0001000000000002000100000001001d0000000101000039000000000301041a000000400100043d00000040021000390000004004000039000000000042043500000060020000390000000002210436000001b603300197000000000032043500000060031000390000000000030435000001f60310009c000006580000813d0000008003100039000000400030043f000001a203000041000001a20420009c000000000203801900000040022002100000000001010433000001a20410009c00000000010380190000006001100210000000000121019f0000000002000414000001a20420009c0000000002038019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f00000001022001900000065e0000613d0000000202000039000000000202041a000000000301043b000000400100043d000000a0041000390000000000340435000000800310003900000000002304350000000102000029000001b602200197000000600310003900000000002304350000004002100039000000000300041000000000003204350000002002100039000001cb030000410000000000320435000000a0030000390000000000310435000001cc0310009c000006580000213d000000c003100039000000400030043f000001a203000041000001a20420009c000000000203801900000040022002100000000001010433000001a20410009c00000000010380190000006001100210000000000121019f0000000002000414000001a20420009c0000000002038019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f00000001022001900000065e0000613d000000000101043b000001b601100197000000000001042d000001f00100004100000000001004350000004101000039000000040010043f000001ef01000041000006830001043000000000010000190000068300010430000000000001042f000001a203000041000001a20410009c00000000010380190000004001100210000001a20420009c00000000020380190000006002200210000000000112019f0000000002000414000001a20420009c0000000002038019000000c002200210000000000112019f000001cd011001c700008010020000390681067c0000040f0000000102200190000006750000613d000000000101043b000000000001042d000000000100001900000683000104300000067a002104210000000102000039000000000001042d0000000002000019000000000001042d0000067f002104230000000102000039000000000001042d0000000002000019000000000001042d0000068100000432000006820001042e0000068300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe0616c697a696e6700000000000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320696e69746908c379a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000000000000000000000002000000000000000000000000000000000000200000000000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498000000020000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000cfe7af7b00000000000000000000000000000000000000000000000000000000f54266a100000000000000000000000000000000000000000000000000000000f54266a200000000000000000000000000000000000000000000000000000000f5f1516800000000000000000000000000000000000000000000000000000000cfe7af7c00000000000000000000000000000000000000000000000000000000d9caed1200000000000000000000000000000000000000000000000000000000a31ee5af00000000000000000000000000000000000000000000000000000000a31ee5b000000000000000000000000000000000000000000000000000000000b852ad36000000000000000000000000000000000000000000000000000000006dde720900000000000000000000000000000000000000000000000000000000969b53da000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000008000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000074f4f547000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff020000000000000000000000000000000000004000000000000000000000000011a2ccc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f62f84b24000000000000000000000000000000000000000000000000000000002fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b079680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000416d6f756e742063616e6e6f74206265207a65726f000000000000000000000000000000000000000000000000000000000000640000008000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eeeeffffffffffffffffffffffffffffffffeeef6d710000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000a000000000000000002020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494000000000000000000000000000000000000000000000000ffffffffffffff3f020000000000000000000000000000000000000000000000000000000000000067670000000000000000000000000000000000000000000000000000000000003cda335100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000001000000000000000000000000000000000000000000000000000000000000006d6b00000000000000000000000000000000000000000000000000000000000095f11a40000000000000000000000000000000000000000000000000000000006d74000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000008c2a993e00000000000000000000000000000000000000000000000000000000b84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f634f766572666c6f77000000000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65640000000000000000000000000000000000000000000000000000000000000000000000000084000000800000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffff0000000000000000000000000000000000000000010200000000000000000000ffffffffffffffffffffffffffffffffffffffff0000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e02000002000000000000000000000000000000440000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7c010004751688ab9322961547058fd0f36d3edf69880b64cbb2857041d33f4a133cda33511d41a8a5431b1770c5bc0ddd62e1cd30555d16659b89c0d60f4f9f570200000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7b010000691fa4f751f8312bc555242f18ed78cdc9aabc0ea77d7d5a675ee8ac6f02000000000000000000000000000000000000a4000000000000000000000000f2fde38b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6266320000000000000000000000000000000000000000000000000000000000736600000000000000000000000000000000000000000000000000000000000064660000000000000000000000000000000000000000000000000000000000006266000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff800000000000000000000000000000000000000000000000000000000000000000f5cf0be6820df44d868e986d4d5cafabd5702ac45d181a5ac4eb5ed59a001b03", - "linkReferences": {}, - "deployedLinkReferences": {}, - "factoryDeps": { - "0x010000691fa4f751f8312bc555242f18ed78cdc9aabc0ea77d7d5a675ee8ac6f": "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol:UpgradeableBeacon", - "0x010004751688ab9322961547058fd0f36d3edf69880b64cbb2857041d33f4a13": "contracts/bridge/L2StandardERC20.sol:L2StandardERC20" - } -} diff --git a/l1-contracts/script-config/artifacts/TransparentUpgradeableProxy.json b/l1-contracts/script-config/artifacts/TransparentUpgradeableProxy.json deleted file mode 100644 index c8880c120..000000000 --- a/l1-contracts/script-config/artifacts/TransparentUpgradeableProxy.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "_format": "hh-zksolc-artifact-1", - "contractName": "TransparentUpgradeableProxy", - "sourceName": "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_logic", - "type": "address" - }, - { - "internalType": "address", - "name": "admin_", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x00020000000000020008000000000002000000000301001900000060033002700000012c0330019700010000003103550000008008000039000000400080043f00000001022001900000001e0000c13d000000000431034f00000000050004110000013d02000041000000000702041a0000013002700197000000000603004b000000270000c13d000000000325004b0000010c0000c13d000000000101043b0000014101100197000001420310009c0000001b0000613d000001430310009c000002c20000613d000001440310009c000002680000c13d00000000010004160000000001000019000004ac000104300000012d023000410000012e0220009c0000005f0000213d000001520100004100000000001004350000004101000039000000040010043f0000015301000041000004ac00010430000000000525004b0000012d0000c13d000000000401043b0000014104400197000001420540009c000001670000c13d0000000002000416000000000202004b000002c20000c13d000000240230008c000002c20000413d0000000401100370000000000201043b000001300120009c000002c20000213d000000a001000039000000400010043f000000800000043f00000133010000410000000000100439000800000002001d00000004002004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b000002a80000c13d000000400100043d00000064021000390000015403000041000000000032043500000044021000390000015503000041000000000032043500000024021000390000002d0300003900000000003204350000013c0200004100000000002104350000000402100039000000200300003900000000003204350000012c020000410000012c0310009c000000000102801900000040011002100000014c011001c7000004ac000104300000009f023000390000012f02200197000000400020043f0000001f0230018f00000005043002720000006e0000613d00000000050000190000000506500210000000000761034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000660000413d000000000502004b0000007d0000613d0000000504400210000000000141034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f00000000001404350000005f0130008c000002c20000a13d000000800900043d000001300190009c000002c20000213d000000a00700043d000001300170009c000002c20000213d000000c00200043d000001310120009c000002c20000213d0000001f012000390000013204000041000000000531004b000000000500001900000000050480190000013201100197000000000601004b0000000004008019000001320110009c000000000405c019000000000104004b000002c20000c13d00000080012000390000000001010433000001310410009c000000210000213d0000003f04100039000000200a00008a0000000004a4016f000000400b00043d00000000044b00190000000005b4004b00000000050000190000000105004039000001310640009c000000210000213d0000000105500190000000210000c13d0000008003300039000000400040043f00000000061b0436000000a0022000390000000004210019000000000334004b000002c20000213d00060000000b001d00050000000a001d000700000007001d000300000008001d000000000301004b000000b90000613d000000000300001900000000046300190000000005230019000000000505043300000000005404350000002003300039000000000413004b000000b20000413d000400000006001d0000000001160019000000000001043500000133010000410000000000100439000800000009001d00000004009004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b0000004a0000613d000000080100002900000130051001970000013501000041000000000201041a0000013602200197000000000252019f000000000021041b0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000137011001c70000800d020000390000000203000039000001380400004104aa049b0000040f0000000803000029000000010120019000000007020000290000000605000029000002c20000613d0000000001050433000000000101004b000003770000c13d0000013d01000041000000000301041a0000013004200197000000400100043d0000002002100039000800000004001d0000000000420435000700000003001d000001300230019700000000002104350000012c0200004100000000030004140000012c0430009c00000000030280190000012c0410009c00000000010280190000004001100210000000c002300210000000000112019f0000013e011001c70000800d0200003900000001030000390000013f0400004104aa049b0000040f0000000101200190000002c20000613d000000080100006b0000025a0000613d0000000701000029000001360110019700000008011001af0000013d02000041000000000012041b0000002001000039000001000010044300000120000004430000014001000041000004ab0001042e0000013501000041000000000201041a00000000010004140000013002200197000000040320008c000001e90000c13d00000000030000310000001f0230018f00000005013002720000011e0000613d00000000050000190000000506500210000000000764034f000000000707043b00000000007604350000000105500039000000000615004b000001170000413d000000000502004b0000020e0000613d00000003022002100000000501100210000000000501043300000000052501cf000000000525022f000000000414034f000000000404043b0000010002200089000000000424022f00000000022401cf000000000252019f00000000002104350000020e0000013d0000001f0530018f0000013502000041000000000202041a000001300220019700000005063002720000013b0000613d00000000070000190000000508700210000000000981034f000000000909043b00000000009804350000000107700039000000000867004b000001340000413d000000000705004b000001490000613d00000003055002100000000506600210000000000706043300000000075701cf000000000757022f000000000161034f000000000101043b0000010005500089000000000151022f00000000015101cf000000000171019f00000000001604350000000001000414000000040520008c0000020f0000c13d00000000030000310000001f0230018f0000000501300272000001580000613d00000000050000190000000506500210000000000764034f000000000707043b00000000007604350000000105500039000000000615004b000001510000413d000000000502004b000002360000613d00000003022002100000000501100210000000000501043300000000052501cf000000000525022f000000000414034f000000000404043b0000010002200089000000000424022f00000000022401cf000000000252019f0000000000210435000002360000013d000001430540009c0000023b0000c13d000000440230008c000002c20000413d0000000402100370000000000802043b000001300280009c000002c20000213d0000002402100370000000000402043b000001310240009c000002c20000213d00000023024000390000013205000041000000000632004b000000000600001900000000060580190000013202200197000000000702004b0000000005008019000001320220009c000000000506c019000000000205004b000002c20000c13d0000000405400039000000000251034f000000000202043b000001310620009c000000210000213d000000bf06200039000000200900008a000000000696016f000001310760009c000000210000213d000000400060043f000000800020043f00000000042400190000002404400039000000000334004b000002c20000213d0000002003500039000000000131034f0000001f0320018f00000005042002720000019d0000613d00000000050000190000000506500210000000000761034f000000000707043b000000a00660003900000000007604350000000105500039000000000645004b000001950000413d000700000009001d000000000503004b000001ad0000613d0000000504400210000000000141034f0000000303300210000000a004400039000000000504043300000000053501cf000000000535022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f0000000000140435000000a001200039000000000001043500000133010000410000000000100439000800000008001d00000004008004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b0000004a0000613d0000013501000041000000000201041a000001360220019700000008022001af0000000805000029000000000021041b0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000137011001c70000800d020000390000000203000039000001380400004104aa049b0000040f00000008030000290000000101200190000002c20000613d000000400100043d000600000001001d000001390110009c000000210000213d00000006040000290000006001400039000000400010043f00000040014000390000013a02000041000000000021043500000020014000390000013b02000041000000000021043500000027010000390000000000140435000000800200043d0000000001000414000000040330008c0000040d0000c13d000000010200003900000000040000310000041d0000013d0000012c030000410000012c0410009c0000000001038019000000c00110021004aa04a50000040f0001000000010355000000000301001900000060033002700000001f0430018f0000012c0030019d0000012c033001970000000505300272000001fe0000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b000001f70000413d000000000604004b0000020c0000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000000101200190000002640000613d000002360000013d0000012c040000410000012c0510009c0000000001048019000000c0011002100000006003300210000000000131019f04aa04a50000040f0001000000010355000000000301001900000060033002700000001f0430018f0000012c0030019d0000012c033001970000000505300272000002260000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b0000021f0000413d000000000604004b000002340000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000000101200190000002660000613d0000012c010000410000012c0230009c00000000030180190000006001300210000004ab0001042e000001440540009c0000026e0000c13d0000000004000416000000000404004b000002c20000c13d000000240330008c000002c20000413d0000000401100370000000000401043b000001300140009c000002c20000213d000000800020043f000000a00040043f0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000148011001c70000800d020000390000000103000039000700000004001d0000013f04000041000800000007001d04aa049b0000040f000000070400002900000008030000290000000101200190000002c20000613d000000000104004b000002c40000c13d000000400100043d00000064021000390000014a03000041000000000032043500000044021000390000014b03000041000000000032043500000024021000390000002603000039000000530000013d0000006001300210000004ac000104300000006001300210000004ac00010430000001450310009c000002750000c13d0000000001000416000000000101004b000002c20000c13d0000027d0000013d000001450140009c000002840000c13d0000000001000416000000000101004b000002c20000c13d000000a00020043f0000028d0000013d000001460110009c0000029a0000c13d0000000001000416000000000101004b000002c20000c13d0000013501000041000000000101041a0000013002100197000000a00020043f0000002001000039000000800010043f000000c001000039000000400010043f0000015a01000041000004ab0001042e000001460140009c0000029a0000c13d0000000001000416000000000101004b000002c20000c13d0000013501000041000000000101041a0000013001100197000000a00010043f0000002001000039000000800010043f000000c001000039000000400010043f000000800100003900000147020000410000015003000041000001500410009c000000000103801900000040011002100000015101100041000000000121019f000004ab0001042e0000013c01000041000000800010043f0000002001000039000000840010043f0000004201000039000000a40010043f0000015601000041000000c40010043f0000015701000041000000e40010043f0000015801000041000001040010043f0000015901000041000004ac000104300000013501000041000000000201041a000001360220019700000008022001af0000000805000029000000000021041b0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000137011001c70000800d020000390000000203000039000001380400004104aa049b0000040f00000008080000290000000101200190000002c20000613d000000800100043d000000000101004b000002d00000c13d000000400100043d000001490210009c000000210000213d000002cb0000013d0000000001000019000004ac000104300000013601300197000000000114019f0000013d02000041000000000012041b000000400100043d000001490210009c000000210000213d0000002002100039000000400020043f00000000000104350000000002000019000002930000013d000000400900043d000001390190009c000000210000213d0000006001900039000000400010043f00000040019000390000013a02000041000000000021043500000020019000390000013b02000041000000000021043500000027010000390000000000190435000000800200043d0000000001000414000000040380008c000002e40000c13d00000001020000390000000004000031000002f70000013d0000012c030000410000012c0410009c00000000010380190000012c0420009c00000000020380190000006002200210000000c001100210000000000121019f0000014d011001c70000000002080019000700000009001d04aa04a50000040f00000007090000290000000808000029000000010220018f000100000001035500000060011002700000012c0010019d0000012c0410019700000060030000390000008001000039000000000504004b000003230000c13d0000000003030433000000000202004b000003530000c13d000000000203004b0000038c0000c13d000000400100043d0000013c0200004100000000002104350000000402100039000000200300003900000000003204350000000002090433000000240310003900000000002304350000004403100039000000000402004b000003140000613d000000000400001900000000053400190000002004400039000000000694001900000000060604330000000000650435000000000524004b0000030d0000413d0000001f04200039000000200500008a000000000454016f0000000002320019000000000002043500000044024000390000012c030000410000012c0420009c00000000020380190000012c0410009c000000000103801900000040011002100000006002200210000000000112019f000004ac00010430000001310140009c000000210000213d0000003f01400039000000200300008a000000000131016f000000400300043d0000000001130019000000000531004b00000000050000190000000105004039000001310610009c000000210000213d0000000105500190000000210000c13d000000000a090019000000400010043f0000001f0540018f000000000143043600000001060003670000000504400272000003410000613d000000000700001900000005087002100000000009810019000000000886034f000000000808043b00000000008904350000000107700039000000000847004b000003390000413d000000000705004b000000080800002900000000090a0019000002fb0000613d0000000504400210000000000646034f00000000044100190000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000002fb0000013d000000000103004b000002be0000c13d0000013301000041000000000010043900000004008004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b000002be0000c13d000000400100043d00000044021000390000014e03000041000000000032043500000024021000390000001d0300003900000000003204350000013c0200004100000000002104350000000402100039000000200300003900000000003204350000012c020000410000012c0310009c000000000102801900000040011002100000014f011001c7000004ac00010430000000400400043d000001390140009c000000210000213d0000006001400039000000400010043f00000040014000390000013a0200004100000000002104350000002701000039000200000004001d00000000021404360000013b01000041000100000002001d000000000012043500000000020504330000000001000414000000040330008c000003950000c13d00000001020000390000000003000031000003a90000013d0000012c020000410000012c0430009c00000000030280190000012c0410009c000000000102801900000040011002100000006002300210000000000112019f000004ac000104300000012c0300004100000004050000290000012c0450009c000000000503801900000040045002100000012c0520009c00000000020380190000006002200210000000000242019f0000012c0410009c0000000001038019000000c001100210000000000112019f000000080200002904aa04a50000040f000000010220018f000100000001035500000060011002700000012c0010019d0000012c031001970000006001000039000000000403004b000003c90000c13d0000000001010433000000000202004b000003f70000c13d000000000201004b000004830000c13d000000400400043d000800000004001d0000013c01000041000000000014043500000004014000390000002002000039000000000021043500000002010000290000000003010433000700000003001d000000240140003900000000003104350000004402400039000000010100002904aa048d0000040f00000007010000290000001f01100039000000050110017f00000044011000390000012c020000410000012c0310009c00000000010280190000000804000029000004870000013d000001310130009c0000000504000029000000210000213d0000003f01300039000000000441016f000000400100043d0000000004410019000000000514004b00000000050000190000000105004039000001310640009c000000210000213d0000000105500190000000210000c13d000000400040043f0000001f0430018f000000000931043600000001050003670000000503300272000003e60000613d000000000600001900000005076002100000000008790019000000000775034f000000000707043b00000000007804350000000106600039000000000736004b000003de0000413d000300000009001d000000000604004b000003ac0000613d0000000503300210000000000535034f00000003033000290000000304400210000000000603043300000000064601cf000000000646022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000464019f0000000000430435000003ac0000013d000000000101004b00000007020000290000000803000029000000e60000c13d0000013301000041000000000010043900000004003004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b0000000702000029000000e60000c13d000003650000013d0000012c030000410000012c0410009c00000000010380190000012c0420009c00000000020380190000006002200210000000c001100210000000000121019f0000014d011001c7000000080200002904aa04a50000040f000000010220018f000100000001035500000060011002700000012c0010019d0000012c0410019700000060030000390000008001000039000000000504004b0000043e0000c13d0000000003030433000000000202004b0000046b0000c13d000000000203004b0000038c0000c13d000000400100043d0000013c02000041000000000021043500000004021000390000002003000039000000000032043500000006070000290000000002070433000000240310003900000000002304350000004403100039000000000402004b0000043b0000613d000000000400001900000000053400190000002004400039000000000674001900000000060604330000000000650435000000000524004b000004340000413d0000001f042000390000000705000029000003160000013d000001310140009c0000000703000029000000210000213d0000003f01400039000000000131016f000000400300043d0000000001130019000000000531004b00000000050000190000000105004039000001310610009c000000210000213d0000000105500190000000210000c13d000000400010043f0000001f0540018f0000000001430436000000010600036700000005044002720000045b0000613d000000000700001900000005087002100000000009810019000000000886034f000000000808043b00000000008904350000000107700039000000000847004b000004530000413d000000000705004b000004210000613d0000000504400210000000000646034f00000000044100190000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000004210000013d000000000103004b0000047e0000c13d00000133010000410000000000100439000000080100002900000004001004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b000003650000613d000000400100043d000001490210009c000000210000213d000002cb0000013d000000000001042f0000012c020000410000012c0310009c000000000102801900000003040000290000012c0340009c000000000402801900000040024002100000006001100210000000000121019f000004ac00010430000000000403004b000004970000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000534004b000004900000413d00000000012300190000000000010435000000000001042d000000000001042f0000049e002104210000000102000039000000000001042d0000000002000019000000000001042d000004a3002104230000000102000039000000000001042d0000000002000019000000000001042d000004a8002104250000000102000039000000000001042d0000000002000019000000000001042d000004aa00000432000004ab0001042e000004ac0001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009fffffffffffffffffffffffffffffffffffffffffffffffff000000000000007f00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff80000000000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcffffffffffffffffffffffff00000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b000000000000000000000000000000000000000000000000ffffffffffffff9f206661696c656400000000000000000000000000000000000000000000000000416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c08c379a000000000000000000000000000000000000000000000000000000000b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610302000000000000000000000000000000000000400000000000000000000000007e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f0000000200000000000000000000000000000040000001000000000000000000ffffffff000000000000000000000000000000000000000000000000000000003659cfe6000000000000000000000000000000000000000000000000000000004f1ef286000000000000000000000000000000000000000000000000000000008f28397000000000000000000000000000000000000000000000000000000000f851a440000000000000000000000000000000000000000000000000000000005c60da1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000200000000000000000000000000000000000040000000800000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf6464726573730000000000000000000000000000000000000000000000000000455243313936373a206e65772061646d696e20697320746865207a65726f206100000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffdf00000000000000000000000000000000000000000000002000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000006f74206120636f6e747261637400000000000000000000000000000000000000455243313936373a206e657720696d706c656d656e746174696f6e206973206e5472616e73706172656e745570677261646561626c6550726f78793a2061646d696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267657400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a40000008000000000000000000000000000000000000000000000000000000020000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000007444ff0b02dc9864c7dbf97ccd7719c286d6972190eeb0285ea9e04a713977c0", - "deployedBytecode": "0x00020000000000020008000000000002000000000301001900000060033002700000012c0330019700010000003103550000008008000039000000400080043f00000001022001900000001e0000c13d000000000431034f00000000050004110000013d02000041000000000702041a0000013002700197000000000603004b000000270000c13d000000000325004b0000010c0000c13d000000000101043b0000014101100197000001420310009c0000001b0000613d000001430310009c000002c20000613d000001440310009c000002680000c13d00000000010004160000000001000019000004ac000104300000012d023000410000012e0220009c0000005f0000213d000001520100004100000000001004350000004101000039000000040010043f0000015301000041000004ac00010430000000000525004b0000012d0000c13d000000000401043b0000014104400197000001420540009c000001670000c13d0000000002000416000000000202004b000002c20000c13d000000240230008c000002c20000413d0000000401100370000000000201043b000001300120009c000002c20000213d000000a001000039000000400010043f000000800000043f00000133010000410000000000100439000800000002001d00000004002004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b000002a80000c13d000000400100043d00000064021000390000015403000041000000000032043500000044021000390000015503000041000000000032043500000024021000390000002d0300003900000000003204350000013c0200004100000000002104350000000402100039000000200300003900000000003204350000012c020000410000012c0310009c000000000102801900000040011002100000014c011001c7000004ac000104300000009f023000390000012f02200197000000400020043f0000001f0230018f00000005043002720000006e0000613d00000000050000190000000506500210000000000761034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000660000413d000000000502004b0000007d0000613d0000000504400210000000000141034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f00000000001404350000005f0130008c000002c20000a13d000000800900043d000001300190009c000002c20000213d000000a00700043d000001300170009c000002c20000213d000000c00200043d000001310120009c000002c20000213d0000001f012000390000013204000041000000000531004b000000000500001900000000050480190000013201100197000000000601004b0000000004008019000001320110009c000000000405c019000000000104004b000002c20000c13d00000080012000390000000001010433000001310410009c000000210000213d0000003f04100039000000200a00008a0000000004a4016f000000400b00043d00000000044b00190000000005b4004b00000000050000190000000105004039000001310640009c000000210000213d0000000105500190000000210000c13d0000008003300039000000400040043f00000000061b0436000000a0022000390000000004210019000000000334004b000002c20000213d00060000000b001d00050000000a001d000700000007001d000300000008001d000000000301004b000000b90000613d000000000300001900000000046300190000000005230019000000000505043300000000005404350000002003300039000000000413004b000000b20000413d000400000006001d0000000001160019000000000001043500000133010000410000000000100439000800000009001d00000004009004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b0000004a0000613d000000080100002900000130051001970000013501000041000000000201041a0000013602200197000000000252019f000000000021041b0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000137011001c70000800d020000390000000203000039000001380400004104aa049b0000040f0000000803000029000000010120019000000007020000290000000605000029000002c20000613d0000000001050433000000000101004b000003770000c13d0000013d01000041000000000301041a0000013004200197000000400100043d0000002002100039000800000004001d0000000000420435000700000003001d000001300230019700000000002104350000012c0200004100000000030004140000012c0430009c00000000030280190000012c0410009c00000000010280190000004001100210000000c002300210000000000112019f0000013e011001c70000800d0200003900000001030000390000013f0400004104aa049b0000040f0000000101200190000002c20000613d000000080100006b0000025a0000613d0000000701000029000001360110019700000008011001af0000013d02000041000000000012041b0000002001000039000001000010044300000120000004430000014001000041000004ab0001042e0000013501000041000000000201041a00000000010004140000013002200197000000040320008c000001e90000c13d00000000030000310000001f0230018f00000005013002720000011e0000613d00000000050000190000000506500210000000000764034f000000000707043b00000000007604350000000105500039000000000615004b000001170000413d000000000502004b0000020e0000613d00000003022002100000000501100210000000000501043300000000052501cf000000000525022f000000000414034f000000000404043b0000010002200089000000000424022f00000000022401cf000000000252019f00000000002104350000020e0000013d0000001f0530018f0000013502000041000000000202041a000001300220019700000005063002720000013b0000613d00000000070000190000000508700210000000000981034f000000000909043b00000000009804350000000107700039000000000867004b000001340000413d000000000705004b000001490000613d00000003055002100000000506600210000000000706043300000000075701cf000000000757022f000000000161034f000000000101043b0000010005500089000000000151022f00000000015101cf000000000171019f00000000001604350000000001000414000000040520008c0000020f0000c13d00000000030000310000001f0230018f0000000501300272000001580000613d00000000050000190000000506500210000000000764034f000000000707043b00000000007604350000000105500039000000000615004b000001510000413d000000000502004b000002360000613d00000003022002100000000501100210000000000501043300000000052501cf000000000525022f000000000414034f000000000404043b0000010002200089000000000424022f00000000022401cf000000000252019f0000000000210435000002360000013d000001430540009c0000023b0000c13d000000440230008c000002c20000413d0000000402100370000000000802043b000001300280009c000002c20000213d0000002402100370000000000402043b000001310240009c000002c20000213d00000023024000390000013205000041000000000632004b000000000600001900000000060580190000013202200197000000000702004b0000000005008019000001320220009c000000000506c019000000000205004b000002c20000c13d0000000405400039000000000251034f000000000202043b000001310620009c000000210000213d000000bf06200039000000200900008a000000000696016f000001310760009c000000210000213d000000400060043f000000800020043f00000000042400190000002404400039000000000334004b000002c20000213d0000002003500039000000000131034f0000001f0320018f00000005042002720000019d0000613d00000000050000190000000506500210000000000761034f000000000707043b000000a00660003900000000007604350000000105500039000000000645004b000001950000413d000700000009001d000000000503004b000001ad0000613d0000000504400210000000000141034f0000000303300210000000a004400039000000000504043300000000053501cf000000000535022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f0000000000140435000000a001200039000000000001043500000133010000410000000000100439000800000008001d00000004008004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b0000004a0000613d0000013501000041000000000201041a000001360220019700000008022001af0000000805000029000000000021041b0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000137011001c70000800d020000390000000203000039000001380400004104aa049b0000040f00000008030000290000000101200190000002c20000613d000000400100043d000600000001001d000001390110009c000000210000213d00000006040000290000006001400039000000400010043f00000040014000390000013a02000041000000000021043500000020014000390000013b02000041000000000021043500000027010000390000000000140435000000800200043d0000000001000414000000040330008c0000040d0000c13d000000010200003900000000040000310000041d0000013d0000012c030000410000012c0410009c0000000001038019000000c00110021004aa04a50000040f0001000000010355000000000301001900000060033002700000001f0430018f0000012c0030019d0000012c033001970000000505300272000001fe0000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b000001f70000413d000000000604004b0000020c0000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000000101200190000002640000613d000002360000013d0000012c040000410000012c0510009c0000000001048019000000c0011002100000006003300210000000000131019f04aa04a50000040f0001000000010355000000000301001900000060033002700000001f0430018f0000012c0030019d0000012c033001970000000505300272000002260000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000756004b0000021f0000413d000000000604004b000002340000613d00000003044002100000000505500210000000000605043300000000064601cf000000000646022f000000000151034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f00000000001504350000000101200190000002660000613d0000012c010000410000012c0230009c00000000030180190000006001300210000004ab0001042e000001440540009c0000026e0000c13d0000000004000416000000000404004b000002c20000c13d000000240330008c000002c20000413d0000000401100370000000000401043b000001300140009c000002c20000213d000000800020043f000000a00040043f0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000148011001c70000800d020000390000000103000039000700000004001d0000013f04000041000800000007001d04aa049b0000040f000000070400002900000008030000290000000101200190000002c20000613d000000000104004b000002c40000c13d000000400100043d00000064021000390000014a03000041000000000032043500000044021000390000014b03000041000000000032043500000024021000390000002603000039000000530000013d0000006001300210000004ac000104300000006001300210000004ac00010430000001450310009c000002750000c13d0000000001000416000000000101004b000002c20000c13d0000027d0000013d000001450140009c000002840000c13d0000000001000416000000000101004b000002c20000c13d000000a00020043f0000028d0000013d000001460110009c0000029a0000c13d0000000001000416000000000101004b000002c20000c13d0000013501000041000000000101041a0000013002100197000000a00020043f0000002001000039000000800010043f000000c001000039000000400010043f0000015a01000041000004ab0001042e000001460140009c0000029a0000c13d0000000001000416000000000101004b000002c20000c13d0000013501000041000000000101041a0000013001100197000000a00010043f0000002001000039000000800010043f000000c001000039000000400010043f000000800100003900000147020000410000015003000041000001500410009c000000000103801900000040011002100000015101100041000000000121019f000004ab0001042e0000013c01000041000000800010043f0000002001000039000000840010043f0000004201000039000000a40010043f0000015601000041000000c40010043f0000015701000041000000e40010043f0000015801000041000001040010043f0000015901000041000004ac000104300000013501000041000000000201041a000001360220019700000008022001af0000000805000029000000000021041b0000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000137011001c70000800d020000390000000203000039000001380400004104aa049b0000040f00000008080000290000000101200190000002c20000613d000000800100043d000000000101004b000002d00000c13d000000400100043d000001490210009c000000210000213d000002cb0000013d0000000001000019000004ac000104300000013601300197000000000114019f0000013d02000041000000000012041b000000400100043d000001490210009c000000210000213d0000002002100039000000400020043f00000000000104350000000002000019000002930000013d000000400900043d000001390190009c000000210000213d0000006001900039000000400010043f00000040019000390000013a02000041000000000021043500000020019000390000013b02000041000000000021043500000027010000390000000000190435000000800200043d0000000001000414000000040380008c000002e40000c13d00000001020000390000000004000031000002f70000013d0000012c030000410000012c0410009c00000000010380190000012c0420009c00000000020380190000006002200210000000c001100210000000000121019f0000014d011001c70000000002080019000700000009001d04aa04a50000040f00000007090000290000000808000029000000010220018f000100000001035500000060011002700000012c0010019d0000012c0410019700000060030000390000008001000039000000000504004b000003230000c13d0000000003030433000000000202004b000003530000c13d000000000203004b0000038c0000c13d000000400100043d0000013c0200004100000000002104350000000402100039000000200300003900000000003204350000000002090433000000240310003900000000002304350000004403100039000000000402004b000003140000613d000000000400001900000000053400190000002004400039000000000694001900000000060604330000000000650435000000000524004b0000030d0000413d0000001f04200039000000200500008a000000000454016f0000000002320019000000000002043500000044024000390000012c030000410000012c0420009c00000000020380190000012c0410009c000000000103801900000040011002100000006002200210000000000112019f000004ac00010430000001310140009c000000210000213d0000003f01400039000000200300008a000000000131016f000000400300043d0000000001130019000000000531004b00000000050000190000000105004039000001310610009c000000210000213d0000000105500190000000210000c13d000000000a090019000000400010043f0000001f0540018f000000000143043600000001060003670000000504400272000003410000613d000000000700001900000005087002100000000009810019000000000886034f000000000808043b00000000008904350000000107700039000000000847004b000003390000413d000000000705004b000000080800002900000000090a0019000002fb0000613d0000000504400210000000000646034f00000000044100190000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000002fb0000013d000000000103004b000002be0000c13d0000013301000041000000000010043900000004008004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b000002be0000c13d000000400100043d00000044021000390000014e03000041000000000032043500000024021000390000001d0300003900000000003204350000013c0200004100000000002104350000000402100039000000200300003900000000003204350000012c020000410000012c0310009c000000000102801900000040011002100000014f011001c7000004ac00010430000000400400043d000001390140009c000000210000213d0000006001400039000000400010043f00000040014000390000013a0200004100000000002104350000002701000039000200000004001d00000000021404360000013b01000041000100000002001d000000000012043500000000020504330000000001000414000000040330008c000003950000c13d00000001020000390000000003000031000003a90000013d0000012c020000410000012c0430009c00000000030280190000012c0410009c000000000102801900000040011002100000006002300210000000000112019f000004ac000104300000012c0300004100000004050000290000012c0450009c000000000503801900000040045002100000012c0520009c00000000020380190000006002200210000000000242019f0000012c0410009c0000000001038019000000c001100210000000000112019f000000080200002904aa04a50000040f000000010220018f000100000001035500000060011002700000012c0010019d0000012c031001970000006001000039000000000403004b000003c90000c13d0000000001010433000000000202004b000003f70000c13d000000000201004b000004830000c13d000000400400043d000800000004001d0000013c01000041000000000014043500000004014000390000002002000039000000000021043500000002010000290000000003010433000700000003001d000000240140003900000000003104350000004402400039000000010100002904aa048d0000040f00000007010000290000001f01100039000000050110017f00000044011000390000012c020000410000012c0310009c00000000010280190000000804000029000004870000013d000001310130009c0000000504000029000000210000213d0000003f01300039000000000441016f000000400100043d0000000004410019000000000514004b00000000050000190000000105004039000001310640009c000000210000213d0000000105500190000000210000c13d000000400040043f0000001f0430018f000000000931043600000001050003670000000503300272000003e60000613d000000000600001900000005076002100000000008790019000000000775034f000000000707043b00000000007804350000000106600039000000000736004b000003de0000413d000300000009001d000000000604004b000003ac0000613d0000000503300210000000000535034f00000003033000290000000304400210000000000603043300000000064601cf000000000646022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000464019f0000000000430435000003ac0000013d000000000101004b00000007020000290000000803000029000000e60000c13d0000013301000041000000000010043900000004003004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b0000000702000029000000e60000c13d000003650000013d0000012c030000410000012c0410009c00000000010380190000012c0420009c00000000020380190000006002200210000000c001100210000000000121019f0000014d011001c7000000080200002904aa04a50000040f000000010220018f000100000001035500000060011002700000012c0010019d0000012c0410019700000060030000390000008001000039000000000504004b0000043e0000c13d0000000003030433000000000202004b0000046b0000c13d000000000203004b0000038c0000c13d000000400100043d0000013c02000041000000000021043500000004021000390000002003000039000000000032043500000006070000290000000002070433000000240310003900000000002304350000004403100039000000000402004b0000043b0000613d000000000400001900000000053400190000002004400039000000000674001900000000060604330000000000650435000000000524004b000004340000413d0000001f042000390000000705000029000003160000013d000001310140009c0000000703000029000000210000213d0000003f01400039000000000131016f000000400300043d0000000001130019000000000531004b00000000050000190000000105004039000001310610009c000000210000213d0000000105500190000000210000c13d000000400010043f0000001f0540018f0000000001430436000000010600036700000005044002720000045b0000613d000000000700001900000005087002100000000009810019000000000886034f000000000808043b00000000008904350000000107700039000000000847004b000004530000413d000000000705004b000004210000613d0000000504400210000000000646034f00000000044100190000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000004210000013d000000000103004b0000047e0000c13d00000133010000410000000000100439000000080100002900000004001004430000012c0100004100000000020004140000012c0320009c0000000002018019000000c00120021000000134011001c7000080020200003904aa04a00000040f0000000102200190000004820000613d000000000101043b000000000101004b000003650000613d000000400100043d000001490210009c000000210000213d000002cb0000013d000000000001042f0000012c020000410000012c0310009c000000000102801900000003040000290000012c0340009c000000000402801900000040024002100000006001100210000000000121019f000004ac00010430000000000403004b000004970000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000534004b000004900000413d00000000012300190000000000010435000000000001042d000000000001042f0000049e002104210000000102000039000000000001042d0000000002000019000000000001042d000004a3002104230000000102000039000000000001042d0000000002000019000000000001042d000004a8002104250000000102000039000000000001042d0000000002000019000000000001042d000004aa00000432000004ab0001042e000004ac0001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009fffffffffffffffffffffffffffffffffffffffffffffffff000000000000007f00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff80000000000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcffffffffffffffffffffffff00000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b000000000000000000000000000000000000000000000000ffffffffffffff9f206661696c656400000000000000000000000000000000000000000000000000416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c08c379a000000000000000000000000000000000000000000000000000000000b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610302000000000000000000000000000000000000400000000000000000000000007e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f0000000200000000000000000000000000000040000001000000000000000000ffffffff000000000000000000000000000000000000000000000000000000003659cfe6000000000000000000000000000000000000000000000000000000004f1ef286000000000000000000000000000000000000000000000000000000008f28397000000000000000000000000000000000000000000000000000000000f851a440000000000000000000000000000000000000000000000000000000005c60da1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000200000000000000000000000000000000000040000000800000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf6464726573730000000000000000000000000000000000000000000000000000455243313936373a206e65772061646d696e20697320746865207a65726f206100000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffdf00000000000000000000000000000000000000000000002000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000006f74206120636f6e747261637400000000000000000000000000000000000000455243313936373a206e657720696d706c656d656e746174696f6e206973206e5472616e73706172656e745570677261646561626c6550726f78793a2061646d696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267657400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a40000008000000000000000000000000000000000000000000000000000000020000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000007444ff0b02dc9864c7dbf97ccd7719c286d6972190eeb0285ea9e04a713977c0", - "linkReferences": {}, - "deployedLinkReferences": {}, - "factoryDeps": {} -} diff --git a/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol b/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol index e93d5c987..fda1c5932 100644 --- a/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol +++ b/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +pragma solidity ^0.8.20; import {L2SharedBridge} from "../bridge/L2SharedBridge.sol"; import {L2StandardERC20} from "../bridge/L2StandardERC20.sol"; diff --git a/system-contracts/foundry.toml b/system-contracts/foundry.toml index ee3885489..06485883a 100644 --- a/system-contracts/foundry.toml +++ b/system-contracts/foundry.toml @@ -11,3 +11,4 @@ remappings = [ [profile.default.zksync] zksolc = "1.5.0" +enable_eravm_extensions = true diff --git a/system-contracts/scripts/calculate-hashes.ts b/system-contracts/scripts/calculate-hashes.ts index a8fc8036f..1b9f355a5 100644 --- a/system-contracts/scripts/calculate-hashes.ts +++ b/system-contracts/scripts/calculate-hashes.ts @@ -42,10 +42,10 @@ const findFilesEndingWith = (path: string, endingWith: string): string[] => { } }; -const SOLIDITY_ARTIFACTS_DIR = "artifacts-zk"; +const SOLIDITY_ARTIFACTS_DIR = "zkout"; const getSolidityContractDetails = (dir: string, contractName: string): ContractDetails => { - const bytecodePath = join(SOLIDITY_ARTIFACTS_DIR, dir, contractName + ".sol", contractName + ".json"); + const bytecodePath = join(SOLIDITY_ARTIFACTS_DIR, contractName + ".sol", contractName + ".json"); const sourceCodePath = join(dir, contractName + ".sol"); return { contractName, @@ -55,7 +55,7 @@ const getSolidityContractDetails = (dir: string, contractName: string): Contract }; const getSolidityContractsDetails = (dir: string): ContractDetails[] => { - const bytecodesDir = join(SOLIDITY_ARTIFACTS_DIR, dir); + const bytecodesDir = SOLIDITY_ARTIFACTS_DIR; const dirsEndingWithSol = findDirsEndingWith(bytecodesDir, ".sol"); const contractNames = dirsEndingWithSol.map((d) => d.replace(".sol", "")); const solidityContractsDetails = contractNames.map((c) => getSolidityContractDetails(dir, c)); @@ -100,7 +100,7 @@ const readBytecode = (details: ContractDetails): string => { try { if (details.bytecodePath.endsWith(".json")) { const jsonFile = fs.readFileSync(absolutePath, "utf8"); - return ethers.utils.hexlify(JSON.parse(jsonFile).bytecode); + return ethers.utils.hexlify("0x" + JSON.parse(jsonFile).bytecode.object); } else { return ethers.utils.hexlify(fs.readFileSync(absolutePath)); } diff --git a/system-contracts/scripts/preprocess-bootloader.ts b/system-contracts/scripts/preprocess-bootloader.ts index 952181455..e3dc18aaf 100644 --- a/system-contracts/scripts/preprocess-bootloader.ts +++ b/system-contracts/scripts/preprocess-bootloader.ts @@ -13,7 +13,8 @@ const preprocess = require("preprocess"); const SYSTEM_PARAMS = require("../../SystemConfig.json"); /* eslint-enable@typescript-eslint/no-var-requires */ -const OUTPUT_DIR = "bootloader/build"; +const OUTPUT_DIR_1 = "contracts-preprocessed/bootloader"; +const OUTPUT_DIR_2 = "bootloader/build"; const PREPROCCESING_MODES = ["proved_batch", "playground_batch"]; @@ -224,15 +225,32 @@ async function main() { }); const provedBootloaderWithTests = preprocess.preprocess(bootloaderWithTests, { BOOTLOADER_TYPE: "proved_batch" }); - if (!existsSync(OUTPUT_DIR)) { - mkdirSync(OUTPUT_DIR); + if (!existsSync(OUTPUT_DIR_1)) { + mkdirSync(OUTPUT_DIR_1); } - writeFileSync(`${OUTPUT_DIR}/bootloader_test.yul`, provedBootloaderWithTests); - writeFileSync(`${OUTPUT_DIR}/proved_batch.yul`, provedBatchBootloader); - writeFileSync(`${OUTPUT_DIR}/playground_batch.yul`, playgroundBatchBootloader); - writeFileSync(`${OUTPUT_DIR}/gas_test.yul`, gasTestBootloader); - writeFileSync(`${OUTPUT_DIR}/fee_estimate.yul`, feeEstimationBootloader); + if (!existsSync(OUTPUT_DIR_2)) { + mkdirSync(OUTPUT_DIR_2); + } + + const transferTest = readFileSync("bootloader/tests/transfer_test.yul").toString(); + const dummy = readFileSync("bootloader/tests/dummy.yul").toString(); + + writeFileSync(`${OUTPUT_DIR_1}/bootloader_test.yul`, provedBootloaderWithTests); + writeFileSync(`${OUTPUT_DIR_1}/proved_batch.yul`, provedBatchBootloader); + writeFileSync(`${OUTPUT_DIR_1}/playground_batch.yul`, playgroundBatchBootloader); + writeFileSync(`${OUTPUT_DIR_1}/gas_test.yul`, gasTestBootloader); + writeFileSync(`${OUTPUT_DIR_1}/fee_estimate.yul`, feeEstimationBootloader); + writeFileSync(`${OUTPUT_DIR_1}/dummy.yul`, dummy); + writeFileSync(`${OUTPUT_DIR_1}/transfer_test.yul`, transferTest); + + writeFileSync(`${OUTPUT_DIR_2}/bootloader_test.yul`, provedBootloaderWithTests); + writeFileSync(`${OUTPUT_DIR_2}/proved_batch.yul`, provedBatchBootloader); + writeFileSync(`${OUTPUT_DIR_2}/playground_batch.yul`, playgroundBatchBootloader); + writeFileSync(`${OUTPUT_DIR_2}/gas_test.yul`, gasTestBootloader); + writeFileSync(`${OUTPUT_DIR_2}/fee_estimate.yul`, feeEstimationBootloader); + writeFileSync(`${OUTPUT_DIR_2}/dummy.yul`, dummy); + writeFileSync(`${OUTPUT_DIR_2}/transfer_test.yul`, transferTest); console.log("Bootloader preprocessing done!"); } From dcb0eca154118b7a396f3008bd42a5fb680658f9 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 22 Oct 2024 12:59:02 +0200 Subject: [PATCH 12/54] feat(zkstack): Show chain info (#955) Signed-off-by: Danil --- .../ChainConfigurationReader.s.sol | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 l1-contracts/deploy-scripts/ChainConfigurationReader.s.sol diff --git a/l1-contracts/deploy-scripts/ChainConfigurationReader.s.sol b/l1-contracts/deploy-scripts/ChainConfigurationReader.s.sol new file mode 100644 index 000000000..54a9ebe8a --- /dev/null +++ b/l1-contracts/deploy-scripts/ChainConfigurationReader.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import {Script, console2 as console} from "forge-std/Script.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; +import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {StateTransitionManager} from "contracts/state-transition/StateTransitionManager.sol"; +import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; +import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; + +contract ChainConfigurationReader is Script { + function run(address stmAddress, uint256 chainId) public { + StateTransitionManager stm = StateTransitionManager(stmAddress); + IZkSyncHyperchain diamondProxy = IZkSyncHyperchain(stm.getHyperchain(chainId)); + address payable chainAdmin = payable(stm.getChainAdmin(chainId)); + address tokenMultiplierSetter = ChainAdmin(chainAdmin).tokenMultiplierSetter(); + address owner = ChainAdmin(chainAdmin).owner(); + address basetoken = diamondProxy.getBaseToken(); + (uint32 major, uint32 minor, uint32 patch) = diamondProxy.getSemverProtocolVersion(); + address validatorTimelock = stm.validatorTimelock(); + PubdataPricingMode pubdataPricingMode = diamondProxy.getPubdataPricingMode(); + + uint256 baseTokenGasPriceMultiplierNominator = diamondProxy.baseTokenGasPriceMultiplierNominator(); + uint256 baseTokenGasPriceMultiplierDenominator = diamondProxy.baseTokenGasPriceMultiplierDenominator(); + + console.log("=====INFO ABOUT CHAIN %d =====", chainId); + console.log("Diamond Proxy %s", address(diamondProxy)); + console.log("ChainAdmin %s", chainAdmin); + console.log("Token Multiplier Setter of ChainAdmin %s", tokenMultiplierSetter); + console.log("Owner of ChainAdmin %s", owner); + console.log("Protocol Version %d.%d.%d", major, minor, patch); + if (pubdataPricingMode == PubdataPricingMode.Validium) { + console.log("Pubdata Pricing Mode: Validium"); + } else if (pubdataPricingMode == PubdataPricingMode.Rollup) { + console.log("Pubdata Pricing Mode: Rollup"); + } + + console.log("==Validators=="); + getNewValidators(validatorTimelock, chainId); + console.log("==BASE TOKEN=="); + console.log("address: %s", basetoken); + console.log("nominator: %s", baseTokenGasPriceMultiplierNominator); + console.log("denominator: %s", baseTokenGasPriceMultiplierDenominator); + } + + function getNewValidators(address validatorTimelock, uint256 chainId) internal { + bytes32[] memory topics = new bytes32[](2); + topics[0] = ValidatorTimelock.ValidatorAdded.selector; + topics[1] = bytes32(chainId); + Vm.EthGetLogs[] memory logs = vm.eth_getLogs(1, block.number, validatorTimelock, topics); + for (uint256 i = 0; i < logs.length; i++) { + Vm.EthGetLogs memory log = logs[i]; + console.log("New Validator", bytesToAddress(log.data)); + } + } + + function bytesToAddress(bytes memory bys) private pure returns (address addr) { + assembly { + addr := mload(add(bys, 32)) + } + } +} From 72a3e8ec1b68e3632b0cd37c8589450f3cf4987b Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Tue, 1 Oct 2024 11:33:30 +0100 Subject: [PATCH 13/54] Add time window asserter --- .../deploy-scripts/DeployL2Contracts.sol | 21 +++++++++++++++++++ .../dev-contracts/TimestampAsserter.sol | 12 +++++++++++ 2 files changed, 33 insertions(+) create mode 100644 l2-contracts/contracts/dev-contracts/TimestampAsserter.sol diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 4578f1717..9ce7583fd 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -33,6 +33,7 @@ contract DeployL2Script is Script { address consensusRegistryProxy; address multicall3; address forceDeployUpgraderAddress; + address timestampAsserter; } struct ContractsBytecodes { @@ -45,6 +46,7 @@ contract DeployL2Script is Script { bytes consensusRegistryProxyBytecode; bytes multicall3Bytecode; bytes forceDeployUpgrader; + bytes timestampAsserterBytecode; } function run() public { @@ -67,6 +69,7 @@ contract DeployL2Script is Script { deployConsensusRegistry(); deployConsensusRegistryProxy(); deployMulticall3(); + deployTimestampAsserter(); saveOutput(); } @@ -157,6 +160,10 @@ contract DeployL2Script is Script { contracts.forceDeployUpgrader = Utils.readFoundryBytecode( "/../l2-contracts/zkout/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" ); + + contracts.timestampAsserterBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/TimestampAsserter.sol/TimestampAsserter.json" + ); } function initializeConfig() internal { @@ -178,6 +185,7 @@ contract DeployL2Script is Script { vm.serializeAddress("root", "consensus_registry_implementation", config.consensusRegistryImplementation); vm.serializeAddress("root", "consensus_registry_proxy", config.consensusRegistryProxy); vm.serializeAddress("root", "multicall3", config.multicall3); + vm.serializeAddress("root", "timestamp_asserter", config.timestampAsserter); string memory toml = vm.serializeAddress("root", "l2_default_upgrader", config.forceDeployUpgraderAddress); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-deploy-l2-contracts.toml"); @@ -295,6 +303,19 @@ contract DeployL2Script is Script { }); } + function deployTimestampAsserter() internal { + config.timestampAsserter = Utils.deployThroughL1({ + bytecode: contracts.timestampAsserterBytecode, + constructorargs: hex"", + create2salt: "", + l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, + factoryDeps: new bytes[](0), + chainId: config.chainId, + bridgehubAddress: config.bridgehubAddress, + l1SharedBridgeProxy: config.l1SharedBridgeProxy + }); + } + // Deploy a transparent upgradable proxy for the already deployed consensus registry // implementation and save its address into the config. function deployConsensusRegistryProxy() internal { diff --git a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol new file mode 100644 index 000000000..8fc1e66b5 --- /dev/null +++ b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +interface ITimestampAsserter { + function assertTimestampInRange(uint256 start, uint256 end) external view; +} + +contract TimestampAsserter is ITimestampAsserter { + function assertTimestampInRange(uint256 start, uint256 end) public view { + require(start < block.timestamp && end > block.timestamp, "Timestamp is out of range"); + } +} From 4c696850f4ed4bc122807abab553ee8554937cb1 Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Wed, 30 Oct 2024 16:44:48 +0000 Subject: [PATCH 14/54] Changed assertion message --- l2-contracts/contracts/dev-contracts/TimestampAsserter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol index 8fc1e66b5..1d4914987 100644 --- a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol +++ b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol @@ -7,6 +7,6 @@ interface ITimestampAsserter { contract TimestampAsserter is ITimestampAsserter { function assertTimestampInRange(uint256 start, uint256 end) public view { - require(start < block.timestamp && end > block.timestamp, "Timestamp is out of range"); + require(start < block.timestamp && end > block.timestamp, "Block timestamp is out of range"); } } From 9ed4ad048afa236357c2442b6533172ef5b1c5a9 Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Thu, 31 Oct 2024 09:30:28 +0000 Subject: [PATCH 15/54] Review feedback --- .../dev-contracts/ITimestampAsserter.sol | 6 ++++++ .../dev-contracts/TimestampAsserter.sol | 20 +++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol diff --git a/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol new file mode 100644 index 000000000..24c9e7d2a --- /dev/null +++ b/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +interface ITimestampAsserter { + function assertTimestampInRange(uint256 start, uint256 end) external view; +} \ No newline at end of file diff --git a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol index 1d4914987..ae9e13b5c 100644 --- a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol +++ b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol @@ -1,12 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -interface ITimestampAsserter { - function assertTimestampInRange(uint256 start, uint256 end) external view; -} +import "./ITimestampAsserter.sol"; +error TimestampOutOfRange(uint256 currentTimestamp, uint256 start, uint256 end); + +/// @title TimestampAsserter +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev A contract that verifies if the current block timestamp falls within a specified range. +/// This is useful for custom account abstraction where time-bound checks are needed but accessing block.timestamp +/// directly is not possible. contract TimestampAsserter is ITimestampAsserter { - function assertTimestampInRange(uint256 start, uint256 end) public view { - require(start < block.timestamp && end > block.timestamp, "Block timestamp is out of range"); + function assertTimestampInRange(uint256 _start, uint256 _end) public view { + if (block.timestamp < _start || block.timestamp > _end) { + revert TimestampOutOfRange(block.timestamp, _start, _end); + } } -} +} \ No newline at end of file From 9f3f710d67d6dd759a303b9f716c8e20dc2800c5 Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Thu, 31 Oct 2024 09:35:56 +0000 Subject: [PATCH 16/54] Fix lint --- l2-contracts/contracts/dev-contracts/TimestampAsserter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol index ae9e13b5c..802172400 100644 --- a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol +++ b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import "./ITimestampAsserter.sol"; +import {ITimestampAsserter} from "./ITimestampAsserter.sol"; error TimestampOutOfRange(uint256 currentTimestamp, uint256 start, uint256 end); From 698f6ae961c957a7d183ee13caa0b1694a3c863a Mon Sep 17 00:00:00 2001 From: Ivan Schasny <31857042+ischasny@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:43:40 +0000 Subject: [PATCH 17/54] Update l2-contracts/contracts/dev-contracts/TimestampAsserter.sol Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> --- l2-contracts/contracts/dev-contracts/TimestampAsserter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol index 802172400..b1eafad3f 100644 --- a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol +++ b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol @@ -12,7 +12,7 @@ error TimestampOutOfRange(uint256 currentTimestamp, uint256 start, uint256 end); /// This is useful for custom account abstraction where time-bound checks are needed but accessing block.timestamp /// directly is not possible. contract TimestampAsserter is ITimestampAsserter { - function assertTimestampInRange(uint256 _start, uint256 _end) public view { + function assertTimestampInRange(uint256 _start, uint256 _end) external view { if (block.timestamp < _start || block.timestamp > _end) { revert TimestampOutOfRange(block.timestamp, _start, _end); } From 50a0db7722fee9ad9312fb21cda6916fada1e1d9 Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Thu, 31 Oct 2024 10:44:46 +0000 Subject: [PATCH 18/54] add new lines --- l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol | 2 +- l2-contracts/contracts/dev-contracts/TimestampAsserter.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol index 24c9e7d2a..47d9ec103 100644 --- a/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol +++ b/l2-contracts/contracts/dev-contracts/ITimestampAsserter.sol @@ -3,4 +3,4 @@ pragma solidity 0.8.24; interface ITimestampAsserter { function assertTimestampInRange(uint256 start, uint256 end) external view; -} \ No newline at end of file +} diff --git a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol index b1eafad3f..445313fe0 100644 --- a/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol +++ b/l2-contracts/contracts/dev-contracts/TimestampAsserter.sol @@ -17,4 +17,4 @@ contract TimestampAsserter is ITimestampAsserter { revert TimestampOutOfRange(block.timestamp, _start, _end); } } -} \ No newline at end of file +} From b7b9f1b1b23c8db2d2d31868eef88c7e9144e438 Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Mon, 11 Nov 2024 14:12:31 +0000 Subject: [PATCH 19/54] fix: add deploy timestap asserter command --- l1-contracts/deploy-scripts/DeployL2Contracts.sol | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 9ce7583fd..3953ce20c 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -122,6 +122,15 @@ contract DeployL2Script is Script { saveOutput(); } + function runDeployTimestampAsserter() public { + initializeConfig(); + loadContracts(false); + + deployTimestampAsserter()(); + + saveOutput(); + } + function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat contracts.l2StandardErc20FactoryBytecode = Utils.readFoundryBytecode( From 46d75088e7ddb534101874c3ec15b877da1cb417 Mon Sep 17 00:00:00 2001 From: Ivan Schasny Date: Mon, 11 Nov 2024 14:24:29 +0000 Subject: [PATCH 20/54] Typo --- l1-contracts/deploy-scripts/DeployL2Contracts.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 3953ce20c..899cc9263 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -126,7 +126,7 @@ contract DeployL2Script is Script { initializeConfig(); loadContracts(false); - deployTimestampAsserter()(); + deployTimestampAsserter(); saveOutput(); } From 9c3118cc70ad6c8a76f1c21719fd87b563fda4b3 Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 11 Nov 2024 22:00:10 +0700 Subject: [PATCH 21/54] add new chain registrator contract Signed-off-by: Danil --- .../chain-registrator/ChainRegistrator.sol | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 l1-contracts/contracts/chain-registrator/ChainRegistrator.sol diff --git a/l1-contracts/contracts/chain-registrator/ChainRegistrator.sol b/l1-contracts/contracts/chain-registrator/ChainRegistrator.sol new file mode 100644 index 000000000..f01bd5dd6 --- /dev/null +++ b/l1-contracts/contracts/chain-registrator/ChainRegistrator.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {IBridgehub} from "../bridgehub/IBridgehub.sol"; +import {ZkSyncHyperchainStorage, PubdataPricingMode} from "../state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {IZkSyncHyperchain} from "../state-transition/chain-interfaces/IZkSyncHyperchain.sol"; +import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev ChainRegistrator serves as the main point for chain registration. +contract ChainRegistrator is Ownable2StepUpgradeable { + /// Address that will be used for deploying l2 contracts + address l2Deployer; + /// Bridgehub + IBridgehub bridgehub; + + /// Chains that has been succesfuly deployed + mapping(bytes32 => bool) public deployedChains; + /// Proposal for chain registration + mapping(bytes32 => ChainConfig) public proposedChains; + + error ProposalNotFound(); + error ChainIsAlreadyDeployed(); + error ChainIsNotYetDeployed(); + error BridgeIsNotRegistered(); + + /// @notice new chain is deployed + event NewChainDeployed( + uint256 indexed chainId, + address diamondProxy, + address chainAdmin + ); + + /// @notice new chain is proposed to register + event NewChainRegistrationProposal( + uint256 indexed chainId, + address author, + bytes32 key + ); + + /// @notice Shared bridge is registered on l2 + event SharedBridgeRegistered( + uint256 indexed chainId, + address l2Address + ); + + /// @notice new chain is deployed + event L2DeployerChanged( + address newDeployer + ); + + + struct BaseToken { + address tokenAddress; + address tokenMultiplierSetter; + uint128 gasPriceMultiplierNominator; + uint128 gasPriceMultiplierDenominator; + } + + struct ChainConfig { + /// @param Chain id of the new chain should be unique for this bridgehub + uint256 chainId; + /// @param pubdataPricingMode How the users will charged for pubdata. + PubdataPricingMode pubdataPricingMode; + /// @param baseToken of the chain + BaseToken baseToken; + /// @param Operator for making commit txs. + address commitOperator; + /// @param Operator for making Prove and Execute transactions + address operator; + /// @param Governor of the chain. Ownership of the chain will be transferred to this operator + address governor; + } + + function proposeChainRegistration(ChainConfig calldata config) public { + bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); + if (deployedChains[key] || bridgehub.getHyperchain(config.chainId) != address(0)) { + revert ChainIsAlreadyDeployed(); + } + proposedChains[key] = config; + // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. + if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { + uint256 amount = 1 ether * config.baseToken.gasPriceMultiplierNominator / config.baseToken.gasPriceMultiplierDenominator; + if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { + IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); + } + } + emit NewChainRegistrationProposal(config.chainId, msg.sender, key); + } + + function changeDeployer(address newDeployer) onlyOwner public { + l2Deployer = newDeployer; + emit L2DeployerChanged(l2Deployer); + } + + + function chainRegistered(address author, uint256 chainId) onlyOwner public { + bytes32 key = keccak256(abi.encode(author, chainId)); + ChainConfig memory config = proposedChains[key]; + if (config.chainId == 0) { + revert ProposalNotFound(); + } + + if (deployedChains[key]) { + revert ChainIsAlreadyDeployed(); + } + address diamondProxy = bridgehub.getHyperchain(chainId); + if (diamondProxy == address(0)) { + revert ChainIsNotYetDeployed(); + } + address chainAdmin = IZkSyncHyperchain(diamondProxy).getAdmin(); + address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); + if (l2BridgeAddress == address(0)) { + revert BridgeIsNotRegistered(); + } + emit NewChainDeployed(chainId, address(diamondProxy), address(chainAdmin)); + emit SharedBridgeRegistered(chainId, l2BridgeAddress); + deployedChains[key] = true; + } +} \ No newline at end of file From 9fd56a374c515e5bea39026e4a5d31057c8a5142 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 12 Nov 2024 00:21:50 +0700 Subject: [PATCH 22/54] Add test Signed-off-by: Danil --- ...hainRegistrator.sol => ChainRegistrar.sol} | 26 ++++- .../chain-registrator/ChainRegistrator.t.sol | 107 ++++++++++++++++++ 2 files changed, 127 insertions(+), 6 deletions(-) rename l1-contracts/contracts/chain-registrator/{ChainRegistrator.sol => ChainRegistrar.sol} (82%) create mode 100644 l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol diff --git a/l1-contracts/contracts/chain-registrator/ChainRegistrator.sol b/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol similarity index 82% rename from l1-contracts/contracts/chain-registrator/ChainRegistrator.sol rename to l1-contracts/contracts/chain-registrator/ChainRegistrar.sol index f01bd5dd6..cea706e73 100644 --- a/l1-contracts/contracts/chain-registrator/ChainRegistrator.sol +++ b/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol @@ -5,14 +5,16 @@ pragma solidity 0.8.24; import {IBridgehub} from "../bridgehub/IBridgehub.sol"; import {ZkSyncHyperchainStorage, PubdataPricingMode} from "../state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; import {IZkSyncHyperchain} from "../state-transition/chain-interfaces/IZkSyncHyperchain.sol"; +import {IStateTransitionManager} from "../state-transition/IStateTransitionManager.sol"; import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -/// @dev ChainRegistrator serves as the main point for chain registration. -contract ChainRegistrator is Ownable2StepUpgradeable { +/// @dev ChainRegistrar serves as the main point for chain registration. +contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { /// Address that will be used for deploying l2 contracts address l2Deployer; /// Bridgehub @@ -76,9 +78,20 @@ contract ChainRegistrator is Ownable2StepUpgradeable { address governor; } + constructor(address _bridgehub, address _l2Deployer) { + bridgehub = IBridgehub(_bridgehub); + l2Deployer = _l2Deployer; + } + + /// @notice used to initialize the contract + function initialize(address _owner) external { + _transferOwnership(_owner); + } + + function proposeChainRegistration(ChainConfig calldata config) public { bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); - if (deployedChains[key] || bridgehub.getHyperchain(config.chainId) != address(0)) { + if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { revert ChainIsAlreadyDeployed(); } proposedChains[key] = config; @@ -108,16 +121,17 @@ contract ChainRegistrator is Ownable2StepUpgradeable { if (deployedChains[key]) { revert ChainIsAlreadyDeployed(); } - address diamondProxy = bridgehub.getHyperchain(chainId); - if (diamondProxy == address(0)) { + address stm = bridgehub.stateTransitionManager(chainId); + if (stm == address(0)) { revert ChainIsNotYetDeployed(); } + address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); address chainAdmin = IZkSyncHyperchain(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); } - emit NewChainDeployed(chainId, address(diamondProxy), address(chainAdmin)); + emit NewChainDeployed(chainId, diamondProxy, chainAdmin); emit SharedBridgeRegistered(chainId, l2BridgeAddress); deployedChains[key] = true; } diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol new file mode 100644 index 000000000..2e4b585d5 --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {Test} from "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {DummyStateTransitionManagerWBH} from "contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol"; +import "contracts/bridgehub/Bridgehub.sol"; +import "contracts/chain-registrator/ChainRegistrar.sol"; +import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import "contracts/dev-contracts/test/DummyBridgehub.sol"; +import "contracts/dev-contracts/test/DummySharedBridge.sol"; +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {console2 as console} from "forge-std/Script.sol"; +import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; +import {ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; + +contract ChainRegistrarTest is Test { + DummyBridgehub private bridgeHub; + DummyStateTransitionManagerWBH private stm; + address private admin; + address private deployer; + ChainRegistrar private chainRegistrar; + L1SharedBridge private sharedBridge; + bytes diamondCutData; + + constructor () public { + bridgeHub = new DummyBridgehub(); + stm = new DummyStateTransitionManagerWBH(address(bridgeHub)); + admin = makeAddr("admin"); + deployer = makeAddr("deployer"); + address defaultOwner = bridgeHub.owner(); + vm.prank(defaultOwner); + bridgeHub.transferOwnership(admin); + vm.prank(admin); + bridgeHub.acceptOwnership(); + + sharedBridge = new L1SharedBridge({ + _l1WethAddress: makeAddr("weth"), + _bridgehub: IBridgehub(bridgeHub), + _eraChainId: 270, + _eraDiamondProxy: makeAddr("era") + }); + address defaultOwnerSb = sharedBridge.owner(); + vm.prank(defaultOwnerSb); + sharedBridge.transferOwnership(admin); + vm.startPrank(admin); + sharedBridge.acceptOwnership(); + bridgeHub.setSharedBridge(address(sharedBridge)); + bridgeHub.addStateTransitionManager(address(stm)); + bridgeHub.addToken(ETH_TOKEN_ADDRESS); + + + Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](0); + + Diamond.DiamondCutData memory diamondCutDataStruct = Diamond.DiamondCutData({ + facetCuts: facetCuts, + initAddress: makeAddr("init"), + initCalldata: bytes("") + }); + ChainCreationParams memory chainCreationParams = ChainCreationParams({ + genesisUpgrade: makeAddr("genesis"), + genesisBatchHash: bytes32(uint256(0x01)), + genesisIndexRepeatedStorageChanges: 0x01, + genesisBatchCommitment: bytes32(uint256(0x01)), + diamondCut: diamondCutDataStruct + }); + diamondCutData = abi.encode(diamondCutDataStruct); + vm.stopPrank(); + vm.prank(stm.admin()); + stm.setChainCreationParams(chainCreationParams); + chainRegistrar = new ChainRegistrar(address(bridgeHub), deployer); + chainRegistrar.initialize(admin); + } + + function test_SuccessfulProposal() public { + address author = makeAddr("author"); + ChainRegistrar.BaseToken memory baseToken = ChainRegistrar.BaseToken({ + tokenAddress: ETH_TOKEN_ADDRESS, + tokenMultiplierSetter: makeAddr("setter"), + gasPriceMultiplierNominator: 1, + gasPriceMultiplierDenominator: 1 + }); + vm.prank(author); + vm.recordLogs(); + chainRegistrar.proposeChainRegistration(ChainRegistrar.ChainConfig({ + chainId: 1, + pubdataPricingMode: PubdataPricingMode.Validium, + baseToken: baseToken, + commitOperator: makeAddr("commitOperator"), + operator: makeAddr("operator"), + governor: makeAddr("governor") + })); + Vm.Log[] memory proposeLogs = vm.getRecordedLogs(); + console.logAddress(admin); + console.logAddress(bridgeHub.admin()); + console.logAddress(bridgeHub.owner()); + vm.prank(admin); + + bridgeHub.createNewChain(1, address(stm), baseToken.tokenAddress, 0, admin, diamondCutData); + vm.prank(admin); +// sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); + vm.recordLogs(); +// chainRegistrar.chainRegistered(author, 1); + Vm.Log[] memory registeredLogs = vm.getRecordedLogs(); + + } +} From 0589a9b91278f4aa81b0ad15aebb793251ef623e Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 12 Nov 2024 15:03:43 +0700 Subject: [PATCH 23/54] Make test passes Signed-off-by: Danil --- .../chain-registrator/ChainRegistrar.sol | 11 ++++- .../dev-contracts/test/DummyHyperchain.sol | 23 ++++++--- ...Registrator.t.sol => ChainRegistrar.t.sol} | 47 +++++++++++++++++-- 3 files changed, 68 insertions(+), 13 deletions(-) rename l1-contracts/test/foundry/unit/concrete/chain-registrator/{ChainRegistrator.t.sol => ChainRegistrar.t.sol} (67%) diff --git a/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol index cea706e73..6c90ab32d 100644 --- a/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol @@ -10,6 +10,7 @@ import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -126,13 +127,21 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert ChainIsNotYetDeployed(); } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); - address chainAdmin = IZkSyncHyperchain(diamondProxy).getAdmin(); + (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); + address chainAdmin = bytesToAddress(returnData); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); } + emit NewChainDeployed(chainId, diamondProxy, chainAdmin); emit SharedBridgeRegistered(chainId, l2BridgeAddress); deployedChains[key] = true; } + + function bytesToAddress(bytes memory bys) private pure returns (address addr) { + assembly { + addr := mload(add(bys, 32)) + } + } } \ No newline at end of file diff --git a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol index 11be65a2b..ece0d915d 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol @@ -5,6 +5,7 @@ import {MailboxFacet} from "../../state-transition/chain-deps/facets/Mailbox.sol import {FeeParams, PubdataPricingMode} from "../../state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; contract DummyHyperchain is MailboxFacet { + address public admin; constructor(address bridgeHubAddress, uint256 _eraChainId) MailboxFacet(_eraChainId) { s.bridgehub = bridgeHubAddress; } @@ -32,15 +33,23 @@ contract DummyHyperchain is MailboxFacet { s.priorityTxMaxGasLimit = type(uint256).max; } + function initialize(address _admin) external { + admin = _admin; + } + + function getAdmin() external view returns (address) { + return admin; + } + function _randomFeeParams() internal pure returns (FeeParams memory) { return FeeParams({ - pubdataPricingMode: PubdataPricingMode.Rollup, - batchOverheadL1Gas: 1_000_000, - maxPubdataPerBatch: 110_000, - maxL2GasPerBatch: 80_000_000, - priorityTxMaxPubdata: 99_000, - minimalL2GasPrice: 250_000_000 - }); + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1_000_000, + maxPubdataPerBatch: 110_000, + maxL2GasPerBatch: 80_000_000, + priorityTxMaxPubdata: 99_000, + minimalL2GasPrice: 250_000_000 + }); } } diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol similarity index 67% rename from l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol rename to l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 2e4b585d5..542e31efe 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrator.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -4,15 +4,22 @@ pragma solidity ^0.8.0; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {DummyStateTransitionManagerWBH} from "contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol"; +import {VerifierParams, IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; + import "contracts/bridgehub/Bridgehub.sol"; import "contracts/chain-registrator/ChainRegistrar.sol"; import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; import "contracts/dev-contracts/test/DummyBridgehub.sol"; import "contracts/dev-contracts/test/DummySharedBridge.sol"; import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {console2 as console} from "forge-std/Script.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; +import {FeeParams} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import "../../../../../contracts/dev-contracts/test/DummyHyperchain.sol"; + contract ChainRegistrarTest is Test { DummyBridgehub private bridgeHub; @@ -22,6 +29,8 @@ contract ChainRegistrarTest is Test { ChainRegistrar private chainRegistrar; L1SharedBridge private sharedBridge; bytes diamondCutData; + bytes initCalldata; + constructor () public { bridgeHub = new DummyBridgehub(); @@ -52,10 +61,33 @@ contract ChainRegistrarTest is Test { Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](0); + + DiamondInitializeDataNewChain memory initializeData = DiamondInitializeDataNewChain({ + verifier: IVerifier(makeAddr("verifier")), + verifierParams: VerifierParams({ + recursionNodeLevelVkHash: bytes32(0), + recursionLeafLevelVkHash: bytes32(0), + recursionCircuitsSetVksHash: bytes32(0) + }), + l2BootloaderBytecodeHash: bytes32(0), + l2DefaultAccountBytecodeHash: bytes32(0), + priorityTxMaxGasLimit: 10, + feeParams: FeeParams({ + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1_000_000, + maxPubdataPerBatch: 110_000, + maxL2GasPerBatch: 80_000_000, + priorityTxMaxPubdata: 99_000, + minimalL2GasPrice: 250_000_000 + }), + blobVersionedHashRetriever: makeAddr("blob") + }); + initCalldata = abi.encode(initializeData); + Diamond.DiamondCutData memory diamondCutDataStruct = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: makeAddr("init"), - initCalldata: bytes("") + initCalldata: initCalldata }); ChainCreationParams memory chainCreationParams = ChainCreationParams({ genesisUpgrade: makeAddr("genesis"), @@ -94,13 +126,18 @@ contract ChainRegistrarTest is Test { console.logAddress(admin); console.logAddress(bridgeHub.admin()); console.logAddress(bridgeHub.owner()); + DummyHyperchain hyperchain = new DummyHyperchain(address(bridgeHub), 270); + hyperchain.initialize(admin); +// console.logBytes4(GettersFacet.getAdmin.selector); +// console.logBytes4(DummyHyperchain.getAdmin.selector); vm.prank(admin); - - bridgeHub.createNewChain(1, address(stm), baseToken.tokenAddress, 0, admin, diamondCutData); + stm.setHyperchain(1, makeAddr("hyperchain")); + bridgeHub.setStateTransitionManager(1, address(stm)); vm.prank(admin); -// sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); + sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); vm.recordLogs(); -// chainRegistrar.chainRegistered(author, 1); + vm.prank(admin); + chainRegistrar.chainRegistered(author, 1); Vm.Log[] memory registeredLogs = vm.getRecordedLogs(); } From ca8edffed03a385c80953a2a750980ad0c04e600 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 12 Nov 2024 15:52:27 +0700 Subject: [PATCH 24/54] Add deployer Signed-off-by: Danil --- .../ChainRegistrar.sol | 0 l1-contracts/deploy-scripts/DeployL1.s.sol | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+) rename l1-contracts/contracts/{chain-registrator => chain-registrar}/ChainRegistrar.sol (100%) diff --git a/l1-contracts/contracts/chain-registrator/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol similarity index 100% rename from l1-contracts/contracts/chain-registrator/ChainRegistrar.sol rename to l1-contracts/contracts/chain-registrar/ChainRegistrar.sol diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 416ffd6a3..6286089b0 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -34,6 +34,7 @@ import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; import {AddressHasNoCode} from "./ZkSyncScriptErrors.sol"; +import {ChainRegistrar} from "../contracts/chain-registrar/ChainRegistrar.sol"; contract DeployL1Script is Script { using stdToml for string; @@ -52,6 +53,7 @@ contract DeployL1Script is Script { address blobVersionedHashRetriever; address validatorTimelock; address create2Factory; + address chainRegistrar; } // solhint-disable-next-line gas-struct-packing @@ -88,6 +90,7 @@ contract DeployL1Script is Script { uint256 l1ChainId; uint256 eraChainId; address deployerAddress; + address l2Deployer; address ownerAddress; bool testnetVerifier; ContractsConfig contracts; @@ -157,6 +160,7 @@ contract DeployL1Script is Script { deployErc20BridgeImplementation(); deployErc20BridgeProxy(); updateSharedBridge(); + deployChainRegistrar(); updateOwners(); @@ -176,6 +180,7 @@ contract DeployL1Script is Script { // https://book.getfoundry.sh/cheatcodes/parse-toml config.eraChainId = toml.readUint("$.era_chain_id"); config.ownerAddress = toml.readAddress("$.owner_address"); + config.l2Deployer = toml.readAddress("$.l2_deployer"); config.testnetVerifier = toml.readBool("$.testnet_verifier"); config.contracts.governanceSecurityCouncilAddress = toml.readAddress( @@ -301,6 +306,20 @@ contract DeployL1Script is Script { addresses.governance = contractAddress; } + function deployChainRegistrar() internal { + bytes memory bytecode = abi.encodePacked( + type(ChainRegistrar).creationCode, + abi.encode( + addresses.bridgehub.bridgehubProxy, + config.l2Deployer + ) + ); + address contractAddress = deployViaCreate2(bytecode); + console.log("Chain Registrar deployed at:", contractAddress); + addresses.chainRegistrar = contractAddress; + } + + function deployChainAdmin() internal { bytes memory bytecode = abi.encodePacked( type(ChainAdmin).creationCode, @@ -715,6 +734,7 @@ contract DeployL1Script is Script { vm.serializeAddress("deployed_addresses", "chain_admin", addresses.chainAdmin); vm.serializeString("deployed_addresses", "bridgehub", bridgehub); vm.serializeString("deployed_addresses", "state_transition", stateTransition); + vm.serializeAddress("deployed_addresses", "chain_registrar", addresses.chainRegistrar); string memory deployedAddresses = vm.serializeString("deployed_addresses", "bridges", bridges); vm.serializeAddress("root", "create2_factory_addr", addresses.create2Factory); From 0e9e30d9ba72e6987d0dae4bb7ef0aca6f08e4c8 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 12 Nov 2024 17:46:30 +0700 Subject: [PATCH 25/54] Fix registrator Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 6 ++ .../deploy-scripts/RegisterHyperchain.s.sol | 89 ++++++------------- .../chain-registrator/ChainRegistrar.t.sol | 6 +- 3 files changed, 35 insertions(+), 66 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 6c90ab32d..8a5f7b079 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -111,6 +111,11 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { emit L2DeployerChanged(l2Deployer); } + function getChainConfig(address author, uint256 chainId) public view returns (ChainConfig memory){ + bytes32 key = keccak256(abi.encode(author, chainId)); + return proposedChains[key]; + } + function chainRegistered(address author, uint256 chainId) onlyOwner public { bytes32 key = keccak256(abi.encode(author, chainId)); @@ -128,6 +133,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); + require(success); address chainAdmin = bytesToAddress(returnData); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index bbc01226d..79200372d 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -14,6 +14,7 @@ import {Governance} from "contracts/governance/Governance.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {Utils} from "./Utils.sol"; import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {ChainRegistrar} from "contracts/chain-registrar/ChainRegistrar.sol"; contract RegisterHyperchainScript is Script { using stdToml for string; @@ -23,35 +24,27 @@ contract RegisterHyperchainScript is Script { // solhint-disable-next-line gas-struct-packing struct Config { - address deployerAddress; - address ownerAddress; uint256 chainChainId; - bool validiumMode; - uint256 bridgehubCreateNewChainSalt; - address validatorSenderOperatorCommitEth; - address validatorSenderOperatorBlobsEth; - address baseToken; - uint128 baseTokenGasPriceMultiplierNominator; - uint128 baseTokenGasPriceMultiplierDenominator; + address proposalAuthor; + address chainRegistrar; address bridgehub; address stateTransitionProxy; address validatorTimelock; bytes diamondCutData; - address governanceSecurityCouncilAddress; - uint256 governanceMinDelay; address newDiamondProxy; - address governance; address chainAdmin; } + ChainRegistrar chainRegistrar; Config internal config; + ChainRegistrar.ChainConfig internal chainConfig; function run() public { console.log("Deploying Hyperchain"); initializeConfig(); + loadChain(); - deployGovernance(); deployChainAdmin(); checkTokenAddress(); registerTokenOnBridgehub(); @@ -69,48 +62,39 @@ contract RegisterHyperchainScript is Script { string memory path = string.concat(root, "/script-config/register-hyperchain.toml"); string memory toml = vm.readFile(path); - config.deployerAddress = msg.sender; - // Config file must be parsed key by key, otherwise values returned // are parsed alfabetically and not by key. // https://book.getfoundry.sh/cheatcodes/parse-toml - config.ownerAddress = toml.readAddress("$.owner_address"); - config.bridgehub = toml.readAddress("$.deployed_addresses.bridgehub.bridgehub_proxy_addr"); config.stateTransitionProxy = toml.readAddress( "$.deployed_addresses.state_transition.state_transition_proxy_addr" ); config.validatorTimelock = toml.readAddress("$.deployed_addresses.validator_timelock_addr"); + config.chainRegistrar = toml.readAddress("$.deployed_addresses.chain_registrar"); config.diamondCutData = toml.readBytes("$.contracts_config.diamond_cut_data"); config.chainChainId = toml.readUint("$.chain.chain_chain_id"); + config.proposalAuthor = toml.readUint("$.chain.proposal_author"); config.bridgehubCreateNewChainSalt = toml.readUint("$.chain.bridgehub_create_new_chain_salt"); - config.baseToken = toml.readAddress("$.chain.base_token_addr"); - config.validiumMode = toml.readBool("$.chain.validium_mode"); - config.validatorSenderOperatorCommitEth = toml.readAddress("$.chain.validator_sender_operator_commit_eth"); - config.validatorSenderOperatorBlobsEth = toml.readAddress("$.chain.validator_sender_operator_blobs_eth"); - config.baseTokenGasPriceMultiplierNominator = uint128( - toml.readUint("$.chain.base_token_gas_price_multiplier_nominator") - ); - config.baseTokenGasPriceMultiplierDenominator = uint128( - toml.readUint("$.chain.base_token_gas_price_multiplier_denominator") - ); - config.governanceMinDelay = uint256(toml.readUint("$.chain.governance_min_delay")); - config.governanceSecurityCouncilAddress = toml.readAddress("$.chain.governance_security_council_address"); + chainRegistrar = ChainRegistrar(config.chainRegistrar); + } + + function loadChain() internal { + chainConfig = chainRegistrar.getChainConfig(config.proposalAuthor, config.chainChainId); } function checkTokenAddress() internal view { - if (config.baseToken == address(0)) { + if (chainConfig.baseToken.tokenAddress == address(0)) { revert("Token address is not set"); } // Check if it's ethereum address - if (config.baseToken == ADDRESS_ONE) { + if (chainConfig.baseToken.tokenAddress == ADDRESS_ONE) { return; } - if (config.baseToken.code.length == 0) { + if (chainConfig.baseToken.tokenAddress.code.length == 0) { revert("Token address is not a contract address"); } @@ -120,10 +104,10 @@ contract RegisterHyperchainScript is Script { function registerTokenOnBridgehub() internal { Bridgehub bridgehub = Bridgehub(config.bridgehub); - if (bridgehub.tokenIsRegistered(config.baseToken)) { + if (bridgehub.tokenIsRegistered(chainConfig.baseToken.tokenAddress)) { console.log("Token already registered on Bridgehub"); } else { - bytes memory data = abi.encodeCall(bridgehub.addToken, (config.baseToken)); + bytes memory data = abi.encodeCall(bridgehub.addToken, (chainConfig.baseToken.tokenAddress)); Utils.chainAdminMulticall({ _chainAdmin: bridgehub.admin(), _target: config.bridgehub, @@ -134,20 +118,10 @@ contract RegisterHyperchainScript is Script { } } - function deployGovernance() internal { - vm.broadcast(); - Governance governance = new Governance( - config.ownerAddress, - config.governanceSecurityCouncilAddress, - config.governanceMinDelay - ); - console.log("Governance deployed at:", address(governance)); - config.governance = address(governance); - } function deployChainAdmin() internal { vm.broadcast(); - ChainAdmin chainAdmin = new ChainAdmin(config.ownerAddress, address(0)); + ChainAdmin chainAdmin = new ChainAdmin(chainConfig.governor, address(0)); console.log("ChainAdmin deployed at:", address(chainAdmin)); config.chainAdmin = address(chainAdmin); } @@ -159,9 +133,9 @@ contract RegisterHyperchainScript is Script { bytes memory data = abi.encodeCall( bridgehub.createNewChain, ( - config.chainChainId, + chainConfig.chainId, config.stateTransitionProxy, - config.baseToken, + chainConfig.baseToken.tokenAddress, config.bridgehubCreateNewChainSalt, msg.sender, config.diamondCutData @@ -172,15 +146,7 @@ contract RegisterHyperchainScript is Script { console.log("Hyperchain registered"); // Get new diamond proxy address from emitted events - Vm.Log[] memory logs = vm.getRecordedLogs(); - address diamondProxyAddress; - uint256 logsLength = logs.length; - for (uint256 i = 0; i < logsLength; ++i) { - if (logs[i].topics[0] == STATE_TRANSITION_NEW_CHAIN_HASH) { - diamondProxyAddress = address(uint160(uint256(logs[i].topics[2]))); - break; - } - } + address diamondProxyAddress = bridgehub.getHyperchain(chainConfig.chainId); if (diamondProxyAddress == address(0)) { revert("Diamond proxy address not found"); } @@ -192,8 +158,8 @@ contract RegisterHyperchainScript is Script { ValidatorTimelock validatorTimelock = ValidatorTimelock(config.validatorTimelock); vm.startBroadcast(); - validatorTimelock.addValidator(config.chainChainId, config.validatorSenderOperatorCommitEth); - validatorTimelock.addValidator(config.chainChainId, config.validatorSenderOperatorBlobsEth); + validatorTimelock.addValidator(chainConfig.chainId, chainConfig.commitOperator); + validatorTimelock.addValidator(chainConfig.chainId, chainConfig.operator); vm.stopBroadcast(); console.log("Validators added"); @@ -204,11 +170,11 @@ contract RegisterHyperchainScript is Script { vm.startBroadcast(); hyperchain.setTokenMultiplier( - config.baseTokenGasPriceMultiplierNominator, - config.baseTokenGasPriceMultiplierDenominator + chainConfig.baseToken.gasPriceMultiplierNominator, + chainConfig.baseToken.gasPriceMultiplierDenominator ); - if (config.validiumMode) { + if (chainConfig.pubdataPricingMode == PubdataPricingMode.Validium) { hyperchain.setPubdataPricingMode(PubdataPricingMode.Validium); } @@ -227,7 +193,6 @@ contract RegisterHyperchainScript is Script { function saveOutput() internal { vm.serializeAddress("root", "diamond_proxy_addr", config.newDiamondProxy); vm.serializeAddress("root", "chain_admin_addr", config.chainAdmin); - string memory toml = vm.serializeAddress("root", "governance_addr", config.governance); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-register-hyperchain.toml"); vm.writeToml(toml, path); diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 542e31efe..5037889f4 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -8,7 +8,7 @@ import {VerifierParams, IVerifier} from "contracts/state-transition/chain-interf import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; import "contracts/bridgehub/Bridgehub.sol"; -import "contracts/chain-registrator/ChainRegistrar.sol"; +import "contracts/chain-registrar/ChainRegistrar.sol"; import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; import "contracts/dev-contracts/test/DummyBridgehub.sol"; @@ -18,7 +18,7 @@ import {console2 as console} from "forge-std/Script.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; import {FeeParams} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; -import "../../../../../contracts/dev-contracts/test/DummyHyperchain.sol"; +import "contracts/dev-contracts/test/DummyHyperchain.sol"; contract ChainRegistrarTest is Test { @@ -128,8 +128,6 @@ contract ChainRegistrarTest is Test { console.logAddress(bridgeHub.owner()); DummyHyperchain hyperchain = new DummyHyperchain(address(bridgeHub), 270); hyperchain.initialize(admin); -// console.logBytes4(GettersFacet.getAdmin.selector); -// console.logBytes4(DummyHyperchain.getAdmin.selector); vm.prank(admin); stm.setHyperchain(1, makeAddr("hyperchain")); bridgeHub.setStateTransitionManager(1, address(stm)); From e4b0c8586989e60ff03e2dee215d3e5d497485e2 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 12 Nov 2024 19:33:09 +0700 Subject: [PATCH 26/54] Simplify propose chain signature Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 26 ++++++++++++++++++- .../deploy-scripts/RegisterHyperchain.s.sol | 4 +-- .../chain-registrator/ChainRegistrar.t.sol | 17 +++++------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 8a5f7b079..a82327732 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -90,7 +90,31 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } - function proposeChainRegistration(ChainConfig calldata config) public { + function proposeChainRegistration( + uint256 chainId, + PubdataPricingMode pubdataPricingMode, + address commitOperator, + address operator, + address governor, + address tokenAddress, + address tokenMultiplierSetter, + uint128 gasPriceMultiplierNominator, + uint128 gasPriceMultiplierDenominator + ) public { + + ChainConfig memory config = ChainConfig({ + chainId: chainId, + pubdataPricingMode: pubdataPricingMode, + commitOperator: commitOperator, + operator: operator, + governor: governor, + baseToken: BaseToken({ + tokenAddress: tokenAddress, + tokenMultiplierSetter: tokenMultiplierSetter, + gasPriceMultiplierNominator: gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + }) + }); bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { revert ChainIsAlreadyDeployed(); diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index 79200372d..b0aad0951 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -35,7 +35,7 @@ contract RegisterHyperchainScript is Script { address chainAdmin; } - ChainRegistrar chainRegistrar; + ChainRegistrar internal chainRegistrar; Config internal config; ChainRegistrar.ChainConfig internal chainConfig; @@ -192,7 +192,7 @@ contract RegisterHyperchainScript is Script { function saveOutput() internal { vm.serializeAddress("root", "diamond_proxy_addr", config.newDiamondProxy); - vm.serializeAddress("root", "chain_admin_addr", config.chainAdmin); + string memory toml = vm.serializeAddress("root", "chain_admin_addr", config.chainAdmin); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-register-hyperchain.toml"); vm.writeToml(toml, path); diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 5037889f4..9a7f69677 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -106,22 +106,19 @@ contract ChainRegistrarTest is Test { function test_SuccessfulProposal() public { address author = makeAddr("author"); - ChainRegistrar.BaseToken memory baseToken = ChainRegistrar.BaseToken({ - tokenAddress: ETH_TOKEN_ADDRESS, - tokenMultiplierSetter: makeAddr("setter"), - gasPriceMultiplierNominator: 1, - gasPriceMultiplierDenominator: 1 - }); vm.prank(author); vm.recordLogs(); - chainRegistrar.proposeChainRegistration(ChainRegistrar.ChainConfig({ + chainRegistrar.proposeChainRegistration({ chainId: 1, pubdataPricingMode: PubdataPricingMode.Validium, - baseToken: baseToken, commitOperator: makeAddr("commitOperator"), operator: makeAddr("operator"), - governor: makeAddr("governor") - })); + governor: makeAddr("governor"), + tokenAddress: ETH_TOKEN_ADDRESS, + tokenMultiplierSetter: makeAddr("setter"), + gasPriceMultiplierNominator: 1, + gasPriceMultiplierDenominator: 1 + }); Vm.Log[] memory proposeLogs = vm.getRecordedLogs(); console.logAddress(admin); console.logAddress(bridgeHub.admin()); From 1804692b121aeab046d6dae32ddc2332509fa83a Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 12 Nov 2024 19:33:09 +0700 Subject: [PATCH 27/54] Simplify propose chain signature Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 36 ++++++------------- .../dev-contracts/test/DummyHyperchain.sol | 14 ++++---- l1-contracts/deploy-scripts/DeployL1.s.sol | 6 +--- .../deploy-scripts/RegisterHyperchain.s.sol | 14 ++++---- .../chain-registrator/ChainRegistrar.t.sol | 29 +++++++-------- 5 files changed, 39 insertions(+), 60 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index a82327732..ff1284c80 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -19,7 +19,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { /// Address that will be used for deploying l2 contracts address l2Deployer; /// Bridgehub - IBridgehub bridgehub; + IBridgehub public bridgehub; /// Chains that has been succesfuly deployed mapping(bytes32 => bool) public deployedChains; @@ -32,30 +32,16 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { error BridgeIsNotRegistered(); /// @notice new chain is deployed - event NewChainDeployed( - uint256 indexed chainId, - address diamondProxy, - address chainAdmin - ); + event NewChainDeployed(uint256 indexed chainId, address diamondProxy, address chainAdmin); /// @notice new chain is proposed to register - event NewChainRegistrationProposal( - uint256 indexed chainId, - address author, - bytes32 key - ); + event NewChainRegistrationProposal(uint256 indexed chainId, address author, bytes32 key); /// @notice Shared bridge is registered on l2 - event SharedBridgeRegistered( - uint256 indexed chainId, - address l2Address - ); + event SharedBridgeRegistered(uint256 indexed chainId, address l2Address); /// @notice new chain is deployed - event L2DeployerChanged( - address newDeployer - ); - + event L2DeployerChanged(address newDeployer); struct BaseToken { address tokenAddress; @@ -122,7 +108,8 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { proposedChains[key] = config; // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { - uint256 amount = 1 ether * config.baseToken.gasPriceMultiplierNominator / config.baseToken.gasPriceMultiplierDenominator; + uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / + config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); } @@ -130,18 +117,17 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { emit NewChainRegistrationProposal(config.chainId, msg.sender, key); } - function changeDeployer(address newDeployer) onlyOwner public { + function changeDeployer(address newDeployer) public onlyOwner { l2Deployer = newDeployer; emit L2DeployerChanged(l2Deployer); } - function getChainConfig(address author, uint256 chainId) public view returns (ChainConfig memory){ + function getChainConfig(address author, uint256 chainId) public view returns (ChainConfig memory) { bytes32 key = keccak256(abi.encode(author, chainId)); return proposedChains[key]; } - - function chainRegistered(address author, uint256 chainId) onlyOwner public { + function chainRegistered(address author, uint256 chainId) public onlyOwner { bytes32 key = keccak256(abi.encode(author, chainId)); ChainConfig memory config = proposedChains[key]; if (config.chainId == 0) { @@ -174,4 +160,4 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { addr := mload(add(bys, 32)) } } -} \ No newline at end of file +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol index ece0d915d..d90f6bab8 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol @@ -44,12 +44,12 @@ contract DummyHyperchain is MailboxFacet { function _randomFeeParams() internal pure returns (FeeParams memory) { return FeeParams({ - pubdataPricingMode: PubdataPricingMode.Rollup, - batchOverheadL1Gas: 1_000_000, - maxPubdataPerBatch: 110_000, - maxL2GasPerBatch: 80_000_000, - priorityTxMaxPubdata: 99_000, - minimalL2GasPrice: 250_000_000 - }); + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1_000_000, + maxPubdataPerBatch: 110_000, + maxL2GasPerBatch: 80_000_000, + priorityTxMaxPubdata: 99_000, + minimalL2GasPrice: 250_000_000 + }); } } diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 6286089b0..22e7cf242 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -309,17 +309,13 @@ contract DeployL1Script is Script { function deployChainRegistrar() internal { bytes memory bytecode = abi.encodePacked( type(ChainRegistrar).creationCode, - abi.encode( - addresses.bridgehub.bridgehubProxy, - config.l2Deployer - ) + abi.encode(addresses.bridgehub.bridgehubProxy, config.l2Deployer) ); address contractAddress = deployViaCreate2(bytecode); console.log("Chain Registrar deployed at:", contractAddress); addresses.chainRegistrar = contractAddress; } - function deployChainAdmin() internal { bytes memory bytecode = abi.encodePacked( type(ChainAdmin).creationCode, diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index b0aad0951..0f48eec83 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -8,6 +8,8 @@ import {Vm} from "forge-std/Vm.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; +import {StateTransitionManager} from "contracts/state-transition/StateTransitionManager.sol"; + import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; import {Governance} from "contracts/governance/Governance.sol"; @@ -28,6 +30,7 @@ contract RegisterHyperchainScript is Script { address proposalAuthor; address chainRegistrar; address bridgehub; + uint256 bridgehubCreateNewChainSalt; address stateTransitionProxy; address validatorTimelock; bytes diamondCutData; @@ -65,19 +68,19 @@ contract RegisterHyperchainScript is Script { // Config file must be parsed key by key, otherwise values returned // are parsed alfabetically and not by key. // https://book.getfoundry.sh/cheatcodes/parse-toml - config.bridgehub = toml.readAddress("$.deployed_addresses.bridgehub.bridgehub_proxy_addr"); config.stateTransitionProxy = toml.readAddress( "$.deployed_addresses.state_transition.state_transition_proxy_addr" ); - config.validatorTimelock = toml.readAddress("$.deployed_addresses.validator_timelock_addr"); config.chainRegistrar = toml.readAddress("$.deployed_addresses.chain_registrar"); + chainRegistrar = ChainRegistrar(config.chainRegistrar); + config.bridgehub = address(chainRegistrar.bridgehub()); + config.validatorTimelock = StateTransitionManager(config.stateTransitionProxy).validatorTimelock(); config.diamondCutData = toml.readBytes("$.contracts_config.diamond_cut_data"); config.chainChainId = toml.readUint("$.chain.chain_chain_id"); - config.proposalAuthor = toml.readUint("$.chain.proposal_author"); + config.proposalAuthor = toml.readAddress("$.chain.proposal_author"); config.bridgehubCreateNewChainSalt = toml.readUint("$.chain.bridgehub_create_new_chain_salt"); - chainRegistrar = ChainRegistrar(config.chainRegistrar); } function loadChain() internal { @@ -98,7 +101,7 @@ contract RegisterHyperchainScript is Script { revert("Token address is not a contract address"); } - console.log("Using base token address:", config.baseToken); + console.log("Using base token address:", chainConfig.baseToken.tokenAddress); } function registerTokenOnBridgehub() internal { @@ -118,7 +121,6 @@ contract RegisterHyperchainScript is Script { } } - function deployChainAdmin() internal { vm.broadcast(); ChainAdmin chainAdmin = new ChainAdmin(chainConfig.governor, address(0)); diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 9a7f69677..832d044ca 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -20,7 +20,6 @@ import {ChainCreationParams} from "contracts/state-transition/IStateTransitionMa import {FeeParams} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; import "contracts/dev-contracts/test/DummyHyperchain.sol"; - contract ChainRegistrarTest is Test { DummyBridgehub private bridgeHub; DummyStateTransitionManagerWBH private stm; @@ -31,8 +30,7 @@ contract ChainRegistrarTest is Test { bytes diamondCutData; bytes initCalldata; - - constructor () public { + constructor() public { bridgeHub = new DummyBridgehub(); stm = new DummyStateTransitionManagerWBH(address(bridgeHub)); admin = makeAddr("admin"); @@ -58,28 +56,26 @@ contract ChainRegistrarTest is Test { bridgeHub.addStateTransitionManager(address(stm)); bridgeHub.addToken(ETH_TOKEN_ADDRESS); - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](0); - DiamondInitializeDataNewChain memory initializeData = DiamondInitializeDataNewChain({ verifier: IVerifier(makeAddr("verifier")), verifierParams: VerifierParams({ - recursionNodeLevelVkHash: bytes32(0), - recursionLeafLevelVkHash: bytes32(0), - recursionCircuitsSetVksHash: bytes32(0) - }), + recursionNodeLevelVkHash: bytes32(0), + recursionLeafLevelVkHash: bytes32(0), + recursionCircuitsSetVksHash: bytes32(0) + }), l2BootloaderBytecodeHash: bytes32(0), l2DefaultAccountBytecodeHash: bytes32(0), priorityTxMaxGasLimit: 10, feeParams: FeeParams({ - pubdataPricingMode: PubdataPricingMode.Rollup, - batchOverheadL1Gas: 1_000_000, - maxPubdataPerBatch: 110_000, - maxL2GasPerBatch: 80_000_000, - priorityTxMaxPubdata: 99_000, - minimalL2GasPrice: 250_000_000 - }), + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1_000_000, + maxPubdataPerBatch: 110_000, + maxL2GasPerBatch: 80_000_000, + priorityTxMaxPubdata: 99_000, + minimalL2GasPrice: 250_000_000 + }), blobVersionedHashRetriever: makeAddr("blob") }); initCalldata = abi.encode(initializeData); @@ -134,6 +130,5 @@ contract ChainRegistrarTest is Test { vm.prank(admin); chainRegistrar.chainRegistered(author, 1); Vm.Log[] memory registeredLogs = vm.getRecordedLogs(); - } } From 9294bac35afdfa05b2e75b6b48b7bec8b1b49c37 Mon Sep 17 00:00:00 2001 From: Danil Date: Wed, 13 Nov 2024 22:35:16 +0700 Subject: [PATCH 28/54] Finalize registration Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 20 +++++++++---------- l1-contracts/deploy-scripts/DeployL1.s.sol | 2 ++ .../deploy-scripts/DeployL2Contracts.sol | 17 +++++++++++++++- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index ff1284c80..0514aa856 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -32,7 +32,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { error BridgeIsNotRegistered(); /// @notice new chain is deployed - event NewChainDeployed(uint256 indexed chainId, address diamondProxy, address chainAdmin); + event NewChainDeployed(uint256 indexed chainId, address author, address diamondProxy, address chainAdmin); /// @notice new chain is proposed to register event NewChainRegistrationProposal(uint256 indexed chainId, address author, bytes32 key); @@ -40,7 +40,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { /// @notice Shared bridge is registered on l2 event SharedBridgeRegistered(uint256 indexed chainId, address l2Address); - /// @notice new chain is deployed + /// @notice L2 Deployer has changed event L2DeployerChanged(address newDeployer); struct BaseToken { @@ -75,7 +75,6 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { _transferOwnership(_owner); } - function proposeChainRegistration( uint256 chainId, PubdataPricingMode pubdataPricingMode, @@ -87,7 +86,6 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { uint128 gasPriceMultiplierNominator, uint128 gasPriceMultiplierDenominator ) public { - ChainConfig memory config = ChainConfig({ chainId: chainId, pubdataPricingMode: pubdataPricingMode, @@ -95,11 +93,11 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { operator: operator, governor: governor, baseToken: BaseToken({ - tokenAddress: tokenAddress, - tokenMultiplierSetter: tokenMultiplierSetter, - gasPriceMultiplierNominator: gasPriceMultiplierNominator, - gasPriceMultiplierDenominator: gasPriceMultiplierDenominator - }) + tokenAddress: tokenAddress, + tokenMultiplierSetter: tokenMultiplierSetter, + gasPriceMultiplierNominator: gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + }) }); bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { @@ -109,7 +107,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / - config.baseToken.gasPriceMultiplierDenominator; + config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); } @@ -150,7 +148,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert BridgeIsNotRegistered(); } - emit NewChainDeployed(chainId, diamondProxy, chainAdmin); + emit NewChainDeployed(chainId, diamondProxy, author, chainAdmin); emit SharedBridgeRegistered(chainId, l2BridgeAddress); deployedChains[key] = true; } diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 22e7cf242..9aa669225 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -312,6 +312,8 @@ contract DeployL1Script is Script { abi.encode(addresses.bridgehub.bridgehubProxy, config.l2Deployer) ); address contractAddress = deployViaCreate2(bytecode); + vm.broadcast(); + ChainRegistrar(contractAddress).initialize(config.ownerAddress); console.log("Chain Registrar deployed at:", contractAddress); addresses.chainRegistrar = contractAddress; } diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 899cc9263..2c67c8794 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -2,13 +2,14 @@ pragma solidity ^0.8.21; -import {Script} from "forge-std/Script.sol"; +import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {Utils} from "./Utils.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {ChainRegistrar} from "contracts/chain-registrar/ChainRegistrar.sol"; contract DeployL2Script is Script { using stdToml for string; @@ -22,6 +23,8 @@ contract DeployL2Script is Script { address l1SharedBridgeProxy; address governance; address erc20BridgeProxy; + address chainRegistrar; + address proposalAuthor; // The owner of the contract sets the validator/attester weights. // Can be the developer multisig wallet on mainnet. address consensusRegistryOwner; @@ -65,6 +68,7 @@ contract DeployL2Script is Script { deploySharedBridge(); deploySharedBridgeProxy(legacyBridge); initializeChain(); + finalizeRegistration(); deployForceDeployer(); deployConsensusRegistry(); deployConsensusRegistryProxy(); @@ -90,6 +94,7 @@ contract DeployL2Script is Script { deploySharedBridge(); deploySharedBridgeProxy(legacyBridge); initializeChain(); + finalizeRegistration(); saveOutput(); } @@ -184,6 +189,8 @@ contract DeployL2Script is Script { config.l1SharedBridgeProxy = toml.readAddress("$.l1_shared_bridge"); config.erc20BridgeProxy = toml.readAddress("$.erc20_bridge"); config.consensusRegistryOwner = toml.readAddress("$.consensus_registry_owner"); + config.chainRegistrar = toml.readAddress("$.chain_registrar"); + config.proposalAuthor = toml.readAddress("$.proposal_author"); config.chainId = toml.readUint("$.chain_id"); config.eraChainId = toml.readUint("$.era_chain_id"); } @@ -366,4 +373,12 @@ contract DeployL2Script is Script { _value: 0 }); } + + function finalizeRegistration() internal { + ChainRegistrar chainRegistrar = ChainRegistrar(config.chainRegistrar); + console.logAddress(msg.sender); + console.logAddress(chainRegistrar.owner()); + vm.broadcast(); + chainRegistrar.chainRegistered(config.proposalAuthor, config.chainId); + } } From 5579d5a5108f0eee5022ea6fb451164f2bcd2985 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 14 Nov 2024 19:34:45 +0700 Subject: [PATCH 29/54] Update initialization Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 23 ++++++++----------- l1-contracts/deploy-scripts/DeployL1.s.sol | 3 +-- .../chain-registrator/ChainRegistrar.t.sol | 3 +-- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 0514aa856..0ccd83996 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -9,19 +9,18 @@ import {IStateTransitionManager} from "../state-transition/IStateTransitionManag import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; -import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev ChainRegistrar serves as the main point for chain registration. -contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { +contract ChainRegistrar is Ownable2StepUpgradeable { /// Address that will be used for deploying l2 contracts address l2Deployer; /// Bridgehub IBridgehub public bridgehub; - /// Chains that has been succesfuly deployed + /// Chains that has been successfully deployed mapping(bytes32 => bool) public deployedChains; /// Proposal for chain registration mapping(bytes32 => ChainConfig) public proposedChains; @@ -65,13 +64,9 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { address governor; } - constructor(address _bridgehub, address _l2Deployer) { + constructor(address _bridgehub, address _l2Deployer, address _owner) { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; - } - - /// @notice used to initialize the contract - function initialize(address _owner) external { _transferOwnership(_owner); } @@ -93,11 +88,11 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { operator: operator, governor: governor, baseToken: BaseToken({ - tokenAddress: tokenAddress, - tokenMultiplierSetter: tokenMultiplierSetter, - gasPriceMultiplierNominator: gasPriceMultiplierNominator, - gasPriceMultiplierDenominator: gasPriceMultiplierDenominator - }) + tokenAddress: tokenAddress, + tokenMultiplierSetter: tokenMultiplierSetter, + gasPriceMultiplierNominator: gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + }) }); bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { @@ -107,7 +102,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / - config.baseToken.gasPriceMultiplierDenominator; + config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); } diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 9aa669225..5e86a7cd2 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -309,11 +309,10 @@ contract DeployL1Script is Script { function deployChainRegistrar() internal { bytes memory bytecode = abi.encodePacked( type(ChainRegistrar).creationCode, - abi.encode(addresses.bridgehub.bridgehubProxy, config.l2Deployer) + abi.encode(addresses.bridgehub.bridgehubProxy, config.l2Deployer, config.ownerAddress) ); address contractAddress = deployViaCreate2(bytecode); vm.broadcast(); - ChainRegistrar(contractAddress).initialize(config.ownerAddress); console.log("Chain Registrar deployed at:", contractAddress); addresses.chainRegistrar = contractAddress; } diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 832d044ca..3adfc3ab5 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -96,8 +96,7 @@ contract ChainRegistrarTest is Test { vm.stopPrank(); vm.prank(stm.admin()); stm.setChainCreationParams(chainCreationParams); - chainRegistrar = new ChainRegistrar(address(bridgeHub), deployer); - chainRegistrar.initialize(admin); + chainRegistrar = new ChainRegistrar(address(bridgeHub), deployer, admin); } function test_SuccessfulProposal() public { From 43b788e1b6ebfd48b40ab5c6bb4869e477439cab Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 14 Nov 2024 19:43:23 +0700 Subject: [PATCH 30/54] Fix reentranc Signed-off-by: Danil --- l1-contracts/contracts/chain-registrar/ChainRegistrar.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 0ccd83996..9f38abaec 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -10,11 +10,12 @@ import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; +import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev ChainRegistrar serves as the main point for chain registration. -contract ChainRegistrar is Ownable2StepUpgradeable { +contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { /// Address that will be used for deploying l2 contracts address l2Deployer; /// Bridgehub @@ -64,7 +65,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { address governor; } - constructor(address _bridgehub, address _l2Deployer, address _owner) { + constructor(address _bridgehub, address _l2Deployer, address _owner) reentrancyGuardInitializer { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); @@ -120,7 +121,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { return proposedChains[key]; } - function chainRegistered(address author, uint256 chainId) public onlyOwner { + function chainRegistered(address author, uint256 chainId) public onlyOwner nonReentrant { bytes32 key = keccak256(abi.encode(author, chainId)); ChainConfig memory config = proposedChains[key]; if (config.chainId == 0) { From 9c148cc477c8f0c8ea7da224d1c01cc8331cf499 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 14 Nov 2024 19:52:42 +0700 Subject: [PATCH 31/54] Change to call of get admin Signed-off-by: Danil --- .../contracts/chain-registrar/ChainRegistrar.sol | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 9f38abaec..7fdf076b4 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -27,6 +27,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { mapping(bytes32 => ChainConfig) public proposedChains; error ProposalNotFound(); + error BaseTokenTransferFailed(); error ChainIsAlreadyDeployed(); error ChainIsNotYetDeployed(); error BridgeIsNotRegistered(); @@ -105,7 +106,10 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { - IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); + bool success = IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); + if (!success) { + revert BaseTokenTransferFailed(); + } } } emit NewChainRegistrationProposal(config.chainId, msg.sender, key); @@ -136,9 +140,10 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert ChainIsNotYetDeployed(); } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); - (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); - require(success); - address chainAdmin = bytesToAddress(returnData); +// (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); +// require(success); +// address chainAdmin = bytesToAddress(returnData); + address chainAdmin = IGetters(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); From 76100826a511f64340f01fbfbf5ceee5646bbdff Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 14 Nov 2024 20:04:03 +0700 Subject: [PATCH 32/54] Fix lints Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 33 +++++++++---------- l1-contracts/deploy-scripts/DeployL1.s.sol | 1 - .../deploy-scripts/RegisterHyperchain.s.sol | 2 -- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 7fdf076b4..c4b6e357c 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -3,8 +3,7 @@ pragma solidity 0.8.24; import {IBridgehub} from "../bridgehub/IBridgehub.sol"; -import {ZkSyncHyperchainStorage, PubdataPricingMode} from "../state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; -import {IZkSyncHyperchain} from "../state-transition/chain-interfaces/IZkSyncHyperchain.sol"; +import {PubdataPricingMode} from "../state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; import {IStateTransitionManager} from "../state-transition/IStateTransitionManager.sol"; import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; @@ -17,8 +16,8 @@ import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; /// @dev ChainRegistrar serves as the main point for chain registration. contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { /// Address that will be used for deploying l2 contracts - address l2Deployer; - /// Bridgehub + address public l2Deployer; + /// ZKsync Bridgehub IBridgehub public bridgehub; /// Chains that has been successfully deployed @@ -54,16 +53,16 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { struct ChainConfig { /// @param Chain id of the new chain should be unique for this bridgehub uint256 chainId; - /// @param pubdataPricingMode How the users will charged for pubdata. - PubdataPricingMode pubdataPricingMode; - /// @param baseToken of the chain - BaseToken baseToken; /// @param Operator for making commit txs. address commitOperator; /// @param Operator for making Prove and Execute transactions address operator; /// @param Governor of the chain. Ownership of the chain will be transferred to this operator address governor; + /// @param baseToken of the chain + BaseToken baseToken; + /// @param pubdataPricingMode How the users will charged for pubdata. + PubdataPricingMode pubdataPricingMode; } constructor(address _bridgehub, address _l2Deployer, address _owner) reentrancyGuardInitializer { @@ -90,11 +89,11 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { operator: operator, governor: governor, baseToken: BaseToken({ - tokenAddress: tokenAddress, - tokenMultiplierSetter: tokenMultiplierSetter, - gasPriceMultiplierNominator: gasPriceMultiplierNominator, - gasPriceMultiplierDenominator: gasPriceMultiplierDenominator - }) + tokenAddress: tokenAddress, + tokenMultiplierSetter: tokenMultiplierSetter, + gasPriceMultiplierNominator: gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + }) }); bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { @@ -104,7 +103,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / - config.baseToken.gasPriceMultiplierDenominator; + config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { bool success = IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); if (!success) { @@ -140,9 +139,9 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert ChainIsNotYetDeployed(); } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); -// (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); -// require(success); -// address chainAdmin = bytesToAddress(returnData); + // (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); + // require(success); + // address chainAdmin = bytesToAddress(returnData); address chainAdmin = IGetters(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 5e86a7cd2..d0a309c7e 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -312,7 +312,6 @@ contract DeployL1Script is Script { abi.encode(addresses.bridgehub.bridgehubProxy, config.l2Deployer, config.ownerAddress) ); address contractAddress = deployViaCreate2(bytecode); - vm.broadcast(); console.log("Chain Registrar deployed at:", contractAddress); addresses.chainRegistrar = contractAddress; } diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index 0f48eec83..e1c149c2c 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.24; // solhint-disable no-console, gas-custom-errors, reason-string import {Script, console2 as console} from "forge-std/Script.sol"; -import {Vm} from "forge-std/Vm.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; @@ -12,7 +11,6 @@ import {StateTransitionManager} from "contracts/state-transition/StateTransition import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; -import {Governance} from "contracts/governance/Governance.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {Utils} from "./Utils.sol"; import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; From 567abc53308bc30b0720510449e4bc8317b562b7 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 14 Nov 2024 22:12:13 +0700 Subject: [PATCH 33/54] Return correct admin Signed-off-by: Danil --- .../contracts/chain-registrar/ChainRegistrar.sol | 14 +++----------- l1-contracts/deploy-scripts/DeployL2Contracts.sol | 2 -- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index c4b6e357c..dffd9f67b 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -139,23 +139,15 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert ChainIsNotYetDeployed(); } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); - // (bool success, bytes memory returnData) = diamondProxy.call(abi.encodeWithSelector(IGetters.getAdmin.selector)); - // require(success); - // address chainAdmin = bytesToAddress(returnData); - address chainAdmin = IGetters(diamondProxy).getAdmin(); + // Matter Labs team set the pending admin to the chain admin and now governor of the chain must accept ownership + address chainAdmin = IGetters(diamondProxy).getPendingAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); } - emit NewChainDeployed(chainId, diamondProxy, author, chainAdmin); + emit NewChainDeployed(chainId, author, diamondProxy, chainAdmin); emit SharedBridgeRegistered(chainId, l2BridgeAddress); deployedChains[key] = true; } - - function bytesToAddress(bytes memory bys) private pure returns (address addr) { - assembly { - addr := mload(add(bys, 32)) - } - } } diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 2c67c8794..5ea46ff0c 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -376,8 +376,6 @@ contract DeployL2Script is Script { function finalizeRegistration() internal { ChainRegistrar chainRegistrar = ChainRegistrar(config.chainRegistrar); - console.logAddress(msg.sender); - console.logAddress(chainRegistrar.owner()); vm.broadcast(); chainRegistrar.chainRegistered(config.proposalAuthor, config.chainId); } From 6ea44a22629c813857859c18295ba6603f319b52 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 14 Nov 2024 22:19:55 +0700 Subject: [PATCH 34/54] Small refactoring Signed-off-by: Danil --- l1-contracts/contracts/chain-registrar/ChainRegistrar.sol | 8 ++++---- l1-contracts/deploy-scripts/DeployL2Contracts.sol | 2 +- l1-contracts/deploy-scripts/RegisterHyperchain.s.sol | 4 ++-- .../unit/concrete/chain-registrator/ChainRegistrar.t.sol | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index dffd9f67b..71b76a73c 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -54,7 +54,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { /// @param Chain id of the new chain should be unique for this bridgehub uint256 chainId; /// @param Operator for making commit txs. - address commitOperator; + address blobOperator; /// @param Operator for making Prove and Execute transactions address operator; /// @param Governor of the chain. Ownership of the chain will be transferred to this operator @@ -74,7 +74,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { function proposeChainRegistration( uint256 chainId, PubdataPricingMode pubdataPricingMode, - address commitOperator, + address blobOperator, address operator, address governor, address tokenAddress, @@ -85,7 +85,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { ChainConfig memory config = ChainConfig({ chainId: chainId, pubdataPricingMode: pubdataPricingMode, - commitOperator: commitOperator, + blobOperator: blobOperator, operator: operator, governor: governor, baseToken: BaseToken({ @@ -124,7 +124,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { return proposedChains[key]; } - function chainRegistered(address author, uint256 chainId) public onlyOwner nonReentrant { + function setChainAsRegistered(address author, uint256 chainId) public onlyOwner nonReentrant { bytes32 key = keccak256(abi.encode(author, chainId)); ChainConfig memory config = proposedChains[key]; if (config.chainId == 0) { diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 5ea46ff0c..2655be9be 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -377,6 +377,6 @@ contract DeployL2Script is Script { function finalizeRegistration() internal { ChainRegistrar chainRegistrar = ChainRegistrar(config.chainRegistrar); vm.broadcast(); - chainRegistrar.chainRegistered(config.proposalAuthor, config.chainId); + chainRegistrar.setChainAsRegistered(config.proposalAuthor, config.chainId); } } diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index e1c149c2c..8c648b861 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -145,7 +145,7 @@ contract RegisterHyperchainScript is Script { Utils.chainAdminMulticall({_chainAdmin: bridgehub.admin(), _target: config.bridgehub, _data: data, _value: 0}); console.log("Hyperchain registered"); - // Get new diamond proxy address from emitted events + // Get new diamond proxy address from bridgehub address diamondProxyAddress = bridgehub.getHyperchain(chainConfig.chainId); if (diamondProxyAddress == address(0)) { revert("Diamond proxy address not found"); @@ -158,7 +158,7 @@ contract RegisterHyperchainScript is Script { ValidatorTimelock validatorTimelock = ValidatorTimelock(config.validatorTimelock); vm.startBroadcast(); - validatorTimelock.addValidator(chainConfig.chainId, chainConfig.commitOperator); + validatorTimelock.addValidator(chainConfig.chainId, chainConfig.blobOperator); validatorTimelock.addValidator(chainConfig.chainId, chainConfig.operator); vm.stopBroadcast(); diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 3adfc3ab5..ed05e0312 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -106,7 +106,7 @@ contract ChainRegistrarTest is Test { chainRegistrar.proposeChainRegistration({ chainId: 1, pubdataPricingMode: PubdataPricingMode.Validium, - commitOperator: makeAddr("commitOperator"), + blobOperator: makeAddr("blobOperator"), operator: makeAddr("operator"), governor: makeAddr("governor"), tokenAddress: ETH_TOKEN_ADDRESS, @@ -127,7 +127,7 @@ contract ChainRegistrarTest is Test { sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); vm.recordLogs(); vm.prank(admin); - chainRegistrar.chainRegistered(author, 1); + chainRegistrar.setChainAsRegistered(author, 1); Vm.Log[] memory registeredLogs = vm.getRecordedLogs(); } } From 7a642e5ce67b36d87a6cc897ae83aa8332985849 Mon Sep 17 00:00:00 2001 From: Danil Date: Sat, 16 Nov 2024 13:02:49 +0700 Subject: [PATCH 35/54] Fix base token transfering Signed-off-by: Danil --- l1-contracts/contracts/chain-registrar/ChainRegistrar.sol | 2 +- l1-contracts/deploy-scripts/RegisterHyperchain.s.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 71b76a73c..ed18ae554 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -104,7 +104,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / config.baseToken.gasPriceMultiplierDenominator; - if (IERC20(config.baseToken.tokenAddress).balanceOf(address(this)) < amount) { + if (IERC20(config.baseToken.tokenAddress).balanceOf(l2Deployer) < amount) { bool success = IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); if (!success) { revert BaseTokenTransferFailed(); diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index 8c648b861..044175025 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -121,7 +121,7 @@ contract RegisterHyperchainScript is Script { function deployChainAdmin() internal { vm.broadcast(); - ChainAdmin chainAdmin = new ChainAdmin(chainConfig.governor, address(0)); + ChainAdmin chainAdmin = new ChainAdmin(chainConfig.governor, chainConfig.baseToken.tokenMultiplierSetter); console.log("ChainAdmin deployed at:", address(chainAdmin)); config.chainAdmin = address(chainAdmin); } From d0e377288728f18ab4b64b46fa18202624d2e71f Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 18 Nov 2024 18:20:19 +0700 Subject: [PATCH 36/54] Propose chain registration script Signed-off-by: Danil --- .../ProposeChainRegistration.sol | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 l1-contracts/deploy-scripts/ProposeChainRegistration.sol diff --git a/l1-contracts/deploy-scripts/ProposeChainRegistration.sol b/l1-contracts/deploy-scripts/ProposeChainRegistration.sol new file mode 100644 index 000000000..4aa29bad5 --- /dev/null +++ b/l1-contracts/deploy-scripts/ProposeChainRegistration.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {Script, console2 as console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; +import {ChainRegistrar} from "contracts/chain-registrar/ChainRegistrar.sol"; +import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; + +contract ProposeChainRegistration is Script { + using stdToml for string; + address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; + + // solhint-disable-next-line gas-struct-packing + struct Config { + address chainRegistrar; + ChainRegistrar.ChainConfig chainConfig; + } + + Config config; + + function run() external { + initializeConfig(); + approveBaseToken(); + proposeRegistration(); + } + + function initializeConfig() internal { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-config/config-propose-chain-registration.toml"); + string memory toml = vm.readFile(path); + + // Config file must be parsed key by key, otherwise values returned + // are parsed alfabetically and not by key. + // https://book.getfoundry.sh/cheatcodes/parse-toml + config.chainRegistrar = toml.readAddress("$.chain_registrar"); + + config.chainConfig.chainId = toml.readUint("$.chain.chain_id"); + config.chainConfig.operator = toml.readAddress("$.chain.operator"); + config.chainConfig.blobOperator = toml.readAddress("$.chain.blobOperator"); + config.chainConfig.governor = toml.readAddress("$.chain.governor"); + config.chainConfig.pubdataPricingMode = PubdataPricingMode(toml.readUint("$.chain.pubdataPricingMode")); + + config.chainConfig.baseToken.tokenMultiplierSetter = toml.readAddress("$.base_token.token_multiplier_setter"); + config.chainConfig.baseToken.tokenAddress = toml.readAddress("$.base_token.token_address"); + config.chainConfig.baseToken.gasPriceMultiplierNominator = uint128( + toml.readUint("$.base_token.gas_price_multiplier_nominator") + ); + config.chainConfig.baseToken.gasPriceMultiplierDenominator = uint128( + toml.readUint("$.base_token.gas_price_multiplier_denominator") + ); + } + + function approveBaseToken() internal { + if (config.chainConfig.baseToken.tokenAddress == ADDRESS_ONE) { + return; + } + uint256 amount = (1 ether * config.chainConfig.baseToken.gasPriceMultiplierNominator) / + config.chainConfig.baseToken.gasPriceMultiplierDenominator; + + vm.broadcast(); + IERC20(config.chainConfig.baseToken.tokenAddress).approve(config.chainRegistrar, amount); + } + + function proposeRegistration() internal { + ChainRegistrar chain_registrar = ChainRegistrar(config.chainRegistrar); + vm.broadcast(); + chain_registrar.proposeChainRegistration( + config.chainConfig.chainId, + config.chainConfig.pubdataPricingMode, + config.chainConfig.blobOperator, + config.chainConfig.operator, + config.chainConfig.governor, + config.chainConfig.baseToken.tokenAddress, + config.chainConfig.baseToken.tokenMultiplierSetter, + config.chainConfig.baseToken.gasPriceMultiplierNominator, + config.chainConfig.baseToken.gasPriceMultiplierDenominator + ); + } +} From e99c0ff3ebc6a8689b184d696c392b0da18fb597 Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 18 Nov 2024 19:09:29 +0700 Subject: [PATCH 37/54] Propose chain registration script Signed-off-by: Danil --- ...roposeChainRegistration.sol => ProposeChainRegistration.s.sol} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename l1-contracts/deploy-scripts/{ProposeChainRegistration.sol => ProposeChainRegistration.s.sol} (100%) diff --git a/l1-contracts/deploy-scripts/ProposeChainRegistration.sol b/l1-contracts/deploy-scripts/ProposeChainRegistration.s.sol similarity index 100% rename from l1-contracts/deploy-scripts/ProposeChainRegistration.sol rename to l1-contracts/deploy-scripts/ProposeChainRegistration.s.sol From 9d007bbb30795c204b72e752f02173a7257e274f Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 18 Nov 2024 19:17:16 +0700 Subject: [PATCH 38/54] Fix script Signed-off-by: Danil --- .../deploy-scripts/ProposeChainRegistration.s.sol | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/l1-contracts/deploy-scripts/ProposeChainRegistration.s.sol b/l1-contracts/deploy-scripts/ProposeChainRegistration.s.sol index 4aa29bad5..0676a056b 100644 --- a/l1-contracts/deploy-scripts/ProposeChainRegistration.s.sol +++ b/l1-contracts/deploy-scripts/ProposeChainRegistration.s.sol @@ -37,17 +37,19 @@ contract ProposeChainRegistration is Script { config.chainConfig.chainId = toml.readUint("$.chain.chain_id"); config.chainConfig.operator = toml.readAddress("$.chain.operator"); - config.chainConfig.blobOperator = toml.readAddress("$.chain.blobOperator"); + config.chainConfig.blobOperator = toml.readAddress("$.chain.blob_operator"); config.chainConfig.governor = toml.readAddress("$.chain.governor"); - config.chainConfig.pubdataPricingMode = PubdataPricingMode(toml.readUint("$.chain.pubdataPricingMode")); + config.chainConfig.pubdataPricingMode = PubdataPricingMode(toml.readUint("$.chain.pubdata_pricing_mode")); - config.chainConfig.baseToken.tokenMultiplierSetter = toml.readAddress("$.base_token.token_multiplier_setter"); - config.chainConfig.baseToken.tokenAddress = toml.readAddress("$.base_token.token_address"); + config.chainConfig.baseToken.tokenMultiplierSetter = toml.readAddress( + "$.chain.base_token.token_multiplier_setter" + ); + config.chainConfig.baseToken.tokenAddress = toml.readAddress("$.chain.base_token.address"); config.chainConfig.baseToken.gasPriceMultiplierNominator = uint128( - toml.readUint("$.base_token.gas_price_multiplier_nominator") + toml.readUint("$.chain.base_token.nominator") ); config.chainConfig.baseToken.gasPriceMultiplierDenominator = uint128( - toml.readUint("$.base_token.gas_price_multiplier_denominator") + toml.readUint("$.chain.base_token.denominator") ); } From 9a72fc2de1377df53027d6ec61347a5ec5b04fef Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 10:39:26 +0700 Subject: [PATCH 39/54] Deploy registrar with transperent proxy Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 2 +- l1-contracts/deploy-scripts/DeployL1.s.sol | 21 ++++++++++++++----- .../chain-registrator/ChainRegistrar.t.sol | 3 ++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index ed18ae554..64167ff65 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -65,7 +65,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { PubdataPricingMode pubdataPricingMode; } - constructor(address _bridgehub, address _l2Deployer, address _owner) reentrancyGuardInitializer { + function initialize(address _bridgehub, address _l2Deployer, address _owner) public reentrancyGuardInitializer { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index d0a309c7e..6213f3bb9 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -307,13 +307,24 @@ contract DeployL1Script is Script { } function deployChainRegistrar() internal { + bytes memory bytecodeImplementation = abi.encodePacked(type(ChainRegistrar).creationCode); + address chainRegistrarImplementation = deployViaCreate2(bytecodeImplementation); + console.log("Chain Registrar implementation deployed at:", chainRegistrarImplementation); + bytes memory bytecode = abi.encodePacked( - type(ChainRegistrar).creationCode, - abi.encode(addresses.bridgehub.bridgehubProxy, config.l2Deployer, config.ownerAddress) + type(TransparentUpgradeableProxy).creationCode, + abi.encode( + chainRegistrarImplementation, + addresses.transparentProxyAdmin, + abi.encodeCall( + ChainRegistrar.initialize, + (addresses.bridgehub.bridgehubProxy, config.l2Deployer, config.ownerAddress) + ) + ) ); - address contractAddress = deployViaCreate2(bytecode); - console.log("Chain Registrar deployed at:", contractAddress); - addresses.chainRegistrar = contractAddress; + address chainRegistrar = deployViaCreate2(bytecode); + console.log("Chain Registrar deployed at:", chainRegistrar); + addresses.chainRegistrar = chainRegistrar; } function deployChainAdmin() internal { diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index ed05e0312..b836d2ece 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -96,7 +96,8 @@ contract ChainRegistrarTest is Test { vm.stopPrank(); vm.prank(stm.admin()); stm.setChainCreationParams(chainCreationParams); - chainRegistrar = new ChainRegistrar(address(bridgeHub), deployer, admin); + chainRegistrar = new ChainRegistrar(); + chainRegistrar.initialize(address(bridgeHub), deployer, admin); } function test_SuccessfulProposal() public { From 49befd8c2860bc4522227e98bf80abebc02cac8b Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 14:30:52 +0700 Subject: [PATCH 40/54] Implemet get deployed config Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 64167ff65..59e66491b 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -65,12 +65,25 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { PubdataPricingMode pubdataPricingMode; } + struct DeployedChainConfig { + address pendingChainAdmin; + address chainAdmin; + address diamondProxy; + address l2BridgeAddress; + } + + // @dev Initialize the contract function initialize(address _bridgehub, address _l2Deployer, address _owner) public reentrancyGuardInitializer { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); } + // @dev Propose a new chain to be registered in zksync ecosystem. + // ZkSync administration will use this data for registering the chain on bridgehub. + // The call will fail if the chain already registered. + // Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer + // this token to l2 deployer directly function proposeChainRegistration( uint256 chainId, PubdataPricingMode pubdataPricingMode, @@ -114,6 +127,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { emit NewChainRegistrationProposal(config.chainId, msg.sender, key); } + // @dev Change l2 deployer function changeDeployer(address newDeployer) public onlyOwner { l2Deployer = newDeployer; emit L2DeployerChanged(l2Deployer); @@ -124,30 +138,42 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { return proposedChains[key]; } - function setChainAsRegistered(address author, uint256 chainId) public onlyOwner nonReentrant { - bytes32 key = keccak256(abi.encode(author, chainId)); - ChainConfig memory config = proposedChains[key]; - if (config.chainId == 0) { - revert ProposalNotFound(); - } - - if (deployedChains[key]) { - revert ChainIsAlreadyDeployed(); - } + function getDeployedChainConfig(uint256 chainId) public view returns (DeployedChainConfig memory) { address stm = bridgehub.stateTransitionManager(chainId); if (stm == address(0)) { revert ChainIsNotYetDeployed(); } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); - // Matter Labs team set the pending admin to the chain admin and now governor of the chain must accept ownership - address chainAdmin = IGetters(diamondProxy).getPendingAdmin(); + + address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); + address chainAdmin = IGetters(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); } - emit NewChainDeployed(chainId, author, diamondProxy, chainAdmin); - emit SharedBridgeRegistered(chainId, l2BridgeAddress); + DeployedChainConfig memory config = DeployedChainConfig({ + pendingChainAdmin: pendingChainAdmin, + chainAdmin: chainAdmin, + diamondProxy: diamondProxy, + l2BridgeAddress: l2BridgeAddress + }); + return config; + } + + // @dev Mark chain as registered. Emit necessary events for spinning up the chain server + function setChainAsRegistered(address author, uint256 chainId) public onlyOwner nonReentrant { + bytes32 key = keccak256(abi.encode(author, chainId)); + ChainConfig memory config = proposedChains[key]; + if (config.chainId == 0) { + revert ProposalNotFound(); + } + + DeployedChainConfig memory deployedConfig = getDeployedChainConfig(chainId); + + // Matter Labs team set the pending admin to the chain admin and now governor of the chain must accept ownership + emit NewChainDeployed(chainId, author, deployedConfig.diamondProxy, deployedConfig.pendingChainAdmin); + emit SharedBridgeRegistered(chainId, deployedConfig.l2BridgeAddress); deployedChains[key] = true; } } From b077dd4e1c1c5b761a51681837650b76583b70c6 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 14:41:06 +0700 Subject: [PATCH 41/54] Registered chain config as an additional function Signed-off-by: Danil --- .../contracts/chain-registrar/ChainRegistrar.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 59e66491b..dd052c6f7 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -65,7 +65,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { PubdataPricingMode pubdataPricingMode; } - struct DeployedChainConfig { + struct RegisteredChainConfig { address pendingChainAdmin; address chainAdmin; address diamondProxy; @@ -138,7 +138,8 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { return proposedChains[key]; } - function getDeployedChainConfig(uint256 chainId) public view returns (DeployedChainConfig memory) { + // @dev Get data about the chain that has been fully deployed + function getRegisteredChainConfig(uint256 chainId) public view returns (RegisteredChainConfig memory) { address stm = bridgehub.stateTransitionManager(chainId); if (stm == address(0)) { revert ChainIsNotYetDeployed(); @@ -152,7 +153,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert BridgeIsNotRegistered(); } - DeployedChainConfig memory config = DeployedChainConfig({ + RegisteredChainConfig memory config = RegisteredChainConfig({ pendingChainAdmin: pendingChainAdmin, chainAdmin: chainAdmin, diamondProxy: diamondProxy, @@ -169,7 +170,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { revert ProposalNotFound(); } - DeployedChainConfig memory deployedConfig = getDeployedChainConfig(chainId); + RegisteredChainConfig memory deployedConfig = getRegisteredChainConfig(chainId); // Matter Labs team set the pending admin to the chain admin and now governor of the chain must accept ownership emit NewChainDeployed(chainId, author, deployedConfig.diamondProxy, deployedConfig.pendingChainAdmin); From 9c138fd8183329cf5dec1e17ebf386c64440d8df Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 14:45:55 +0100 Subject: [PATCH 42/54] Apply suggestions from code review Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> --- l1-contracts/contracts/chain-registrar/ChainRegistrar.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index dd052c6f7..20021bd2a 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -15,7 +15,7 @@ import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; /// @custom:security-contact security@matterlabs.dev /// @dev ChainRegistrar serves as the main point for chain registration. contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { - /// Address that will be used for deploying l2 contracts + /// @notice Address that will be used for deploying l2 contracts address public l2Deployer; /// ZKsync Bridgehub IBridgehub public bridgehub; @@ -80,7 +80,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } // @dev Propose a new chain to be registered in zksync ecosystem. - // ZkSync administration will use this data for registering the chain on bridgehub. + // ZKsync administration will use this data for registering the chain on bridgehub. // The call will fail if the chain already registered. // Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer // this token to l2 deployer directly From 7cc89ac8714b8b264206ca224d7de7418cdd3f94 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 21:06:54 +0700 Subject: [PATCH 43/54] Try to fix the test Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 30 +++++++++++++------ .../dev-contracts/test/DummyHyperchain.sol | 18 ++++++----- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 20021bd2a..c7762ecce 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -102,11 +102,11 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { operator: operator, governor: governor, baseToken: BaseToken({ - tokenAddress: tokenAddress, - tokenMultiplierSetter: tokenMultiplierSetter, - gasPriceMultiplierNominator: gasPriceMultiplierNominator, - gasPriceMultiplierDenominator: gasPriceMultiplierDenominator - }) + tokenAddress: tokenAddress, + tokenMultiplierSetter: tokenMultiplierSetter, + gasPriceMultiplierNominator: gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + }) }); bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { @@ -116,7 +116,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / - config.baseToken.gasPriceMultiplierDenominator; + config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(l2Deployer) < amount) { bool success = IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); if (!success) { @@ -139,15 +139,22 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } // @dev Get data about the chain that has been fully deployed - function getRegisteredChainConfig(uint256 chainId) public view returns (RegisteredChainConfig memory) { + function getRegisteredChainConfig(uint256 chainId) public returns (RegisteredChainConfig memory) { address stm = bridgehub.stateTransitionManager(chainId); if (stm == address(0)) { revert ChainIsNotYetDeployed(); } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); - address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); - address chainAdmin = IGetters(diamondProxy).getAdmin(); + (bool success, bytes memory data) = diamondProxy.call(abi.encodeWithSignature("getPendingAdmin()")); + require(success); + (bool success1, bytes memory data1) = diamondProxy.call(abi.encodeWithSignature("getAdmin()")); + require(success1); + + address pendingChainAdmin = bytesToAddress(data); + address chainAdmin = bytesToAddress(data1); +// address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); +// address chainAdmin = IGetters(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); @@ -177,4 +184,9 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { emit SharedBridgeRegistered(chainId, deployedConfig.l2BridgeAddress); deployedChains[key] = true; } + + function bytesToAddress(bytes memory b) private pure returns (address) { + return address(uint160(bytes20(b))); + } + } diff --git a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol index d90f6bab8..13a6539d0 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol @@ -41,15 +41,19 @@ contract DummyHyperchain is MailboxFacet { return admin; } + function getPendingAdmin() external view returns (address) { + return admin; + } + function _randomFeeParams() internal pure returns (FeeParams memory) { return FeeParams({ - pubdataPricingMode: PubdataPricingMode.Rollup, - batchOverheadL1Gas: 1_000_000, - maxPubdataPerBatch: 110_000, - maxL2GasPerBatch: 80_000_000, - priorityTxMaxPubdata: 99_000, - minimalL2GasPrice: 250_000_000 - }); + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1_000_000, + maxPubdataPerBatch: 110_000, + maxL2GasPerBatch: 80_000_000, + priorityTxMaxPubdata: 99_000, + minimalL2GasPrice: 250_000_000 + }); } } From 139474f33b11d640a4c14ced3135d2c8c8a73cfc Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 21:19:36 +0700 Subject: [PATCH 44/54] Properly fix test Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 28 ++++++------------- .../dev-contracts/test/DummyHyperchain.sol | 14 +++++----- .../chain-registrator/ChainRegistrar.t.sol | 10 ++++--- 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index c7762ecce..fec24baee 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -102,11 +102,11 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { operator: operator, governor: governor, baseToken: BaseToken({ - tokenAddress: tokenAddress, - tokenMultiplierSetter: tokenMultiplierSetter, - gasPriceMultiplierNominator: gasPriceMultiplierNominator, - gasPriceMultiplierDenominator: gasPriceMultiplierDenominator - }) + tokenAddress: tokenAddress, + tokenMultiplierSetter: tokenMultiplierSetter, + gasPriceMultiplierNominator: gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + }) }); bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { @@ -116,7 +116,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / - config.baseToken.gasPriceMultiplierDenominator; + config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(l2Deployer) < amount) { bool success = IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); if (!success) { @@ -146,15 +146,8 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); - (bool success, bytes memory data) = diamondProxy.call(abi.encodeWithSignature("getPendingAdmin()")); - require(success); - (bool success1, bytes memory data1) = diamondProxy.call(abi.encodeWithSignature("getAdmin()")); - require(success1); - - address pendingChainAdmin = bytesToAddress(data); - address chainAdmin = bytesToAddress(data1); -// address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); -// address chainAdmin = IGetters(diamondProxy).getAdmin(); + address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); + address chainAdmin = IGetters(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); @@ -184,9 +177,4 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { emit SharedBridgeRegistered(chainId, deployedConfig.l2BridgeAddress); deployedChains[key] = true; } - - function bytesToAddress(bytes memory b) private pure returns (address) { - return address(uint160(bytes20(b))); - } - } diff --git a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol index 13a6539d0..5e85e97e8 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol @@ -48,12 +48,12 @@ contract DummyHyperchain is MailboxFacet { function _randomFeeParams() internal pure returns (FeeParams memory) { return FeeParams({ - pubdataPricingMode: PubdataPricingMode.Rollup, - batchOverheadL1Gas: 1_000_000, - maxPubdataPerBatch: 110_000, - maxL2GasPerBatch: 80_000_000, - priorityTxMaxPubdata: 99_000, - minimalL2GasPrice: 250_000_000 - }); + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1_000_000, + maxPubdataPerBatch: 110_000, + maxL2GasPerBatch: 80_000_000, + priorityTxMaxPubdata: 99_000, + minimalL2GasPrice: 250_000_000 + }); } } diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index b836d2ece..60cdc2161 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -116,13 +116,10 @@ contract ChainRegistrarTest is Test { gasPriceMultiplierDenominator: 1 }); Vm.Log[] memory proposeLogs = vm.getRecordedLogs(); - console.logAddress(admin); - console.logAddress(bridgeHub.admin()); - console.logAddress(bridgeHub.owner()); DummyHyperchain hyperchain = new DummyHyperchain(address(bridgeHub), 270); hyperchain.initialize(admin); vm.prank(admin); - stm.setHyperchain(1, makeAddr("hyperchain")); + stm.setHyperchain(1, address(hyperchain)); bridgeHub.setStateTransitionManager(1, address(stm)); vm.prank(admin); sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); @@ -130,5 +127,10 @@ contract ChainRegistrarTest is Test { vm.prank(admin); chainRegistrar.setChainAsRegistered(author, 1); Vm.Log[] memory registeredLogs = vm.getRecordedLogs(); + ChainRegistrar.RegisteredChainConfig memory registeredConfig = chainRegistrar.getRegisteredChainConfig(1); + require(registeredConfig.diamondProxy != address(0)); + require(registeredConfig.chainAdmin != address(0)); + require(registeredConfig.l2BridgeAddress != address(0)); + require(registeredConfig.pendingChainAdmin != address(0)); } } From 5828b737d9b6923dbe97dea35d87edbdaefce604 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 21 Nov 2024 21:35:43 +0700 Subject: [PATCH 45/54] Apply review suggestions Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 88 +++++++++---------- .../chain-registrator/ChainRegistrar.t.sol | 18 ++-- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index fec24baee..e08a59ebb 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -10,20 +10,22 @@ import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev ChainRegistrar serves as the main point for chain registration. contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { + using SafeERC20 for IERC20; /// @notice Address that will be used for deploying l2 contracts address public l2Deployer; /// ZKsync Bridgehub IBridgehub public bridgehub; /// Chains that has been successfully deployed - mapping(bytes32 => bool) public deployedChains; + mapping(address => mapping(uint256 => bool)) public deployedChains; /// Proposal for chain registration - mapping(bytes32 => ChainConfig) public proposedChains; + mapping(address => mapping(uint256 => ChainConfig)) public proposedChains; error ProposalNotFound(); error BaseTokenTransferFailed(); @@ -35,7 +37,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { event NewChainDeployed(uint256 indexed chainId, address author, address diamondProxy, address chainAdmin); /// @notice new chain is proposed to register - event NewChainRegistrationProposal(uint256 indexed chainId, address author, bytes32 key); + event NewChainRegistrationProposal(uint256 indexed chainId, address author); /// @notice Shared bridge is registered on l2 event SharedBridgeRegistered(uint256 indexed chainId, address l2Address); @@ -85,70 +87,67 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { // Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer // this token to l2 deployer directly function proposeChainRegistration( - uint256 chainId, - PubdataPricingMode pubdataPricingMode, - address blobOperator, - address operator, - address governor, - address tokenAddress, - address tokenMultiplierSetter, - uint128 gasPriceMultiplierNominator, - uint128 gasPriceMultiplierDenominator + uint256 _chainId, + PubdataPricingMode _pubdataPricingMode, + address _blobOperator, + address _operator, + address _governor, + address _tokenAddress, + address _tokenMultiplierSetter, + uint128 _gasPriceMultiplierNominator, + uint128 _gasPriceMultiplierDenominator ) public { ChainConfig memory config = ChainConfig({ - chainId: chainId, - pubdataPricingMode: pubdataPricingMode, - blobOperator: blobOperator, - operator: operator, - governor: governor, + chainId: _chainId, + pubdataPricingMode: _pubdataPricingMode, + blobOperator: _blobOperator, + operator: _operator, + governor: _governor, baseToken: BaseToken({ - tokenAddress: tokenAddress, - tokenMultiplierSetter: tokenMultiplierSetter, - gasPriceMultiplierNominator: gasPriceMultiplierNominator, - gasPriceMultiplierDenominator: gasPriceMultiplierDenominator + tokenAddress: _tokenAddress, + tokenMultiplierSetter: _tokenMultiplierSetter, + gasPriceMultiplierNominator: _gasPriceMultiplierNominator, + gasPriceMultiplierDenominator: _gasPriceMultiplierDenominator }) }); - bytes32 key = keccak256(abi.encode(msg.sender, config.chainId)); - if (deployedChains[key] || bridgehub.stateTransitionManager(config.chainId) != address(0)) { + if ( + deployedChains[msg.sender][config.chainId] || bridgehub.stateTransitionManager(config.chainId) != address(0) + ) { revert ChainIsAlreadyDeployed(); } - proposedChains[key] = config; + proposedChains[msg.sender][_chainId] = config; // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / config.baseToken.gasPriceMultiplierDenominator; if (IERC20(config.baseToken.tokenAddress).balanceOf(l2Deployer) < amount) { - bool success = IERC20(config.baseToken.tokenAddress).transferFrom(msg.sender, l2Deployer, amount); - if (!success) { - revert BaseTokenTransferFailed(); - } + IERC20(config.baseToken.tokenAddress).safeTransferFrom(msg.sender, l2Deployer, amount); } } - emit NewChainRegistrationProposal(config.chainId, msg.sender, key); + emit NewChainRegistrationProposal(config.chainId, msg.sender); } // @dev Change l2 deployer - function changeDeployer(address newDeployer) public onlyOwner { - l2Deployer = newDeployer; + function changeDeployer(address _newDeployer) public onlyOwner { + l2Deployer = _newDeployer; emit L2DeployerChanged(l2Deployer); } - function getChainConfig(address author, uint256 chainId) public view returns (ChainConfig memory) { - bytes32 key = keccak256(abi.encode(author, chainId)); - return proposedChains[key]; + function getChainConfig(address _author, uint256 _chainId) public view returns (ChainConfig memory) { + return proposedChains[_author][_chainId]; } // @dev Get data about the chain that has been fully deployed - function getRegisteredChainConfig(uint256 chainId) public returns (RegisteredChainConfig memory) { - address stm = bridgehub.stateTransitionManager(chainId); + function getRegisteredChainConfig(uint256 _chainId) public view returns (RegisteredChainConfig memory) { + address stm = bridgehub.stateTransitionManager(_chainId); if (stm == address(0)) { revert ChainIsNotYetDeployed(); } - address diamondProxy = IStateTransitionManager(stm).getHyperchain(chainId); + address diamondProxy = IStateTransitionManager(stm).getHyperchain(_chainId); address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); address chainAdmin = IGetters(diamondProxy).getAdmin(); - address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(chainId); + address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(_chainId); if (l2BridgeAddress == address(0)) { revert BridgeIsNotRegistered(); } @@ -163,18 +162,17 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } // @dev Mark chain as registered. Emit necessary events for spinning up the chain server - function setChainAsRegistered(address author, uint256 chainId) public onlyOwner nonReentrant { - bytes32 key = keccak256(abi.encode(author, chainId)); - ChainConfig memory config = proposedChains[key]; + function setChainAsRegistered(address _author, uint256 _chainId) public onlyOwner nonReentrant { + ChainConfig memory config = proposedChains[_author][_chainId]; if (config.chainId == 0) { revert ProposalNotFound(); } - RegisteredChainConfig memory deployedConfig = getRegisteredChainConfig(chainId); + RegisteredChainConfig memory deployedConfig = getRegisteredChainConfig(_chainId); // Matter Labs team set the pending admin to the chain admin and now governor of the chain must accept ownership - emit NewChainDeployed(chainId, author, deployedConfig.diamondProxy, deployedConfig.pendingChainAdmin); - emit SharedBridgeRegistered(chainId, deployedConfig.l2BridgeAddress); - deployedChains[key] = true; + emit NewChainDeployed(_chainId, _author, deployedConfig.diamondProxy, deployedConfig.pendingChainAdmin); + emit SharedBridgeRegistered(_chainId, deployedConfig.l2BridgeAddress); + deployedChains[_author][_chainId] = true; } } diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 60cdc2161..2097f37b0 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -105,15 +105,15 @@ contract ChainRegistrarTest is Test { vm.prank(author); vm.recordLogs(); chainRegistrar.proposeChainRegistration({ - chainId: 1, - pubdataPricingMode: PubdataPricingMode.Validium, - blobOperator: makeAddr("blobOperator"), - operator: makeAddr("operator"), - governor: makeAddr("governor"), - tokenAddress: ETH_TOKEN_ADDRESS, - tokenMultiplierSetter: makeAddr("setter"), - gasPriceMultiplierNominator: 1, - gasPriceMultiplierDenominator: 1 + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("governor"), + _tokenAddress: ETH_TOKEN_ADDRESS, + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 1, + _gasPriceMultiplierDenominator: 1 }); Vm.Log[] memory proposeLogs = vm.getRecordedLogs(); DummyHyperchain hyperchain = new DummyHyperchain(address(bridgeHub), 270); From 6ed3ebc82eb78759c19e599aff6473db73d0b59b Mon Sep 17 00:00:00 2001 From: Danil Date: Fri, 22 Nov 2024 18:27:47 +0700 Subject: [PATCH 46/54] Remove unnnecessary functions Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 51 ++++--------------- .../deploy-scripts/DeployL2Contracts.sol | 7 --- .../deploy-scripts/RegisterHyperchain.s.sol | 2 +- .../chain-registrator/ChainRegistrar.t.sol | 2 - 4 files changed, 12 insertions(+), 50 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index e08a59ebb..5c245f29e 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -9,39 +9,29 @@ import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; -import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev ChainRegistrar serves as the main point for chain registration. -contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { +contract ChainRegistrar is Ownable2StepUpgradeable { using SafeERC20 for IERC20; /// @notice Address that will be used for deploying l2 contracts address public l2Deployer; /// ZKsync Bridgehub IBridgehub public bridgehub; - /// Chains that has been successfully deployed - mapping(address => mapping(uint256 => bool)) public deployedChains; /// Proposal for chain registration mapping(address => mapping(uint256 => ChainConfig)) public proposedChains; - error ProposalNotFound(); error BaseTokenTransferFailed(); error ChainIsAlreadyDeployed(); error ChainIsNotYetDeployed(); error BridgeIsNotRegistered(); - /// @notice new chain is deployed - event NewChainDeployed(uint256 indexed chainId, address author, address diamondProxy, address chainAdmin); - /// @notice new chain is proposed to register event NewChainRegistrationProposal(uint256 indexed chainId, address author); - /// @notice Shared bridge is registered on l2 - event SharedBridgeRegistered(uint256 indexed chainId, address l2Address); - /// @notice L2 Deployer has changed event L2DeployerChanged(address newDeployer); @@ -75,17 +65,19 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { } // @dev Initialize the contract - function initialize(address _bridgehub, address _l2Deployer, address _owner) public reentrancyGuardInitializer { + function initialize(address _bridgehub, address _l2Deployer, address _owner) public { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); } - // @dev Propose a new chain to be registered in zksync ecosystem. - // ZKsync administration will use this data for registering the chain on bridgehub. - // The call will fail if the chain already registered. - // Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer - // this token to l2 deployer directly + /// @dev Propose a new chain to be registered in zksync ecosystem. + /// ZKsync administration will use this data for registering the chain on bridgehub. + /// The call will fail if the chain already registered. + /// Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer + /// this token to l2 deployer directly + /// @param _chainId + function proposeChainRegistration( uint256 _chainId, PubdataPricingMode _pubdataPricingMode, @@ -96,7 +88,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { address _tokenMultiplierSetter, uint128 _gasPriceMultiplierNominator, uint128 _gasPriceMultiplierDenominator - ) public { + ) external { ChainConfig memory config = ChainConfig({ chainId: _chainId, pubdataPricingMode: _pubdataPricingMode, @@ -110,9 +102,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { gasPriceMultiplierDenominator: _gasPriceMultiplierDenominator }) }); - if ( - deployedChains[msg.sender][config.chainId] || bridgehub.stateTransitionManager(config.chainId) != address(0) - ) { + if (bridgehub.stateTransitionManager(config.chainId) != address(0)) { revert ChainIsAlreadyDeployed(); } proposedChains[msg.sender][_chainId] = config; @@ -133,10 +123,6 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { emit L2DeployerChanged(l2Deployer); } - function getChainConfig(address _author, uint256 _chainId) public view returns (ChainConfig memory) { - return proposedChains[_author][_chainId]; - } - // @dev Get data about the chain that has been fully deployed function getRegisteredChainConfig(uint256 _chainId) public view returns (RegisteredChainConfig memory) { address stm = bridgehub.stateTransitionManager(_chainId); @@ -160,19 +146,4 @@ contract ChainRegistrar is Ownable2StepUpgradeable, ReentrancyGuard { }); return config; } - - // @dev Mark chain as registered. Emit necessary events for spinning up the chain server - function setChainAsRegistered(address _author, uint256 _chainId) public onlyOwner nonReentrant { - ChainConfig memory config = proposedChains[_author][_chainId]; - if (config.chainId == 0) { - revert ProposalNotFound(); - } - - RegisteredChainConfig memory deployedConfig = getRegisteredChainConfig(_chainId); - - // Matter Labs team set the pending admin to the chain admin and now governor of the chain must accept ownership - emit NewChainDeployed(_chainId, _author, deployedConfig.diamondProxy, deployedConfig.pendingChainAdmin); - emit SharedBridgeRegistered(_chainId, deployedConfig.l2BridgeAddress); - deployedChains[_author][_chainId] = true; - } } diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 2655be9be..70ea7ed91 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -68,7 +68,6 @@ contract DeployL2Script is Script { deploySharedBridge(); deploySharedBridgeProxy(legacyBridge); initializeChain(); - finalizeRegistration(); deployForceDeployer(); deployConsensusRegistry(); deployConsensusRegistryProxy(); @@ -373,10 +372,4 @@ contract DeployL2Script is Script { _value: 0 }); } - - function finalizeRegistration() internal { - ChainRegistrar chainRegistrar = ChainRegistrar(config.chainRegistrar); - vm.broadcast(); - chainRegistrar.setChainAsRegistered(config.proposalAuthor, config.chainId); - } } diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index 044175025..bfecbe467 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -82,7 +82,7 @@ contract RegisterHyperchainScript is Script { } function loadChain() internal { - chainConfig = chainRegistrar.getChainConfig(config.proposalAuthor, config.chainChainId); + chainConfig = chainRegistrar.proposedChains[config.proposalAuthor][config.chainChainId]; } function checkTokenAddress() internal view { diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 2097f37b0..bcbe7dc82 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -125,8 +125,6 @@ contract ChainRegistrarTest is Test { sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); vm.recordLogs(); vm.prank(admin); - chainRegistrar.setChainAsRegistered(author, 1); - Vm.Log[] memory registeredLogs = vm.getRecordedLogs(); ChainRegistrar.RegisteredChainConfig memory registeredConfig = chainRegistrar.getRegisteredChainConfig(1); require(registeredConfig.diamondProxy != address(0)); require(registeredConfig.chainAdmin != address(0)); From 9ef8a21cf93563cb8de87dd9f168c4217932a415 Mon Sep 17 00:00:00 2001 From: Danil Date: Fri, 22 Nov 2024 19:57:44 +0700 Subject: [PATCH 47/54] Add more comments Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 5c245f29e..407076780 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -14,6 +14,8 @@ import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev ChainRegistrar serves as the main point for chain registration. +/// Contract should be deployed using Proxy. This contract is an addition to the zksync ecosystem +/// and it's not allowed to do any calls to the Bridgehub. contract ChainRegistrar is Ownable2StepUpgradeable { using SafeERC20 for IERC20; /// @notice Address that will be used for deploying l2 contracts @@ -36,27 +38,33 @@ contract ChainRegistrar is Ownable2StepUpgradeable { event L2DeployerChanged(address newDeployer); struct BaseToken { - address tokenAddress; - address tokenMultiplierSetter; + /// @param gasPriceMultiplierNominator, used to compare the baseTokenPrice to ether for L1->L2 transactions uint128 gasPriceMultiplierNominator; + /// @param gasPriceMultiplierDenominator, used to compare the baseTokenPrice to ether for L1->L2 transactions uint128 gasPriceMultiplierDenominator; + /// @param tokenAddress the base token address used to pay for gas fees + address tokenAddress; + /// @param okenMultiplierSetter The new address to be set as the token multiplier setter. + address tokenMultiplierSetter; } + // solhint-disable-next-line gas-struct-packing struct ChainConfig { /// @param Chain id of the new chain should be unique for this bridgehub uint256 chainId; + /// @param baseToken of the chain + BaseToken baseToken; /// @param Operator for making commit txs. address blobOperator; /// @param Operator for making Prove and Execute transactions address operator; - /// @param Governor of the chain. Ownership of the chain will be transferred to this operator + /// @param Governor of the chain. Ownership of the ChainAdmin will be transferred to this address address governor; - /// @param baseToken of the chain - BaseToken baseToken; /// @param pubdataPricingMode How the users will charged for pubdata. PubdataPricingMode pubdataPricingMode; } + // solhint-disable-next-line gas-struct-packing struct RegisteredChainConfig { address pendingChainAdmin; address chainAdmin; @@ -76,15 +84,22 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// The call will fail if the chain already registered. /// Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer /// this token to l2 deployer directly - /// @param _chainId - + /// @param _chainId of the new chain should be unique for this bridgehub + /// @param _pubdataPricingMode How the users will charged for pubdata. + /// @param _blobOperator for making commit txs. + /// @param _operator for making Prove and Execute transactions + /// @param _governor Ownership of the ChainAdmin will be transferred to this address + /// @param _baseTokenAddress the base token address used to pay for gas fees + /// @param _tokenMultiplierSetter The new address to be set as the token multiplier setter. + /// @param _gasPriceMultiplierNominator, used to compare the baseTokenPrice to ether for L1->L2 transactions + /// @param _gasPriceMultiplierDenominator, used to compare the baseTokenPrice to ether for L1->L2 transactions function proposeChainRegistration( uint256 _chainId, PubdataPricingMode _pubdataPricingMode, address _blobOperator, address _operator, address _governor, - address _tokenAddress, + address _baseTokenAddress, address _tokenMultiplierSetter, uint128 _gasPriceMultiplierNominator, uint128 _gasPriceMultiplierDenominator @@ -96,7 +111,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { operator: _operator, governor: _governor, baseToken: BaseToken({ - tokenAddress: _tokenAddress, + tokenAddress: _baseTokenAddress, tokenMultiplierSetter: _tokenMultiplierSetter, gasPriceMultiplierNominator: _gasPriceMultiplierNominator, gasPriceMultiplierDenominator: _gasPriceMultiplierDenominator From 8ceaa5b26c720c8708d9e16ee830cda698e29b34 Mon Sep 17 00:00:00 2001 From: Danil Date: Fri, 22 Nov 2024 19:57:44 +0700 Subject: [PATCH 48/54] Add more comments Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 108 ++++++++++++------ .../chain-registrator/ChainRegistrar.t.sol | 2 +- 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 407076780..a05a04388 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -11,88 +11,112 @@ import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/ac import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; +/// @title ChainRegistrar Contract /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -/// @dev ChainRegistrar serves as the main point for chain registration. -/// Contract should be deployed using Proxy. This contract is an addition to the zksync ecosystem -/// and it's not allowed to do any calls to the Bridgehub. +/// @notice This contract is used for proposing and registering new chains in the zkSync ecosystem. +/// @notice It helps chain administrators retrieve all necessary L1 information about their chain. +/// @notice Additionally, it assists zkSync administrators in verifying the correctness of registration transactions. +/// @dev ChainRegistrar is designed for use with a proxy for upgradability. +/// @dev It interacts with the Bridgehub for getting chain registration results. +/// @dev This contract does not make write calls to the Bridgehub itself for security reasons. contract ChainRegistrar is Ownable2StepUpgradeable { using SafeERC20 for IERC20; - /// @notice Address that will be used for deploying l2 contracts + + /// @notice Address that will be used for deploying L2 contracts. + /// @dev During the chain proposal, some base tokens must be transferred to this address. address public l2Deployer; - /// ZKsync Bridgehub + + /// @notice Address of the ZKsync Bridgehub. IBridgehub public bridgehub; - /// Proposal for chain registration + /// @notice Mapping of proposed chains by author and chain ID. + /// @notice Stores chain proposals made by users, where each address can propose a chain with a unique chain ID. mapping(address => mapping(uint256 => ChainConfig)) public proposedChains; - error BaseTokenTransferFailed(); + /// @dev Thrown when trying to register a chain that is already deployed. error ChainIsAlreadyDeployed(); + + /// @dev Thrown when querying information about a chain that is not yet deployed. error ChainIsNotYetDeployed(); + + /// @dev Thrown when the bridge for a chain is not registered. error BridgeIsNotRegistered(); - /// @notice new chain is proposed to register + /// @notice Emitted when a new chain registration proposal is made. + /// @param chainId Unique ID of the proposed chain. + /// @param author Address of the proposer. event NewChainRegistrationProposal(uint256 indexed chainId, address author); - /// @notice L2 Deployer has changed + /// @notice Emitted when the L2 deployer address is changed. + /// @param newDeployer Address of the new L2 deployer. event L2DeployerChanged(address newDeployer); + /// @dev Struct for holding the base token configuration of a chain. struct BaseToken { - /// @param gasPriceMultiplierNominator, used to compare the baseTokenPrice to ether for L1->L2 transactions + /// @notice Gas price multiplier numerator, used to compare the base token price to ether for L1->L2 transactions. uint128 gasPriceMultiplierNominator; - /// @param gasPriceMultiplierDenominator, used to compare the baseTokenPrice to ether for L1->L2 transactions + /// @notice Gas price multiplier denominator, used to compare the base token price to ether for L1->L2 transactions. uint128 gasPriceMultiplierDenominator; - /// @param tokenAddress the base token address used to pay for gas fees + /// @notice Address of the base token used for gas fees. address tokenAddress; - /// @param okenMultiplierSetter The new address to be set as the token multiplier setter. + /// @notice Address responsible for setting the token multiplier. address tokenMultiplierSetter; } + /// @dev Struct for holding the configuration of a proposed chain. // solhint-disable-next-line gas-struct-packing struct ChainConfig { - /// @param Chain id of the new chain should be unique for this bridgehub + /// @notice Unique chain ID. uint256 chainId; - /// @param baseToken of the chain + /// @notice Base token configuration for the chain. BaseToken baseToken; - /// @param Operator for making commit txs. + /// @notice Operator responsible for making commit transactions. address blobOperator; - /// @param Operator for making Prove and Execute transactions + /// @notice Operator responsible for making prove and execute transactions. address operator; - /// @param Governor of the chain. Ownership of the ChainAdmin will be transferred to this address + /// @notice Governor of the chain; will receive ownership of the ChainAdmin contract. address governor; - /// @param pubdataPricingMode How the users will charged for pubdata. + /// @notice Mode for charging users for pubdata. PubdataPricingMode pubdataPricingMode; } + /// @dev Struct for holding the configuration of a fully deployed chain. // solhint-disable-next-line gas-struct-packing struct RegisteredChainConfig { + /// @notice Address of the pending admin for the chain. address pendingChainAdmin; + /// @notice Address of the current admin for the chain. address chainAdmin; + /// @notice Address of the main contract (diamond proxy) for the deployed chain. address diamondProxy; + /// @notice Address of the L2 bridge inside the deployed chain. address l2BridgeAddress; } - // @dev Initialize the contract + /// @notice Initializes the contract with the given parameters. + /// @dev Can only be called once, during contract deployment. + /// @param _bridgehub Address of the ZKsync Bridgehub. + /// @param _l2Deployer Address of the L2 deployer. + /// @param _owner Address of the contract owner. function initialize(address _bridgehub, address _l2Deployer, address _owner) public { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); } - /// @dev Propose a new chain to be registered in zksync ecosystem. - /// ZKsync administration will use this data for registering the chain on bridgehub. - /// The call will fail if the chain already registered. - /// Note: For non eth based chains it requires to either approve equivalent of 1 eth of base token or transfer - /// this token to l2 deployer directly - /// @param _chainId of the new chain should be unique for this bridgehub - /// @param _pubdataPricingMode How the users will charged for pubdata. - /// @param _blobOperator for making commit txs. - /// @param _operator for making Prove and Execute transactions - /// @param _governor Ownership of the ChainAdmin will be transferred to this address - /// @param _baseTokenAddress the base token address used to pay for gas fees - /// @param _tokenMultiplierSetter The new address to be set as the token multiplier setter. - /// @param _gasPriceMultiplierNominator, used to compare the baseTokenPrice to ether for L1->L2 transactions - /// @param _gasPriceMultiplierDenominator, used to compare the baseTokenPrice to ether for L1->L2 transactions + /// @notice Proposes a new chain to be registered in the zkSync ecosystem. + /// @dev The proposal will fail if the chain has already been registered. + /// @dev For non-ETH-based chains, either an equivalent of 1 ETH of the base token must be approved or transferred to the L2 deployer. + /// @param _chainId Unique ID of the proposed chain. + /// @param _pubdataPricingMode Mode for charging users for pubdata. + /// @param _blobOperator Address responsible for commit transactions. + /// @param _operator Address responsible for prove and execute transactions. + /// @param _governor Address to receive ownership of the ChainAdmin contract. + /// @param _baseTokenAddress Address of the base token used for gas fees. + /// @param _tokenMultiplierSetter Address responsible for setting the base token multiplier. + /// @param _gasPriceMultiplierNominator Gas price multiplier numerator for L1->L2 transactions. + /// @param _gasPriceMultiplierDenominator Gas price multiplier denominator for L1->L2 transactions. function proposeChainRegistration( uint256 _chainId, PubdataPricingMode _pubdataPricingMode, @@ -117,11 +141,14 @@ contract ChainRegistrar is Ownable2StepUpgradeable { gasPriceMultiplierDenominator: _gasPriceMultiplierDenominator }) }); + if (bridgehub.stateTransitionManager(config.chainId) != address(0)) { revert ChainIsAlreadyDeployed(); } + proposedChains[msg.sender][_chainId] = config; - // For Deploying L2 contracts on for non ETH based networks, we as bridgehub owners required base token. + + // Handle base token transfer for non-ETH-based networks. if (config.baseToken.tokenAddress != ETH_TOKEN_ADDRESS) { uint256 amount = (1 ether * config.baseToken.gasPriceMultiplierNominator) / config.baseToken.gasPriceMultiplierDenominator; @@ -129,23 +156,27 @@ contract ChainRegistrar is Ownable2StepUpgradeable { IERC20(config.baseToken.tokenAddress).safeTransferFrom(msg.sender, l2Deployer, amount); } } + emit NewChainRegistrationProposal(config.chainId, msg.sender); } - // @dev Change l2 deployer + /// @notice Changes the address of the L2 deployer. + /// @param _newDeployer New address of the L2 deployer. function changeDeployer(address _newDeployer) public onlyOwner { l2Deployer = _newDeployer; emit L2DeployerChanged(l2Deployer); } - // @dev Get data about the chain that has been fully deployed + /// @notice Retrieves the configuration of a registered chain by its ID. + /// @param _chainId ID of the chain. + /// @return The configuration of the registered chain. function getRegisteredChainConfig(uint256 _chainId) public view returns (RegisteredChainConfig memory) { address stm = bridgehub.stateTransitionManager(_chainId); if (stm == address(0)) { revert ChainIsNotYetDeployed(); } - address diamondProxy = IStateTransitionManager(stm).getHyperchain(_chainId); + address diamondProxy = IStateTransitionManager(stm).getHyperchain(_chainId); address pendingChainAdmin = IGetters(diamondProxy).getPendingAdmin(); address chainAdmin = IGetters(diamondProxy).getAdmin(); address l2BridgeAddress = bridgehub.sharedBridge().l2BridgeAddress(_chainId); @@ -159,6 +190,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { diamondProxy: diamondProxy, l2BridgeAddress: l2BridgeAddress }); + return config; } } diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index bcbe7dc82..56c58be11 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -110,7 +110,7 @@ contract ChainRegistrarTest is Test { _blobOperator: makeAddr("blobOperator"), _operator: makeAddr("operator"), _governor: makeAddr("governor"), - _tokenAddress: ETH_TOKEN_ADDRESS, + _baseTokenAddress: ETH_TOKEN_ADDRESS, _tokenMultiplierSetter: makeAddr("setter"), _gasPriceMultiplierNominator: 1, _gasPriceMultiplierDenominator: 1 From 2b54930026cf35de315ff3dc342a2b28ee27003a Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 25 Nov 2024 17:10:21 +0700 Subject: [PATCH 49/54] Fix system contracts Signed-off-by: Danil --- system-contracts/scripts/calculate-hashes.ts | 2 +- system-contracts/scripts/preprocess-bootloader.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system-contracts/scripts/calculate-hashes.ts b/system-contracts/scripts/calculate-hashes.ts index 7ecb66723..654280c37 100644 --- a/system-contracts/scripts/calculate-hashes.ts +++ b/system-contracts/scripts/calculate-hashes.ts @@ -106,7 +106,7 @@ const readBytecode = (details: ContractDetails): string => { try { if (details.bytecodePath.endsWith(".json")) { const jsonFile = fs.readFileSync(absolutePath, "utf8"); - return ethers.utils.hexlify("0x" + JSON.parse(jsonFile).bytecode.object); + return ethers.utils.hexlify(JSON.parse(jsonFile).bytecode.object); } else { return ethers.utils.hexlify(fs.readFileSync(absolutePath).toString(), { allowMissingPrefix: true }); } diff --git a/system-contracts/scripts/preprocess-bootloader.ts b/system-contracts/scripts/preprocess-bootloader.ts index e3dc18aaf..ba4605b70 100644 --- a/system-contracts/scripts/preprocess-bootloader.ts +++ b/system-contracts/scripts/preprocess-bootloader.ts @@ -53,7 +53,7 @@ function getSystemContextCodeHash() { let bytecode; try { const artifact = JSON.parse(fs.readFileSync("zkout/SystemContext.sol/SystemContext.json", { encoding: "utf-8" })); - bytecode = "0x" + artifact.bytecode.object; + bytecode = artifact.bytecode.object; } catch (e) { bytecode = hre.artifacts.readArtifactSync("SystemContext").bytecode; } From 3388f522e2c56cced6db1c4ff3896fb2eb8f0bee Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 25 Nov 2024 17:54:19 +0700 Subject: [PATCH 50/54] Add more tests Signed-off-by: Danil --- .../chain-registrator/ChainRegistrar.t.sol | 111 ++++++++++++++++-- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 56c58be11..5bef25427 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -19,6 +19,7 @@ import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; import {FeeParams} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; import "contracts/dev-contracts/test/DummyHyperchain.sol"; +import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; contract ChainRegistrarTest is Test { DummyBridgehub private bridgeHub; @@ -115,20 +116,116 @@ contract ChainRegistrarTest is Test { _gasPriceMultiplierNominator: 1, _gasPriceMultiplierDenominator: 1 }); - Vm.Log[] memory proposeLogs = vm.getRecordedLogs(); + registerChainAndVerify(author, 1); + } + + function test_CustomBaseToken() public { + address author = makeAddr("author"); + vm.prank(author); + vm.recordLogs(); + TestnetERC20Token token = new TestnetERC20Token("test", "test", 18); + token.mint(author, 100 ether); + vm.prank(author); + token.approve(address(chainRegistrar), 10 ether); + vm.prank(author); + chainRegistrar.proposeChainRegistration({ + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("governor"), + _baseTokenAddress: address(token), + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 10, + _gasPriceMultiplierDenominator: 1 + }); + registerChainAndVerify(author, 1); + } + + function test_PreTransferErc20Token() public { + address author = makeAddr("author"); + vm.startPrank(author); + vm.recordLogs(); + TestnetERC20Token token = new TestnetERC20Token("test", "test", 18); + token.mint(author, 100 ether); + token.transfer(chainRegistrar.l2Deployer(), 10 ether); + chainRegistrar.proposeChainRegistration({ + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("governor"), + _baseTokenAddress: address(token), + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 10, + _gasPriceMultiplierDenominator: 1 + }); + vm.stopPrank(); + registerChainAndVerify(author, 1); + } + + function test_BaseTokenPreTransferIsNotEnough() public { + address author = makeAddr("author"); + vm.startPrank(author); + vm.recordLogs(); + TestnetERC20Token token = new TestnetERC20Token("test", "test", 18); + token.mint(author, 100 ether); + token.transfer(chainRegistrar.l2Deployer(), 1 ether); + vm.expectRevert(bytes("ERC20: insufficient allowance")); + chainRegistrar.proposeChainRegistration({ + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("governor"), + _baseTokenAddress: address(token), + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 10, + _gasPriceMultiplierDenominator: 1 + }); + } + + function test_BaseTokenApproveIsNotEnough() public { + address author = makeAddr("author"); + vm.startPrank(author); + vm.recordLogs(); + TestnetERC20Token token = new TestnetERC20Token("test", "test", 18); + token.mint(author, 100 ether); + token.approve(chainRegistrar.l2Deployer(), 1 ether); + vm.expectRevert(bytes("ERC20: insufficient allowance")); + chainRegistrar.proposeChainRegistration({ + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("governor"), + _baseTokenAddress: address(token), + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 10, + _gasPriceMultiplierDenominator: 1 + }); + } + + function registerChainAndVerify(address author, uint256 chainId) internal { DummyHyperchain hyperchain = new DummyHyperchain(address(bridgeHub), 270); hyperchain.initialize(admin); vm.prank(admin); stm.setHyperchain(1, address(hyperchain)); - bridgeHub.setStateTransitionManager(1, address(stm)); - vm.prank(admin); - sharedBridge.initializeChainGovernance(1, makeAddr("l2bridge")); - vm.recordLogs(); + bridgeHub.setStateTransitionManager(chainId, address(stm)); vm.prank(admin); - ChainRegistrar.RegisteredChainConfig memory registeredConfig = chainRegistrar.getRegisteredChainConfig(1); + sharedBridge.initializeChainGovernance(chainId, makeAddr("l2bridge")); + ChainRegistrar.RegisteredChainConfig memory registeredConfig = chainRegistrar.getRegisteredChainConfig(chainId); + ( + uint256 proposedChainId, + ChainRegistrar.BaseToken memory baseToken, + address blobOperator, + address operator, + address governor, + PubdataPricingMode pubdataPricingMode + ) = chainRegistrar.proposedChains(author, chainId); require(registeredConfig.diamondProxy != address(0)); require(registeredConfig.chainAdmin != address(0)); require(registeredConfig.l2BridgeAddress != address(0)); - require(registeredConfig.pendingChainAdmin != address(0)); + require(proposedChainId == chainId); } } From 81013842408fe95650e125caf52bcbfbcfeb984b Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 25 Nov 2024 12:55:05 +0100 Subject: [PATCH 51/54] Apply suggestions from code review Co-authored-by: Vlad Bochok <41153528+vladbochok@users.noreply.github.com> --- .../contracts/chain-registrar/ChainRegistrar.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index a05a04388..87792c72e 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -14,8 +14,8 @@ import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20. /// @title ChainRegistrar Contract /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -/// @notice This contract is used for proposing and registering new chains in the zkSync ecosystem. -/// @notice It helps chain administrators retrieve all necessary L1 information about their chain. +/// @notice This contract is used as a public registry where anyone can propose new chain registration in ZKsync ecosystem. +/// @notice It also helps chain administrators retrieve all necessary L1 information about their chain. /// @notice Additionally, it assists zkSync administrators in verifying the correctness of registration transactions. /// @dev ChainRegistrar is designed for use with a proxy for upgradability. /// @dev It interacts with the Bridgehub for getting chain registration results. @@ -27,7 +27,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// @dev During the chain proposal, some base tokens must be transferred to this address. address public l2Deployer; - /// @notice Address of the ZKsync Bridgehub. + /// @notice Address of ZKsync Bridgehub. IBridgehub public bridgehub; /// @notice Mapping of proposed chains by author and chain ID. @@ -99,13 +99,13 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// @param _bridgehub Address of the ZKsync Bridgehub. /// @param _l2Deployer Address of the L2 deployer. /// @param _owner Address of the contract owner. - function initialize(address _bridgehub, address _l2Deployer, address _owner) public { + function initialize(address _bridgehub, address _l2Deployer, address _owner) external Initializer { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); } - /// @notice Proposes a new chain to be registered in the zkSync ecosystem. + /// @notice Proposes a new chain to be registered in the ZKsync ecosystem. /// @dev The proposal will fail if the chain has already been registered. /// @dev For non-ETH-based chains, either an equivalent of 1 ETH of the base token must be approved or transferred to the L2 deployer. /// @param _chainId Unique ID of the proposed chain. From f0b38c0e778dfa52d38c7c9a332f38023941391e Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 25 Nov 2024 19:29:54 +0700 Subject: [PATCH 52/54] Fix review Signed-off-by: Danil --- .../chain-registrar/ChainRegistrar.sol | 46 +++++++++++-------- .../chain-registrator/ChainRegistrar.t.sol | 30 ++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 87792c72e..5ce51d936 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -16,7 +16,7 @@ import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20. /// @custom:security-contact security@matterlabs.dev /// @notice This contract is used as a public registry where anyone can propose new chain registration in ZKsync ecosystem. /// @notice It also helps chain administrators retrieve all necessary L1 information about their chain. -/// @notice Additionally, it assists zkSync administrators in verifying the correctness of registration transactions. +/// @notice Additionally, it assists ZKsync ecosystem admin in verifying the correctness of registration transactions. /// @dev ChainRegistrar is designed for use with a proxy for upgradability. /// @dev It interacts with the Bridgehub for getting chain registration results. /// @dev This contract does not make write calls to the Bridgehub itself for security reasons. @@ -34,6 +34,9 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// @notice Stores chain proposals made by users, where each address can propose a chain with a unique chain ID. mapping(address => mapping(uint256 => ChainConfig)) public proposedChains; + /// @dev Thrown when trying to propose a chain that is already proposed. + error ChainIsAlreadyProposed(); + /// @dev Thrown when trying to register a chain that is already deployed. error ChainIsAlreadyDeployed(); @@ -53,44 +56,44 @@ contract ChainRegistrar is Ownable2StepUpgradeable { event L2DeployerChanged(address newDeployer); /// @dev Struct for holding the base token configuration of a chain. + /// @param gasPriceMultiplierNominator Gas price multiplier numerator, used to compare the base token price to ether for L1->L2 transactions. + /// @param gasPriceMultiplierDenominator Gas price multiplier denominator, used to compare the base token price to ether for L1->L2 transactions. + /// @param tokenAddress Address of the base token used for gas fees. + /// @param tokenMultiplierSetter Address responsible for setting the token multiplier. struct BaseToken { - /// @notice Gas price multiplier numerator, used to compare the base token price to ether for L1->L2 transactions. uint128 gasPriceMultiplierNominator; - /// @notice Gas price multiplier denominator, used to compare the base token price to ether for L1->L2 transactions. uint128 gasPriceMultiplierDenominator; - /// @notice Address of the base token used for gas fees. address tokenAddress; - /// @notice Address responsible for setting the token multiplier. address tokenMultiplierSetter; } /// @dev Struct for holding the configuration of a proposed chain. + /// @param chainId Unique chain ID. + /// @param baseToken Base token configuration for the chain. + /// @param blobOperator Operator responsible for making commit transactions. + /// @param operator Operator responsible for making prove and execute transactions. + /// @param governor Governor of the chain; will receive ownership of the ChainAdmin contract. + /// @param pubdataPricingMode Mode for charging users for pubdata. // solhint-disable-next-line gas-struct-packing struct ChainConfig { - /// @notice Unique chain ID. uint256 chainId; - /// @notice Base token configuration for the chain. BaseToken baseToken; - /// @notice Operator responsible for making commit transactions. address blobOperator; - /// @notice Operator responsible for making prove and execute transactions. address operator; - /// @notice Governor of the chain; will receive ownership of the ChainAdmin contract. address governor; - /// @notice Mode for charging users for pubdata. PubdataPricingMode pubdataPricingMode; } /// @dev Struct for holding the configuration of a fully deployed chain. + /// @param pendingChainAdmin Address of the pending admin for the chain. + /// @param chainAdmin Address of the current admin for the chain. + /// @param diamondProxy Address of the main contract (diamond proxy) for the deployed chain. + /// @param l2BridgeAddress Address of the L2 bridge inside the deployed chain. // solhint-disable-next-line gas-struct-packing struct RegisteredChainConfig { - /// @notice Address of the pending admin for the chain. address pendingChainAdmin; - /// @notice Address of the current admin for the chain. address chainAdmin; - /// @notice Address of the main contract (diamond proxy) for the deployed chain. address diamondProxy; - /// @notice Address of the L2 bridge inside the deployed chain. address l2BridgeAddress; } @@ -99,7 +102,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// @param _bridgehub Address of the ZKsync Bridgehub. /// @param _l2Deployer Address of the L2 deployer. /// @param _owner Address of the contract owner. - function initialize(address _bridgehub, address _l2Deployer, address _owner) external Initializer { + function initialize(address _bridgehub, address _l2Deployer, address _owner) external initializer { bridgehub = IBridgehub(_bridgehub); l2Deployer = _l2Deployer; _transferOwnership(_owner); @@ -146,6 +149,13 @@ contract ChainRegistrar is Ownable2StepUpgradeable { revert ChainIsAlreadyDeployed(); } + ChainConfig memory existingConfig = proposedChains[msg.sender][_chainId]; + + // Check if the chain has already been proposed. This prevents situations where the chain author tries to modify parameters after the initial proposal, ensuring that ZKsync administrators are aware of any changes. + if (existingConfig.chainId != 0) { + revert ChainIsAlreadyProposed(); + } + proposedChains[msg.sender][_chainId] = config; // Handle base token transfer for non-ETH-based networks. @@ -162,7 +172,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// @notice Changes the address of the L2 deployer. /// @param _newDeployer New address of the L2 deployer. - function changeDeployer(address _newDeployer) public onlyOwner { + function changeDeployer(address _newDeployer) external onlyOwner { l2Deployer = _newDeployer; emit L2DeployerChanged(l2Deployer); } @@ -170,7 +180,7 @@ contract ChainRegistrar is Ownable2StepUpgradeable { /// @notice Retrieves the configuration of a registered chain by its ID. /// @param _chainId ID of the chain. /// @return The configuration of the registered chain. - function getRegisteredChainConfig(uint256 _chainId) public view returns (RegisteredChainConfig memory) { + function getRegisteredChainConfig(uint256 _chainId) external view returns (RegisteredChainConfig memory) { address stm = bridgehub.stateTransitionManager(_chainId); if (stm == address(0)) { revert ChainIsNotYetDeployed(); diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 5bef25427..a90a1a865 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -101,6 +101,36 @@ contract ChainRegistrarTest is Test { chainRegistrar.initialize(address(bridgeHub), deployer, admin); } + function test_ChainIsAlreadyProposed() public { + address author = makeAddr("author"); + vm.startPrank(author); + chainRegistrar.proposeChainRegistration({ + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("governor"), + _baseTokenAddress: ETH_TOKEN_ADDRESS, + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 1, + _gasPriceMultiplierDenominator: 1 + }); + + vm.expectRevert(ChainRegistrar.ChainIsAlreadyProposed.selector); + chainRegistrar.proposeChainRegistration({ + _chainId: 1, + _pubdataPricingMode: PubdataPricingMode.Validium, + _blobOperator: makeAddr("blobOperator"), + _operator: makeAddr("operator"), + _governor: makeAddr("newGovernor"), + _baseTokenAddress: ETH_TOKEN_ADDRESS, + _tokenMultiplierSetter: makeAddr("setter"), + _gasPriceMultiplierNominator: 1, + _gasPriceMultiplierDenominator: 1 + }); + vm.stopPrank(); + } + function test_SuccessfulProposal() public { address author = makeAddr("author"); vm.prank(author); From 7c31307ecb12709278b99af60bf1ed05f85139b0 Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 25 Nov 2024 21:05:58 +0700 Subject: [PATCH 53/54] Add constructor with Signed-off-by: Danil --- l1-contracts/contracts/chain-registrar/ChainRegistrar.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol index 5ce51d936..1faad4c8b 100644 --- a/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol +++ b/l1-contracts/contracts/chain-registrar/ChainRegistrar.sol @@ -97,6 +97,12 @@ contract ChainRegistrar is Ownable2StepUpgradeable { address l2BridgeAddress; } + /// @dev Contract is expected to be used as proxy implementation. + constructor() { + // Disable initialization to prevent Parity hack. + _disableInitializers(); + } + /// @notice Initializes the contract with the given parameters. /// @dev Can only be called once, during contract deployment. /// @param _bridgehub Address of the ZKsync Bridgehub. From 97a4540af226dacf07c2dced2806140a922efd2c Mon Sep 17 00:00:00 2001 From: Danil Date: Mon, 25 Nov 2024 21:25:01 +0700 Subject: [PATCH 54/54] Fix test Signed-off-by: Danil --- .../concrete/chain-registrator/ChainRegistrar.t.sol | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index a90a1a865..e76823456 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -20,6 +20,7 @@ import {ChainCreationParams} from "contracts/state-transition/IStateTransitionMa import {FeeParams} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; import "contracts/dev-contracts/test/DummyHyperchain.sol"; import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; contract ChainRegistrarTest is Test { DummyBridgehub private bridgeHub; @@ -97,8 +98,13 @@ contract ChainRegistrarTest is Test { vm.stopPrank(); vm.prank(stm.admin()); stm.setChainCreationParams(chainCreationParams); - chainRegistrar = new ChainRegistrar(); - chainRegistrar.initialize(address(bridgeHub), deployer, admin); + address chainRegistrarImplementation = address(new ChainRegistrar()); + TransparentUpgradeableProxy chainRegistrarProxy = new TransparentUpgradeableProxy( + chainRegistrarImplementation, + admin, + abi.encodeCall(ChainRegistrar.initialize, (address(bridgeHub), deployer, admin)) + ); + chainRegistrar = ChainRegistrar(address(chainRegistrarProxy)); } function test_ChainIsAlreadyProposed() public {