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 fae9cc907..5ee0fb43e 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 @@ -1,3 +1,4 @@ +legacy_bridge = false chain_id = 215 era_chain_id = 270 l1_shared_bridge = "0x2ae37d8130b82c7e79b3863a39027178e073eedb" @@ -5,3 +6,7 @@ bridgehub = "0xea785a9c91a07ed69b83eb165f4ce2c30ecb4c0b" governance = "0x6a08d69675af7755569a1a25ef37e795493473a1" erc20_bridge = "0x84fbda16bd5f2d66d7fbaec5e8d816e7b7014595" consensus_registry_owner = "0xD64e136566a9E04eb05B30184fF577F52682D182" +deploy_shared_bridge = false +deploy_consensus_registry = false +deploy_multicall3 = false +deploy_force_deploy_upgrader = false diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 4578f1717..167debfc0 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -14,7 +14,14 @@ contract DeployL2Script is Script { using stdToml for string; Config internal config; - ContractsBytecodes internal contracts; + ContractsBytecodes internal bytecodes; + + // Contract deployment specification, needed to verify the contract. + struct ContractSpec { + address addr; + string name; + bytes constructorArgs; + } // solhint-disable-next-line gas-struct-packing struct Config { @@ -27,142 +34,91 @@ contract DeployL2Script is Script { address consensusRegistryOwner; uint256 chainId; uint256 eraChainId; - address l2SharedBridgeImplementation; - address l2SharedBridgeProxy; - address consensusRegistryImplementation; - address consensusRegistryProxy; - address multicall3; - address forceDeployUpgraderAddress; + bool legacyBridge; + bool deploySharedBridge; + bool deployConsensusRegistry; + bool deployMulticall3; + bool deployForceDeployUpgrader; + ContractSpec l2SharedBridgeImplementation; + ContractSpec l2SharedBridgeProxy; + ContractSpec l2ConsensusRegistryImplementation; + ContractSpec l2ConsensusRegistryProxy; + ContractSpec l2Multicall3; + ContractSpec l2ForceDeployUpgrader; } struct ContractsBytecodes { - bytes l2StandardErc20FactoryBytecode; + bytes upgradeableBeacon; bytes beaconProxy; - bytes l2StandardErc20Bytecode; - bytes l2SharedBridgeBytecode; - bytes l2SharedBridgeProxyBytecode; - bytes consensusRegistryBytecode; - bytes consensusRegistryProxyBytecode; - bytes multicall3Bytecode; + bytes l2StandardErc20; + bytes l2SharedBridge; + bytes devL2SharedBridge; + bytes transparentUpgradeableProxy; + bytes consensusRegistry; + bytes multicall3; bytes forceDeployUpgrader; } - function run() public { - deploy(false); - } - - function runWithLegacyBridge() public { - deploy(true); - } - - function deploy(bool legacyBridge) public { - initializeConfig(); - loadContracts(legacyBridge); - - deployFactoryDeps(); - deploySharedBridge(); - 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(legacyBridge); - - deployFactoryDeps(); - deploySharedBridge(); - deploySharedBridgeProxy(legacyBridge); - initializeChain(); + function deploy() public { + loadConfig(); + loadContracts(); - saveOutput(); - } - - function runDefaultUpgrader() public { - initializeConfig(); - loadContracts(false); - - deployForceDeployer(); - - saveOutput(); - } - - function runDeployConsensusRegistry() public { - initializeConfig(); - loadContracts(false); - - deployConsensusRegistry(); - deployConsensusRegistryProxy(); + if (config.deploySharedBridge) { + deploySharedBridge(); + } - saveOutput(); - } + if (config.deployConsensusRegistry) { + deployConsensusRegistry(); + } - function runDeployMulticall3() public { - initializeConfig(); - loadContracts(false); + if (config.deployMulticall3) { + config.l2Multicall3 = deployThroughL1("Multicall3", bytecodes.multicall3, "", new bytes[](0)); + } - deployMulticall3(); + if (config.deployForceDeployUpgrader) { + config.l2ForceDeployUpgrader = deployThroughL1( + "ForceDeployUpgrader", + bytecodes.forceDeployUpgrader, + "", + new bytes[](0) + ); + } saveOutput(); } - function loadContracts(bool legacyBridge) internal { + function loadContracts() internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat - contracts.l2StandardErc20FactoryBytecode = Utils.readFoundryBytecode( + bytecodes.upgradeableBeacon = Utils.readFoundryBytecode( "/../l2-contracts/zkout/UpgradeableBeacon.sol/UpgradeableBeacon.json" ); - contracts.beaconProxy = Utils.readFoundryBytecode("/../l2-contracts/zkout/BeaconProxy.sol/BeaconProxy.json"); - contracts.l2StandardErc20Bytecode = Utils.readFoundryBytecode( + bytecodes.beaconProxy = Utils.readFoundryBytecode("/../l2-contracts/zkout/BeaconProxy.sol/BeaconProxy.json"); + bytecodes.l2StandardErc20 = Utils.readFoundryBytecode( "/../l2-contracts/zkout/L2StandardERC20.sol/L2StandardERC20.json" ); - - if (legacyBridge) { - contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/DevL2SharedBridge.sol/DevL2SharedBridge.json" - ); - } else { - contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/L2SharedBridge.sol/L2SharedBridge.json" - ); - } - - contracts.l2SharedBridgeProxyBytecode = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" + bytecodes.devL2SharedBridge = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/DevL2SharedBridge.sol/DevL2SharedBridge.json" ); - - contracts.consensusRegistryBytecode = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/ConsensusRegistry.sol/ConsensusRegistry.json" + bytecodes.l2SharedBridge = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2SharedBridge.sol/L2SharedBridge.json" ); - contracts.consensusRegistryProxyBytecode = Utils.readFoundryBytecode( + bytecodes.transparentUpgradeableProxy = Utils.readFoundryBytecode( "/../l2-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); - - contracts.multicall3Bytecode = Utils.readFoundryBytecode( - "/../l2-contracts/zkout/Multicall3.sol/Multicall3.json" + bytecodes.consensusRegistry = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/ConsensusRegistry.sol/ConsensusRegistry.json" ); - - contracts.forceDeployUpgrader = Utils.readFoundryBytecode( + bytecodes.multicall3 = Utils.readFoundryBytecode("/../l2-contracts/zkout/Multicall3.sol/Multicall3.json"); + bytecodes.forceDeployUpgrader = Utils.readFoundryBytecode( "/../l2-contracts/zkout/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" ); } - function initializeConfig() internal { + function loadConfig() internal { string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-config/config-deploy-l2-contracts.toml"); string memory toml = vm.readFile(path); + config.legacyBridge = toml.readBool("$.legacy_bridge"); config.bridgehubAddress = toml.readAddress("$.bridgehub"); config.governance = toml.readAddress("$.governance"); config.l1SharedBridgeProxy = toml.readAddress("$.l1_shared_bridge"); @@ -170,37 +126,68 @@ contract DeployL2Script is Script { config.consensusRegistryOwner = toml.readAddress("$.consensus_registry_owner"); config.chainId = toml.readUint("$.chain_id"); config.eraChainId = toml.readUint("$.era_chain_id"); + config.deploySharedBridge = toml.readBool("$.deploy_shared_bridge"); + config.deployConsensusRegistry = toml.readBool("$.deploy_consensus_registry"); + config.deployMulticall3 = toml.readBool("$.deploy_multicall3"); + config.deployForceDeployUpgrader = toml.readBool("$.deploy_force_deploy_upgrader"); + } + + function serializeContract(ContractSpec memory spec) internal returns (string memory json) { + vm.serializeAddress("contract_spec", "address", spec.addr); + vm.serializeString("contract_spec", "name", spec.name); + return vm.serializeBytes("contract_spec", "constructor_args", spec.constructorArgs); } 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 toml = "{}"; + if (config.l2SharedBridgeImplementation.addr != address(0)) { + toml = vm.serializeString( + "root", + "l2_shared_bridge_implementation", + serializeContract(config.l2SharedBridgeImplementation) + ); + } + if (config.l2SharedBridgeProxy.addr != address(0)) { + toml = vm.serializeString("root", "l2_shared_bridge_proxy", serializeContract(config.l2SharedBridgeProxy)); + } + if (config.l2ConsensusRegistryImplementation.addr != address(0)) { + toml = vm.serializeString( + "root", + "l2_consensus_registry_implementation", + serializeContract(config.l2ConsensusRegistryImplementation) + ); + } + if (config.l2ConsensusRegistryProxy.addr != address(0)) { + toml = vm.serializeString( + "root", + "l2_consensus_registry_proxy", + serializeContract(config.l2ConsensusRegistryProxy) + ); + } + if (config.l2Multicall3.addr != address(0)) { + toml = vm.serializeString("root", "l2_multicall3", serializeContract(config.l2Multicall3)); + } + if (config.l2ForceDeployUpgrader.addr != address(0)) { + toml = vm.serializeString( + "root", + "l2_force_deploy_upgrader", + serializeContract(config.l2ForceDeployUpgrader) + ); + } string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-deploy-l2-contracts.toml"); vm.writeToml(toml, path); } - function deployFactoryDeps() internal { - bytes[] memory factoryDeps = new bytes[](3); - factoryDeps[0] = contracts.l2StandardErc20FactoryBytecode; - factoryDeps[1] = contracts.l2StandardErc20Bytecode; - factoryDeps[2] = contracts.beaconProxy; - Utils.publishBytecodes(factoryDeps, config.chainId, config.bridgehubAddress, config.l1SharedBridgeProxy); - } - - function deploySharedBridge() internal { - bytes[] memory factoryDeps = new bytes[](1); - factoryDeps[0] = contracts.beaconProxy; - - bytes memory constructorData = abi.encode(config.eraChainId); - - config.l2SharedBridgeImplementation = Utils.deployThroughL1({ - bytecode: contracts.l2SharedBridgeBytecode, - constructorargs: constructorData, + function deployThroughL1( + string memory name, + bytes memory bytecode, + bytes memory constructorArgs, + bytes[] memory factoryDeps + ) internal returns (ContractSpec memory) { + address addr = Utils.deployThroughL1({ + bytecode: bytecode, + constructorargs: constructorArgs, create2salt: "", l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, factoryDeps: factoryDeps, @@ -208,132 +195,99 @@ contract DeployL2Script is Script { bridgehubAddress: config.bridgehubAddress, l1SharedBridgeProxy: config.l1SharedBridgeProxy }); + return ContractSpec({addr: addr, name: name, constructorArgs: constructorArgs}); } - function deployForceDeployer() internal { - bytes[] memory factoryDeps = new bytes[](0); - config.forceDeployUpgraderAddress = Utils.deployThroughL1({ - bytecode: contracts.forceDeployUpgrader, - constructorargs: "", - create2salt: "", - l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, - factoryDeps: factoryDeps, - chainId: config.chainId, - bridgehubAddress: config.bridgehubAddress, - l1SharedBridgeProxy: config.l1SharedBridgeProxy - }); + function deployTransparentUpgradeableProxy( + ContractSpec memory target, + address admin, + bytes memory data + ) internal returns (ContractSpec memory) { + assert(target.addr != address(0)); + assert(admin != address(0)); + bytes memory constructorArgs = abi.encode(target.addr, admin, data); + return + deployThroughL1( + "TransparentUpgradeableProxy", + bytecodes.transparentUpgradeableProxy, + constructorArgs, + new bytes[](0) + ); } - function deploySharedBridgeProxy(bool legacyBridge) internal { - address l2GovernorAddress = AddressAliasHelper.applyL1ToL2Alias(config.governance); - bytes32 l2StandardErc20BytecodeHash = L2ContractHelper.hashL2Bytecode(contracts.beaconProxy); + function deploySharedBridge() internal { + // Publish relevant factory dependencies. + bytes[] memory factoryDeps = new bytes[](3); + factoryDeps[0] = bytecodes.upgradeableBeacon; + factoryDeps[1] = bytecodes.l2StandardErc20; + factoryDeps[2] = bytecodes.beaconProxy; + Utils.publishBytecodes(factoryDeps, config.chainId, config.bridgehubAddress, config.l1SharedBridgeProxy); + // Deploy the shared bridge contract. + factoryDeps = new bytes[](1); + factoryDeps[0] = bytecodes.beaconProxy; + bytes memory constructorArgs = abi.encode(config.eraChainId); string memory functionSignature; - - if (legacyBridge) { + if (config.legacyBridge) { + config.l2SharedBridgeImplementation = deployThroughL1( + "DevL2SharedBridge", + bytecodes.devL2SharedBridge, + constructorArgs, + factoryDeps + ); functionSignature = "initializeDevBridge(address,address,bytes32,address)"; } else { + config.l2SharedBridgeImplementation = deployThroughL1( + "L2SharedBridge", + bytecodes.l2SharedBridge, + constructorArgs, + factoryDeps + ); functionSignature = "initialize(address,address,bytes32,address)"; } - // solhint-disable-next-line func-named-parameters - bytes memory proxyInitializationParams = abi.encodeWithSignature( - functionSignature, - config.l1SharedBridgeProxy, - config.erc20BridgeProxy, - l2StandardErc20BytecodeHash, - l2GovernorAddress - ); - bytes memory l2SharedBridgeProxyConstructorData = abi.encode( + // Deploy proxy to the shared bridge. + address l2GovernorAddress = AddressAliasHelper.applyL1ToL2Alias(config.governance); + config.l2SharedBridgeProxy = deployTransparentUpgradeableProxy( config.l2SharedBridgeImplementation, l2GovernorAddress, - proxyInitializationParams + abi.encodeWithSignature( + functionSignature, + config.l1SharedBridgeProxy, + config.erc20BridgeProxy, + L2ContractHelper.hashL2Bytecode(bytecodes.beaconProxy), + l2GovernorAddress + ) ); - config.l2SharedBridgeProxy = Utils.deployThroughL1({ - bytecode: contracts.l2SharedBridgeProxyBytecode, - constructorargs: l2SharedBridgeProxyConstructorData, - create2salt: "", - l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, - factoryDeps: new bytes[](0), - chainId: config.chainId, - bridgehubAddress: config.bridgehubAddress, - l1SharedBridgeProxy: config.l1SharedBridgeProxy - }); - } - - // 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 - }); + // Initialize the chain. + L1SharedBridge bridge = L1SharedBridge(config.l1SharedBridgeProxy); + if (bridge.l2BridgeAddress(config.chainId) == address(0)) { + Utils.chainAdminMulticall({ + _chainAdmin: bridge.admin(), + _target: config.l1SharedBridgeProxy, + _data: abi.encodeCall( + bridge.initializeChainGovernance, + (config.chainId, config.l2SharedBridgeProxy.addr) + ), + _value: 0 + }); + } } // 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 + function deployConsensusRegistry() internal { + config.l2ConsensusRegistryImplementation = deployThroughL1( + "ConsensusRegistry", + bytecodes.consensusRegistry, + "", + new bytes[](0) ); - - bytes memory consensusRegistryProxyConstructorData = abi.encode( - config.consensusRegistryImplementation, // _logic - l2GovernorAddress, // admin_ - proxyInitializationParams // _data + config.l2ConsensusRegistryProxy = deployTransparentUpgradeableProxy( + config.l2ConsensusRegistryImplementation, + AddressAliasHelper.applyL1ToL2Alias(config.governance), + abi.encodeWithSignature("initialize(address)", config.consensusRegistryOwner) ); - - 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.chainAdminMulticall({ - _chainAdmin: bridge.admin(), - _target: config.l1SharedBridgeProxy, - _data: abi.encodeCall(bridge.initializeChainGovernance, (config.chainId, config.l2SharedBridgeProxy)), - _value: 0 - }); } } diff --git a/l2-contracts/foundry.toml b/l2-contracts/foundry.toml index deb178a12..66c1e9610 100644 --- a/l2-contracts/foundry.toml +++ b/l2-contracts/foundry.toml @@ -11,3 +11,4 @@ remappings = [ [profile.default.zksync] zksolc = "1.5.0" +enable_eravm_extensions = true diff --git a/yarn.lock b/yarn.lock index 66cd67b1a..6ab96b427 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7931,10 +7931,3 @@ 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"