From ec8e9daec4f4228d04f76ac21d81c962369a6a44 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 10 Sep 2024 15:10:39 +0200 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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(); }