From c77880af4a464d89cfc79b7ea91a094c64868563 Mon Sep 17 00:00:00 2001 From: Yberjon Date: Tue, 9 Jul 2024 14:20:58 +0200 Subject: [PATCH] Deploy Paymaster Test --- l1-contracts/deploy-scripts/DeployL1.s.sol | 551 +------------ .../deploy-scripts/DeployPaymaster.s.sol | 8 +- .../deploy-scripts/RegisterHyperchain.s.sol | 23 +- l1-contracts/deploy-scripts/Utils.sol | 14 +- l1-contracts/deploy-scripts/_DeployL1.s.sol | 734 ++++++++++++++++++ l1-contracts/foundry.toml | 6 +- .../test/foundry/unit/DeployPaymaster.t.sol | 41 +- 7 files changed, 836 insertions(+), 541 deletions(-) create mode 100644 l1-contracts/deploy-scripts/_DeployL1.s.sol diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 42921b3cb..4ef54f119 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -32,101 +32,11 @@ import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-de import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; -import {AddressHasNoCode} from "./ZkSyncScriptErrors.sol"; +import {_DeployL1Script} from "./_DeployL1.s.sol"; -contract DeployL1Script is Script { +contract DeployL1Script is _DeployL1Script { using stdToml for string; - address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; - address internal constant DETERMINISTIC_CREATE2_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; - - // solhint-disable-next-line gas-struct-packing - struct DeployedAddresses { - BridgehubDeployedAddresses bridgehub; - StateTransitionDeployedAddresses stateTransition; - BridgesDeployedAddresses bridges; - address transparentProxyAdmin; - address governance; - address blobVersionedHashRetriever; - address validatorTimelock; - address create2Factory; - } - - // solhint-disable-next-line gas-struct-packing - struct BridgehubDeployedAddresses { - address bridgehubImplementation; - address bridgehubProxy; - } - - // solhint-disable-next-line gas-struct-packing - struct StateTransitionDeployedAddresses { - address stateTransitionProxy; - address stateTransitionImplementation; - address verifier; - address adminFacet; - address mailboxFacet; - address executorFacet; - address gettersFacet; - address diamondInit; - address genesisUpgrade; - address defaultUpgrade; - address diamondProxy; - } - - // solhint-disable-next-line gas-struct-packing - struct BridgesDeployedAddresses { - address erc20BridgeImplementation; - address erc20BridgeProxy; - address sharedBridgeImplementation; - address sharedBridgeProxy; - } - - // solhint-disable-next-line gas-struct-packing - struct Config { - uint256 l1ChainId; - uint256 eraChainId; - address deployerAddress; - address ownerAddress; - bool testnetVerifier; - ContractsConfig contracts; - TokensConfig tokens; - } - - // solhint-disable-next-line gas-struct-packing - struct ContractsConfig { - bytes32 create2FactorySalt; - address create2FactoryAddr; - address multicall3Addr; - uint256 validatorTimelockExecutionDelay; - bytes32 genesisRoot; - uint256 genesisRollupLeafIndex; - bytes32 genesisBatchCommitment; - uint256 latestProtocolVersion; - bytes32 recursionNodeLevelVkHash; - bytes32 recursionLeafLevelVkHash; - bytes32 recursionCircuitsSetVksHash; - uint256 priorityTxMaxGasLimit; - PubdataPricingMode diamondInitPubdataPricingMode; - uint256 diamondInitBatchOverheadL1Gas; - uint256 diamondInitMaxPubdataPerBatch; - uint256 diamondInitMaxL2GasPerBatch; - uint256 diamondInitPriorityTxMaxPubdata; - uint256 diamondInitMinimalL2GasPrice; - address governanceSecurityCouncilAddress; - uint256 governanceMinDelay; - uint256 maxNumberOfChains; - bytes diamondCutData; - bytes32 bootloaderHash; - bytes32 defaultAAHash; - } - - struct TokensConfig { - address tokenWethAddress; - } - - Config internal config; - DeployedAddresses internal addresses; - function run() public { console.log("Deploying L1 contracts"); @@ -161,145 +71,40 @@ contract DeployL1Script is Script { } function initializeConfig() internal { - string memory root = vm.projectRoot(); - string memory path = string.concat(root, "/script-config/config-deploy-l1.toml"); - string memory toml = vm.readFile(path); - - config.l1ChainId = block.chainid; - config.deployerAddress = msg.sender; - - // Config file must be parsed key by key, otherwise values returned - // are parsed alfabetically and not by key. - // https://book.getfoundry.sh/cheatcodes/parse-toml - config.eraChainId = toml.readUint("$.era_chain_id"); - config.ownerAddress = toml.readAddress("$.owner_address"); - config.testnetVerifier = toml.readBool("$.testnet_verifier"); - - config.contracts.governanceSecurityCouncilAddress = toml.readAddress( - "$.contracts.governance_security_council_address" - ); - config.contracts.governanceMinDelay = toml.readUint("$.contracts.governance_min_delay"); - config.contracts.maxNumberOfChains = toml.readUint("$.contracts.max_number_of_chains"); - config.contracts.create2FactorySalt = toml.readBytes32("$.contracts.create2_factory_salt"); - if (vm.keyExistsToml(toml, "$.contracts.create2_factory_addr")) { - config.contracts.create2FactoryAddr = toml.readAddress("$.contracts.create2_factory_addr"); - } - config.contracts.validatorTimelockExecutionDelay = toml.readUint( - "$.contracts.validator_timelock_execution_delay" - ); - config.contracts.genesisRoot = toml.readBytes32("$.contracts.genesis_root"); - config.contracts.genesisRollupLeafIndex = toml.readUint("$.contracts.genesis_rollup_leaf_index"); - config.contracts.genesisBatchCommitment = toml.readBytes32("$.contracts.genesis_batch_commitment"); - config.contracts.latestProtocolVersion = toml.readUint("$.contracts.latest_protocol_version"); - config.contracts.recursionNodeLevelVkHash = toml.readBytes32("$.contracts.recursion_node_level_vk_hash"); - config.contracts.recursionLeafLevelVkHash = toml.readBytes32("$.contracts.recursion_leaf_level_vk_hash"); - config.contracts.recursionCircuitsSetVksHash = toml.readBytes32("$.contracts.recursion_circuits_set_vks_hash"); - config.contracts.priorityTxMaxGasLimit = toml.readUint("$.contracts.priority_tx_max_gas_limit"); - config.contracts.diamondInitPubdataPricingMode = PubdataPricingMode( - toml.readUint("$.contracts.diamond_init_pubdata_pricing_mode") - ); - config.contracts.diamondInitBatchOverheadL1Gas = toml.readUint( - "$.contracts.diamond_init_batch_overhead_l1_gas" - ); - config.contracts.diamondInitMaxPubdataPerBatch = toml.readUint( - "$.contracts.diamond_init_max_pubdata_per_batch" - ); - config.contracts.diamondInitMaxL2GasPerBatch = toml.readUint("$.contracts.diamond_init_max_l2_gas_per_batch"); - config.contracts.diamondInitPriorityTxMaxPubdata = toml.readUint( - "$.contracts.diamond_init_priority_tx_max_pubdata" - ); - config.contracts.diamondInitMinimalL2GasPrice = toml.readUint("$.contracts.diamond_init_minimal_l2_gas_price"); - config.contracts.defaultAAHash = toml.readBytes32("$.contracts.default_aa_hash"); - config.contracts.bootloaderHash = toml.readBytes32("$.contracts.bootloader_hash"); - - config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address"); + _initializeConfig(); } function instantiateCreate2Factory() internal { - address contractAddress; - - bool isDeterministicDeployed = DETERMINISTIC_CREATE2_ADDRESS.code.length > 0; - bool isConfigured = config.contracts.create2FactoryAddr != address(0); - - if (isConfigured) { - if (config.contracts.create2FactoryAddr.code.length == 0) { - revert AddressHasNoCode(config.contracts.create2FactoryAddr); - } - contractAddress = config.contracts.create2FactoryAddr; - console.log("Using configured Create2Factory address:", contractAddress); - } else if (isDeterministicDeployed) { - contractAddress = DETERMINISTIC_CREATE2_ADDRESS; - console.log("Using deterministic Create2Factory address:", contractAddress); - } else { - contractAddress = Utils.deployCreate2Factory(); - console.log("Create2Factory deployed at:", contractAddress); - } - - addresses.create2Factory = contractAddress; + _instantiateCreate2Factory(); } function deployIfNeededMulticall3() internal { // Multicall3 is already deployed on public networks - if (MULTICALL3_ADDRESS.code.length == 0) { - address contractAddress = deployViaCreate2(type(Multicall3).creationCode); - console.log("Multicall3 deployed at:", contractAddress); - config.contracts.multicall3Addr = contractAddress; - } else { - config.contracts.multicall3Addr = MULTICALL3_ADDRESS; - } + _deployIfNeededMulticall3(); } function deployVerifier() internal { - bytes memory code; - if (config.testnetVerifier) { - code = type(TestnetVerifier).creationCode; - } else { - code = type(Verifier).creationCode; - } - address contractAddress = deployViaCreate2(code); - console.log("Verifier deployed at:", contractAddress); - addresses.stateTransition.verifier = contractAddress; + _deployVerifier(); } function deployDefaultUpgrade() internal { - address contractAddress = deployViaCreate2(type(DefaultUpgrade).creationCode); - console.log("DefaultUpgrade deployed at:", contractAddress); - addresses.stateTransition.defaultUpgrade = contractAddress; + _deployDefaultUpgrade(); } function deployGenesisUpgrade() internal { - address contractAddress = deployViaCreate2(type(GenesisUpgrade).creationCode); - console.log("GenesisUpgrade deployed at:", contractAddress); - addresses.stateTransition.genesisUpgrade = contractAddress; + _deployGenesisUpgrade(); } function deployValidatorTimelock() internal { - uint32 executionDelay = uint32(config.contracts.validatorTimelockExecutionDelay); - bytes memory bytecode = abi.encodePacked( - type(ValidatorTimelock).creationCode, - abi.encode(config.deployerAddress, executionDelay, config.eraChainId) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("ValidatorTimelock deployed at:", contractAddress); - addresses.validatorTimelock = contractAddress; + _deployValidatorTimelock(); } function deployGovernance() internal { - bytes memory bytecode = abi.encodePacked( - type(Governance).creationCode, - abi.encode( - config.ownerAddress, - config.contracts.governanceSecurityCouncilAddress, - config.contracts.governanceMinDelay - ) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("Governance deployed at:", contractAddress); - addresses.governance = contractAddress; + _deployGovernance(); } function deployTransparentProxyAdmin() internal { - vm.startBroadcast(); + vm.startBroadcast(msg.sender); ProxyAdmin proxyAdmin = new ProxyAdmin(); proxyAdmin.transferOwnership(addresses.governance); vm.stopBroadcast(); @@ -308,29 +113,12 @@ contract DeployL1Script is Script { } function deployBridgehubContract() internal { - address bridgehubImplementation = deployViaCreate2(type(Bridgehub).creationCode); - console.log("Bridgehub Implementation deployed at:", bridgehubImplementation); - addresses.bridgehub.bridgehubImplementation = bridgehubImplementation; - - bytes memory bytecode = abi.encodePacked( - type(TransparentUpgradeableProxy).creationCode, - abi.encode( - bridgehubImplementation, - addresses.transparentProxyAdmin, - abi.encodeCall(Bridgehub.initialize, (config.deployerAddress)) - ) - ); - address bridgehubProxy = deployViaCreate2(bytecode); - console.log("Bridgehub Proxy deployed at:", bridgehubProxy); - addresses.bridgehub.bridgehubProxy = bridgehubProxy; + _deployBridgehubContract(); } function deployBlobVersionedHashRetriever() internal { // solc contracts/state-transition/utils/blobVersionedHashRetriever.yul --strict-assembly --bin - bytes memory bytecode = hex"600b600b5f39600b5ff3fe5f358049805f5260205ff3"; - address contractAddress = deployViaCreate2(bytecode); - console.log("BlobVersionedHashRetriever deployed at:", contractAddress); - addresses.blobVersionedHashRetriever = contractAddress; + _deployBlobVersionedHashRetriever(); } function deployStateTransitionManagerContract() internal { @@ -341,139 +129,27 @@ contract DeployL1Script is Script { } function deployStateTransitionDiamondFacets() internal { - address executorFacet = deployViaCreate2(type(ExecutorFacet).creationCode); - console.log("ExecutorFacet deployed at:", executorFacet); - addresses.stateTransition.executorFacet = executorFacet; - - address adminFacet = deployViaCreate2(type(AdminFacet).creationCode); - console.log("AdminFacet deployed at:", adminFacet); - addresses.stateTransition.adminFacet = adminFacet; - - address mailboxFacet = deployViaCreate2( - abi.encodePacked(type(MailboxFacet).creationCode, abi.encode(config.eraChainId)) - ); - console.log("MailboxFacet deployed at:", mailboxFacet); - addresses.stateTransition.mailboxFacet = mailboxFacet; - - address gettersFacet = deployViaCreate2(type(GettersFacet).creationCode); - console.log("GettersFacet deployed at:", gettersFacet); - addresses.stateTransition.gettersFacet = gettersFacet; - - address diamondInit = deployViaCreate2(type(DiamondInit).creationCode); - console.log("DiamondInit deployed at:", diamondInit); - addresses.stateTransition.diamondInit = diamondInit; + _deployStateTransitionDiamondFacets(); } function deployStateTransitionManagerImplementation() internal { - bytes memory bytecode = abi.encodePacked( - type(StateTransitionManager).creationCode, - abi.encode(addresses.bridgehub.bridgehubProxy), - abi.encode(config.contracts.maxNumberOfChains) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("StateTransitionManagerImplementation deployed at:", contractAddress); - addresses.stateTransition.stateTransitionImplementation = contractAddress; + _deployStateTransitionManagerImplementation(); } function deployStateTransitionManagerProxy() internal { - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](4); - facetCuts[0] = Diamond.FacetCut({ - facet: addresses.stateTransition.adminFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) - }); - facetCuts[1] = Diamond.FacetCut({ - facet: addresses.stateTransition.gettersFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(addresses.stateTransition.gettersFacet.code) - }); - facetCuts[2] = Diamond.FacetCut({ - facet: addresses.stateTransition.mailboxFacet, - action: Diamond.Action.Add, - isFreezable: true, - selectors: Utils.getAllSelectors(addresses.stateTransition.mailboxFacet.code) - }); - facetCuts[3] = Diamond.FacetCut({ - facet: addresses.stateTransition.executorFacet, - action: Diamond.Action.Add, - isFreezable: true, - selectors: Utils.getAllSelectors(addresses.stateTransition.executorFacet.code) - }); - - VerifierParams memory verifierParams = VerifierParams({ - recursionNodeLevelVkHash: config.contracts.recursionNodeLevelVkHash, - recursionLeafLevelVkHash: config.contracts.recursionLeafLevelVkHash, - recursionCircuitsSetVksHash: config.contracts.recursionCircuitsSetVksHash - }); - - FeeParams memory feeParams = FeeParams({ - pubdataPricingMode: config.contracts.diamondInitPubdataPricingMode, - batchOverheadL1Gas: uint32(config.contracts.diamondInitBatchOverheadL1Gas), - maxPubdataPerBatch: uint32(config.contracts.diamondInitMaxPubdataPerBatch), - maxL2GasPerBatch: uint32(config.contracts.diamondInitMaxL2GasPerBatch), - priorityTxMaxPubdata: uint32(config.contracts.diamondInitPriorityTxMaxPubdata), - minimalL2GasPrice: uint64(config.contracts.diamondInitMinimalL2GasPrice) - }); - - DiamondInitializeDataNewChain memory initializeData = DiamondInitializeDataNewChain({ - verifier: IVerifier(addresses.stateTransition.verifier), - verifierParams: verifierParams, - l2BootloaderBytecodeHash: config.contracts.bootloaderHash, - l2DefaultAccountBytecodeHash: config.contracts.defaultAAHash, - priorityTxMaxGasLimit: config.contracts.priorityTxMaxGasLimit, - feeParams: feeParams, - blobVersionedHashRetriever: addresses.blobVersionedHashRetriever - }); - - Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ - facetCuts: facetCuts, - initAddress: addresses.stateTransition.diamondInit, - initCalldata: abi.encode(initializeData) - }); - - config.contracts.diamondCutData = abi.encode(diamondCut); - - ChainCreationParams memory chainCreationParams = ChainCreationParams({ - genesisUpgrade: addresses.stateTransition.genesisUpgrade, - genesisBatchHash: config.contracts.genesisRoot, - genesisIndexRepeatedStorageChanges: uint64(config.contracts.genesisRollupLeafIndex), - genesisBatchCommitment: config.contracts.genesisBatchCommitment, - diamondCut: diamondCut - }); - - StateTransitionManagerInitializeData memory diamondInitData = StateTransitionManagerInitializeData({ - owner: config.ownerAddress, - validatorTimelock: addresses.validatorTimelock, - chainCreationParams: chainCreationParams, - protocolVersion: config.contracts.latestProtocolVersion - }); - - address contractAddress = deployViaCreate2( - abi.encodePacked( - type(TransparentUpgradeableProxy).creationCode, - abi.encode( - addresses.stateTransition.stateTransitionImplementation, - addresses.transparentProxyAdmin, - abi.encodeCall(StateTransitionManager.initialize, (diamondInitData)) - ) - ) - ); - console.log("StateTransitionManagerProxy deployed at:", contractAddress); - addresses.stateTransition.stateTransitionProxy = contractAddress; + _deployStateTransitionManagerProxy(); } function registerStateTransitionManager() internal { Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); - vm.broadcast(); + vm.broadcast(msg.sender); bridgehub.addStateTransitionManager(addresses.stateTransition.stateTransitionProxy); console.log("StateTransitionManager registered"); } function setStateTransitionManagerInValidatorTimelock() internal { ValidatorTimelock validatorTimelock = ValidatorTimelock(addresses.validatorTimelock); - vm.broadcast(); + vm.broadcast(msg.sender); validatorTimelock.setStateTransitionManager( IStateTransitionManager(addresses.stateTransition.stateTransitionProxy) ); @@ -481,25 +157,7 @@ contract DeployL1Script is Script { } function deployDiamondProxy() internal { - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](1); - facetCuts[0] = Diamond.FacetCut({ - facet: addresses.stateTransition.adminFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) - }); - Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ - facetCuts: facetCuts, - initAddress: address(0), - initCalldata: "" - }); - bytes memory bytecode = abi.encodePacked( - type(DiamondProxy).creationCode, - abi.encode(config.l1ChainId, diamondCut) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("DiamondProxy deployed at:", contractAddress); - addresses.stateTransition.diamondProxy = contractAddress; + _deployDiamondProxy(); } function deploySharedBridgeContracts() internal { @@ -509,35 +167,16 @@ contract DeployL1Script is Script { } function deploySharedBridgeImplementation() internal { - bytes memory bytecode = abi.encodePacked( - type(L1SharedBridge).creationCode, - // solhint-disable-next-line func-named-parameters - abi.encode( - config.tokens.tokenWethAddress, - addresses.bridgehub.bridgehubProxy, - config.eraChainId, - addresses.stateTransition.diamondProxy - ) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("SharedBridgeImplementation deployed at:", contractAddress); - addresses.bridges.sharedBridgeImplementation = contractAddress; + _deploySharedBridgeImplementation(); } function deploySharedBridgeProxy() internal { - bytes memory initCalldata = abi.encodeCall(L1SharedBridge.initialize, (config.deployerAddress)); - bytes memory bytecode = abi.encodePacked( - type(TransparentUpgradeableProxy).creationCode, - abi.encode(addresses.bridges.sharedBridgeImplementation, addresses.transparentProxyAdmin, initCalldata) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("SharedBridgeProxy deployed at:", contractAddress); - addresses.bridges.sharedBridgeProxy = contractAddress; + _deploySharedBridgeProxy(); } function registerSharedBridge() internal { Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); - vm.startBroadcast(); + vm.startBroadcast(msg.sender); bridgehub.addToken(ADDRESS_ONE); bridgehub.setSharedBridge(addresses.bridges.sharedBridgeProxy); vm.stopBroadcast(); @@ -545,35 +184,22 @@ contract DeployL1Script is Script { } function deployErc20BridgeImplementation() internal { - bytes memory bytecode = abi.encodePacked( - type(L1ERC20Bridge).creationCode, - abi.encode(addresses.bridges.sharedBridgeProxy) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("Erc20BridgeImplementation deployed at:", contractAddress); - addresses.bridges.erc20BridgeImplementation = contractAddress; + _deployErc20BridgeImplementation(); } function deployErc20BridgeProxy() internal { - bytes memory initCalldata = abi.encodeCall(L1ERC20Bridge.initialize, ()); - bytes memory bytecode = abi.encodePacked( - type(TransparentUpgradeableProxy).creationCode, - abi.encode(addresses.bridges.erc20BridgeImplementation, addresses.transparentProxyAdmin, initCalldata) - ); - address contractAddress = deployViaCreate2(bytecode); - console.log("Erc20BridgeProxy deployed at:", contractAddress); - addresses.bridges.erc20BridgeProxy = contractAddress; + _deployErc20BridgeProxy(); } function updateSharedBridge() internal { L1SharedBridge sharedBridge = L1SharedBridge(addresses.bridges.sharedBridgeProxy); - vm.broadcast(); + vm.broadcast(msg.sender); sharedBridge.setL1Erc20Bridge(addresses.bridges.erc20BridgeProxy); console.log("SharedBridge updated with ERC20Bridge address"); } function updateOwners() internal { - vm.startBroadcast(); + vm.startBroadcast(msg.sender); ValidatorTimelock validatorTimelock = ValidatorTimelock(addresses.validatorTimelock); validatorTimelock.transferOwnership(config.ownerAddress); @@ -590,129 +216,10 @@ contract DeployL1Script is Script { } function saveOutput() internal { - vm.serializeAddress("bridgehub", "bridgehub_proxy_addr", addresses.bridgehub.bridgehubProxy); - string memory bridgehub = vm.serializeAddress( - "bridgehub", - "bridgehub_implementation_addr", - addresses.bridgehub.bridgehubImplementation - ); - - vm.serializeAddress( - "state_transition", - "state_transition_proxy_addr", - addresses.stateTransition.stateTransitionProxy - ); - vm.serializeAddress( - "state_transition", - "state_transition_implementation_addr", - addresses.stateTransition.stateTransitionImplementation - ); - vm.serializeAddress("state_transition", "verifier_addr", addresses.stateTransition.verifier); - vm.serializeAddress("state_transition", "admin_facet_addr", addresses.stateTransition.adminFacet); - vm.serializeAddress("state_transition", "mailbox_facet_addr", addresses.stateTransition.mailboxFacet); - vm.serializeAddress("state_transition", "executor_facet_addr", addresses.stateTransition.executorFacet); - vm.serializeAddress("state_transition", "getters_facet_addr", addresses.stateTransition.gettersFacet); - vm.serializeAddress("state_transition", "diamond_init_addr", addresses.stateTransition.diamondInit); - vm.serializeAddress("state_transition", "genesis_upgrade_addr", addresses.stateTransition.genesisUpgrade); - vm.serializeAddress("state_transition", "default_upgrade_addr", addresses.stateTransition.defaultUpgrade); - string memory stateTransition = vm.serializeAddress( - "state_transition", - "diamond_proxy_addr", - addresses.stateTransition.diamondProxy - ); - - vm.serializeAddress("bridges", "erc20_bridge_implementation_addr", addresses.bridges.erc20BridgeImplementation); - vm.serializeAddress("bridges", "erc20_bridge_proxy_addr", addresses.bridges.erc20BridgeProxy); - vm.serializeAddress( - "bridges", - "shared_bridge_implementation_addr", - addresses.bridges.sharedBridgeImplementation - ); - string memory bridges = vm.serializeAddress( - "bridges", - "shared_bridge_proxy_addr", - addresses.bridges.sharedBridgeProxy - ); - - vm.serializeUint( - "contracts_config", - "diamond_init_pubdata_pricing_mode", - uint256(config.contracts.diamondInitPubdataPricingMode) - ); - vm.serializeUint( - "contracts_config", - "diamond_init_batch_overhead_l1_gas", - config.contracts.diamondInitBatchOverheadL1Gas - ); - vm.serializeUint( - "contracts_config", - "diamond_init_max_pubdata_per_batch", - config.contracts.diamondInitMaxPubdataPerBatch - ); - vm.serializeUint( - "contracts_config", - "diamond_init_max_l2_gas_per_batch", - config.contracts.diamondInitMaxL2GasPerBatch - ); - vm.serializeUint( - "contracts_config", - "diamond_init_priority_tx_max_pubdata", - config.contracts.diamondInitPriorityTxMaxPubdata - ); - vm.serializeUint( - "contracts_config", - "diamond_init_minimal_l2_gas_price", - config.contracts.diamondInitMinimalL2GasPrice - ); - vm.serializeBytes32( - "contracts_config", - "recursion_node_level_vk_hash", - config.contracts.recursionNodeLevelVkHash - ); - vm.serializeBytes32( - "contracts_config", - "recursion_leaf_level_vk_hash", - config.contracts.recursionLeafLevelVkHash - ); - vm.serializeBytes32( - "contracts_config", - "recursion_circuits_set_vks_hash", - config.contracts.recursionCircuitsSetVksHash - ); - vm.serializeUint("contracts_config", "priority_tx_max_gas_limit", config.contracts.priorityTxMaxGasLimit); - string memory contractsConfig = vm.serializeBytes( - "contracts_config", - "diamond_cut_data", - config.contracts.diamondCutData - ); - - vm.serializeAddress("deployed_addresses", "transparent_proxy_admin_addr", addresses.transparentProxyAdmin); - vm.serializeAddress("deployed_addresses", "governance_addr", addresses.governance); - vm.serializeAddress( - "deployed_addresses", - "blob_versioned_hash_retriever_addr", - addresses.blobVersionedHashRetriever - ); - vm.serializeAddress("deployed_addresses", "validator_timelock_addr", addresses.validatorTimelock); - vm.serializeString("deployed_addresses", "bridgehub", bridgehub); - vm.serializeString("deployed_addresses", "state_transition", stateTransition); - string memory deployedAddresses = vm.serializeString("deployed_addresses", "bridges", bridges); - - vm.serializeAddress("root", "create2_factory_addr", addresses.create2Factory); - vm.serializeBytes32("root", "create2_factory_salt", config.contracts.create2FactorySalt); - vm.serializeAddress("root", "multicall3_addr", config.contracts.multicall3Addr); - vm.serializeUint("root", "l1_chain_id", config.l1ChainId); - vm.serializeUint("root", "era_chain_id", config.eraChainId); - vm.serializeAddress("root", "deployer_addr", config.deployerAddress); - vm.serializeString("root", "deployed_addresses", deployedAddresses); - vm.serializeString("root", "contracts_config", contractsConfig); - string memory toml = vm.serializeAddress("root", "owner_addr", config.ownerAddress); - - string memory path = string.concat(vm.projectRoot(), "/script-out/output-deploy-l1.toml"); - vm.writeToml(toml, path); + _saveOutput(); } function deployViaCreate2(bytes memory _bytecode) internal returns (address) { - return Utils.deployViaCreate2(_bytecode, config.contracts.create2FactorySalt, addresses.create2Factory); + return _deployViaCreate2(_bytecode); } -} +} \ No newline at end of file diff --git a/l1-contracts/deploy-scripts/DeployPaymaster.s.sol b/l1-contracts/deploy-scripts/DeployPaymaster.s.sol index 00df18e6c..040343244 100644 --- a/l1-contracts/deploy-scripts/DeployPaymaster.s.sol +++ b/l1-contracts/deploy-scripts/DeployPaymaster.s.sol @@ -26,9 +26,12 @@ contract DeployPaymaster is Script { string memory root = vm.projectRoot(); string memory path = string.concat(root, "/deploy-script-config-template/config-deploy-paymaster.toml"); string memory toml = vm.readFile(path); - config.bridgehubAddress = toml.readAddress("$.bridgehub"); config.l1SharedBridgeProxy = toml.readAddress("$.l1_shared_bridge"); - config.chainId = toml.readUint("$.chain_id"); + + path = string.concat(root, "/script-out/output-deploy-l1.toml"); + toml = vm.readFile(path); + config.bridgehubAddress = toml.readAddress("$.deployed_addresses.bridgehub.bridgehub_proxy_addr"); + config.chainId = toml.readUint("$.era_chain_id"); } function saveOutput() internal { @@ -50,7 +53,6 @@ contract DeployPaymaster is Script { bytes memory testnetPaymasterBytecode = Utils.readHardhatBytecode( "/../l2-contracts/artifacts-zk/contracts/TestnetPaymaster.sol/TestnetPaymaster.json" ); - console.log("addr", config.bridgehubAddress); config.paymaster = Utils.deployThroughL1({ bytecode: testnetPaymasterBytecode, constructorargs: "", diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index 6da3e5d0b..d9fa0244b 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -64,7 +64,7 @@ contract RegisterHyperchainScript is Script { function initializeConfig() internal { // Grab config from output of l1 deployment string memory root = vm.projectRoot(); - string memory path = string.concat(root, "/script-config/register-hyperchain.toml"); + string memory path = string.concat(root, "/script-out/output-deploy-l1.toml"); string memory toml = vm.readFile(path); config.deployerAddress = msg.sender; @@ -72,7 +72,7 @@ contract RegisterHyperchainScript is Script { // Config file must be parsed key by key, otherwise values returned // are parsed alfabetically and not by key. // https://book.getfoundry.sh/cheatcodes/parse-toml - config.ownerAddress = toml.readAddress("$.owner_address"); + config.ownerAddress = toml.readAddress("$.owner_addr"); config.bridgehub = toml.readAddress("$.deployed_addresses.bridgehub.bridgehub_proxy_addr"); config.stateTransitionProxy = toml.readAddress( @@ -82,6 +82,9 @@ contract RegisterHyperchainScript is Script { config.diamondCutData = toml.readBytes("$.contracts_config.diamond_cut_data"); + path = string.concat(root, "/deploy-script-config-template/register-hyperchain.toml"); + toml = vm.readFile(path); + config.chainChainId = toml.readUint("$.chain.chain_chain_id"); config.bridgehubCreateNewChainSalt = toml.readUint("$.chain.bridgehub_create_new_chain_salt"); config.baseToken = toml.readAddress("$.chain.base_token_addr"); @@ -98,6 +101,16 @@ contract RegisterHyperchainScript is Script { config.governanceSecurityCouncilAddress = toml.readAddress("$.chain.governance_security_council_address"); } + function getValidatorAdmin() public returns (address) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-out/output-deploy-l1.toml"); + string memory toml = vm.readFile(path); + + address validatorAdmin = toml.readAddress("$.deployer_addr"); + + return validatorAdmin; + } + function checkTokenAddress() internal view { if (config.baseToken == address(0)) { revert("Token address is not set"); @@ -193,7 +206,7 @@ contract RegisterHyperchainScript is Script { function addValidators() internal { ValidatorTimelock validatorTimelock = ValidatorTimelock(config.validatorTimelock); - vm.startBroadcast(); + vm.startBroadcast(getValidatorAdmin()); validatorTimelock.addValidator(config.chainChainId, config.validatorSenderOperatorCommitEth); validatorTimelock.addValidator(config.chainChainId, config.validatorSenderOperatorBlobsEth); vm.stopBroadcast(); @@ -204,7 +217,7 @@ contract RegisterHyperchainScript is Script { function configureZkSyncStateTransition() internal { IZkSyncHyperchain hyperchain = IZkSyncHyperchain(config.newDiamondProxy); - vm.startBroadcast(); + vm.startBroadcast(getValidatorAdmin()); hyperchain.setTokenMultiplier( config.baseTokenGasPriceMultiplierNominator, config.baseTokenGasPriceMultiplierDenominator @@ -221,7 +234,7 @@ contract RegisterHyperchainScript is Script { function setPendingAdmin() internal { IZkSyncHyperchain hyperchain = IZkSyncHyperchain(config.newDiamondProxy); - vm.broadcast(); + vm.broadcast(getValidatorAdmin()); hyperchain.setPendingAdmin(config.governance); console.log("Owner for ", config.newDiamondProxy, "set to", config.governance); } diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index 318be6da3..811151cdf 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -12,8 +12,11 @@ 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 {stdToml} from "forge-std/StdToml.sol"; +import {console2 as console} from "forge-std/Script.sol"; library Utils { + using stdToml for string; // Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); Vm internal constant vm = Vm(VM_ADDRESS); @@ -182,7 +185,6 @@ library Utils { address l1SharedBridgeProxy ) internal returns (address) { bytes32 bytecodeHash = L2ContractHelper.hashL2Bytecode(bytecode); - bytes memory deployData = abi.encodeWithSignature( "create2(bytes32,bytes32,bytes)", create2salt, @@ -215,6 +217,7 @@ library Utils { bridgehubAddress: bridgehubAddress, l1SharedBridgeProxy: l1SharedBridgeProxy }); + return contractAddress; } @@ -239,7 +242,7 @@ library Utils { l2GasLimit, REQUIRED_L2_GAS_PRICE_PER_PUBDATA ) * 2; - + L2TransactionRequestDirect memory l2TransactionRequestDirect = L2TransactionRequestDirect({ chainId: chainId, mintValue: requiredValueToDeploy, @@ -303,6 +306,11 @@ library Utils { uint256 _value, uint256 _delay ) internal { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-out/output-deploy-l1.toml"); + string memory toml = vm.readFile(path); + address ownerAddress = toml.readAddress("$.owner_addr"); + IGovernance governance = IGovernance(_governor); IGovernance.Call[] memory calls = new IGovernance.Call[](1); @@ -314,7 +322,7 @@ library Utils { salt: _salt }); - vm.startBroadcast(); + vm.startBroadcast(ownerAddress); governance.scheduleTransparent(operation, _delay); if (_delay == 0) { governance.execute{value: _value}(operation); diff --git a/l1-contracts/deploy-scripts/_DeployL1.s.sol b/l1-contracts/deploy-scripts/_DeployL1.s.sol new file mode 100644 index 000000000..83bc9be0b --- /dev/null +++ b/l1-contracts/deploy-scripts/_DeployL1.s.sol @@ -0,0 +1,734 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +// solhint-disable no-console + +import {Script, console2 as console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import {Utils} from "./Utils.sol"; +import {Multicall3} from "contracts/dev-contracts/Multicall3.sol"; +import {Verifier} from "contracts/state-transition/Verifier.sol"; +import {TestnetVerifier} from "contracts/state-transition/TestnetVerifier.sol"; +import {VerifierParams, IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {DefaultUpgrade} from "contracts/upgrades/DefaultUpgrade.sol"; +import {Governance} from "contracts/governance/Governance.sol"; +import {GenesisUpgrade} from "contracts/upgrades/GenesisUpgrade.sol"; +import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; +import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; +import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; +import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; +import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; +import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; +import {StateTransitionManager} from "contracts/state-transition/StateTransitionManager.sol"; +import {StateTransitionManagerInitializeData, ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; +import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol"; +import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; +import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; +import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; +import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; +import {AddressHasNoCode} from "./ZkSyncScriptErrors.sol"; + +contract _DeployL1Script is Script { + using stdToml for string; + + address constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; + address constant DETERMINISTIC_CREATE2_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + // solhint-disable-next-line gas-struct-packing + struct DeployedAddresses { + BridgehubDeployedAddresses bridgehub; + StateTransitionDeployedAddresses stateTransition; + BridgesDeployedAddresses bridges; + address transparentProxyAdmin; + address governance; + address blobVersionedHashRetriever; + address validatorTimelock; + address create2Factory; + } + + // solhint-disable-next-line gas-struct-packing + struct BridgehubDeployedAddresses { + address bridgehubImplementation; + address bridgehubProxy; + } + + // solhint-disable-next-line gas-struct-packing + struct StateTransitionDeployedAddresses { + address stateTransitionProxy; + address stateTransitionImplementation; + address verifier; + address adminFacet; + address mailboxFacet; + address executorFacet; + address gettersFacet; + address diamondInit; + address genesisUpgrade; + address defaultUpgrade; + address diamondProxy; + } + + // solhint-disable-next-line gas-struct-packing + struct BridgesDeployedAddresses { + address erc20BridgeImplementation; + address erc20BridgeProxy; + address sharedBridgeImplementation; + address sharedBridgeProxy; + } + + // solhint-disable-next-line gas-struct-packing + struct Config { + uint256 l1ChainId; + uint256 eraChainId; + address deployerAddress; + address ownerAddress; + bool testnetVerifier; + ContractsConfig contracts; + TokensConfig tokens; + } + + // solhint-disable-next-line gas-struct-packing + struct ContractsConfig { + bytes32 create2FactorySalt; + address create2FactoryAddr; + address multicall3Addr; + uint256 validatorTimelockExecutionDelay; + bytes32 genesisRoot; + uint256 genesisRollupLeafIndex; + bytes32 genesisBatchCommitment; + uint256 latestProtocolVersion; + bytes32 recursionNodeLevelVkHash; + bytes32 recursionLeafLevelVkHash; + bytes32 recursionCircuitsSetVksHash; + uint256 priorityTxMaxGasLimit; + PubdataPricingMode diamondInitPubdataPricingMode; + uint256 diamondInitBatchOverheadL1Gas; + uint256 diamondInitMaxPubdataPerBatch; + uint256 diamondInitMaxL2GasPerBatch; + uint256 diamondInitPriorityTxMaxPubdata; + uint256 diamondInitMinimalL2GasPrice; + address governanceSecurityCouncilAddress; + uint256 governanceMinDelay; + uint256 maxNumberOfChains; + bytes diamondCutData; + bytes32 bootloaderHash; + bytes32 defaultAAHash; + } + + struct TokensConfig { + address tokenWethAddress; + } + + Config internal config; + DeployedAddresses internal addresses; + + function _run() public { + console.log("Deploying L1 contracts"); + + _initializeConfig(); + + _instantiateCreate2Factory(); + _deployIfNeededMulticall3(); + + _deployVerifier(); + + _deployDefaultUpgrade(); + _deployGenesisUpgrade(); + _deployValidatorTimelock(); + + _deployGovernance(); + _deployTransparentProxyAdmin(); + _deployBridgehubContract(); + _deployBlobVersionedHashRetriever(); + _deployStateTransitionManagerContract(); + _setStateTransitionManagerInValidatorTimelock(); + + _deployDiamondProxy(); + + _deploySharedBridgeContracts(); + _deployErc20BridgeImplementation(); + _deployErc20BridgeProxy(); + _updateSharedBridge(); + + _updateOwners(); + + _saveOutput(); + } + + function _getBridgehubProxyAddress() public view returns (address) { + return addresses.bridgehub.bridgehubProxy; + } + + function _getSharedBridgeProxyAddress() public view returns (address) { + return addresses.bridges.sharedBridgeProxy; + } + + function _getBridgehubStateTransitionProxy() public view returns (address) { + return addresses.stateTransition.stateTransitionProxy; + } + + function _getStateTransitionDiamondProxy() public view returns (address) { + return addresses.stateTransition.diamondProxy; + } + + function _initializeConfig() internal { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/deploy-script-config-template/config-deploy-l1.toml"); + string memory toml = vm.readFile(path); + + config.l1ChainId = block.chainid; + config.deployerAddress = msg.sender; + + // Config file must be parsed key by key, otherwise values returned + // are parsed alfabetically and not by key. + // https://book.getfoundry.sh/cheatcodes/parse-toml + config.eraChainId = toml.readUint("$.era_chain_id"); + config.ownerAddress = toml.readAddress("$.owner_address"); + config.testnetVerifier = toml.readBool("$.testnet_verifier"); + + config.contracts.governanceSecurityCouncilAddress = toml.readAddress( + "$.contracts.governance_security_council_address" + ); + config.contracts.governanceMinDelay = toml.readUint("$.contracts.governance_min_delay"); + config.contracts.maxNumberOfChains = toml.readUint("$.contracts.max_number_of_chains"); + config.contracts.create2FactorySalt = toml.readBytes32("$.contracts.create2_factory_salt"); + if (vm.keyExistsToml(toml, "$.contracts.create2_factory_addr")) { + config.contracts.create2FactoryAddr = toml.readAddress("$.contracts.create2_factory_addr"); + } + config.contracts.validatorTimelockExecutionDelay = toml.readUint( + "$.contracts.validator_timelock_execution_delay" + ); + config.contracts.genesisRoot = toml.readBytes32("$.contracts.genesis_root"); + config.contracts.genesisRollupLeafIndex = toml.readUint("$.contracts.genesis_rollup_leaf_index"); + config.contracts.genesisBatchCommitment = toml.readBytes32("$.contracts.genesis_batch_commitment"); + config.contracts.latestProtocolVersion = toml.readUint("$.contracts.latest_protocol_version"); + config.contracts.recursionNodeLevelVkHash = toml.readBytes32("$.contracts.recursion_node_level_vk_hash"); + config.contracts.recursionLeafLevelVkHash = toml.readBytes32("$.contracts.recursion_leaf_level_vk_hash"); + config.contracts.recursionCircuitsSetVksHash = toml.readBytes32("$.contracts.recursion_circuits_set_vks_hash"); + config.contracts.priorityTxMaxGasLimit = toml.readUint("$.contracts.priority_tx_max_gas_limit"); + config.contracts.diamondInitPubdataPricingMode = PubdataPricingMode( + toml.readUint("$.contracts.diamond_init_pubdata_pricing_mode") + ); + config.contracts.diamondInitBatchOverheadL1Gas = toml.readUint( + "$.contracts.diamond_init_batch_overhead_l1_gas" + ); + config.contracts.diamondInitMaxPubdataPerBatch = toml.readUint( + "$.contracts.diamond_init_max_pubdata_per_batch" + ); + config.contracts.diamondInitMaxL2GasPerBatch = toml.readUint("$.contracts.diamond_init_max_l2_gas_per_batch"); + config.contracts.diamondInitPriorityTxMaxPubdata = toml.readUint( + "$.contracts.diamond_init_priority_tx_max_pubdata" + ); + config.contracts.diamondInitMinimalL2GasPrice = toml.readUint("$.contracts.diamond_init_minimal_l2_gas_price"); + config.contracts.defaultAAHash = toml.readBytes32("$.contracts.default_aa_hash"); + config.contracts.bootloaderHash = toml.readBytes32("$.contracts.bootloader_hash"); + + config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address"); + } + + function _instantiateCreate2Factory() internal { + address contractAddress; + + bool isDeterministicDeployed = DETERMINISTIC_CREATE2_ADDRESS.code.length > 0; + bool isConfigured = config.contracts.create2FactoryAddr != address(0); + + if (isConfigured) { + if (config.contracts.create2FactoryAddr.code.length == 0) { + revert AddressHasNoCode(config.contracts.create2FactoryAddr); + } + contractAddress = config.contracts.create2FactoryAddr; + console.log("Using configured Create2Factory address:", contractAddress); + } else if (isDeterministicDeployed) { + contractAddress = DETERMINISTIC_CREATE2_ADDRESS; + console.log("Using deterministic Create2Factory address:", contractAddress); + } else { + contractAddress = Utils.deployCreate2Factory(); + console.log("Create2Factory deployed at:", contractAddress); + } + + addresses.create2Factory = contractAddress; + } + + function _deployIfNeededMulticall3() internal { + // Multicall3 is already deployed on public networks + if (MULTICALL3_ADDRESS.code.length == 0) { + address contractAddress = _deployViaCreate2(type(Multicall3).creationCode); + console.log("Multicall3 deployed at:", contractAddress); + config.contracts.multicall3Addr = contractAddress; + } else { + config.contracts.multicall3Addr = MULTICALL3_ADDRESS; + } + } + + function _deployVerifier() internal { + bytes memory code; + if (config.testnetVerifier) { + code = type(TestnetVerifier).creationCode; + } else { + code = type(Verifier).creationCode; + } + address contractAddress = _deployViaCreate2(code); + console.log("Verifier deployed at:", contractAddress); + addresses.stateTransition.verifier = contractAddress; + } + + function _deployDefaultUpgrade() internal { + address contractAddress = _deployViaCreate2(type(DefaultUpgrade).creationCode); + console.log("DefaultUpgrade deployed at:", contractAddress); + addresses.stateTransition.defaultUpgrade = contractAddress; + } + + function _deployGenesisUpgrade() internal { + address contractAddress = _deployViaCreate2(type(GenesisUpgrade).creationCode); + console.log("GenesisUpgrade deployed at:", contractAddress); + addresses.stateTransition.genesisUpgrade = contractAddress; + } + + function _deployValidatorTimelock() internal { + uint32 executionDelay = uint32(config.contracts.validatorTimelockExecutionDelay); + bytes memory bytecode = abi.encodePacked( + type(ValidatorTimelock).creationCode, + abi.encode(config.deployerAddress, executionDelay, config.eraChainId) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("ValidatorTimelock deployed at:", contractAddress); + addresses.validatorTimelock = contractAddress; + } + + function _deployGovernance() internal { + bytes memory bytecode = abi.encodePacked( + type(Governance).creationCode, + abi.encode( + config.ownerAddress, + config.contracts.governanceSecurityCouncilAddress, + config.contracts.governanceMinDelay + ) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("Governance deployed at:", contractAddress); + addresses.governance = contractAddress; + } + + function _deployTransparentProxyAdmin() internal { + vm.startBroadcast(msg.sender); + ProxyAdmin proxyAdmin = new ProxyAdmin(); + proxyAdmin.transferOwnership(addresses.governance); + vm.stopBroadcast(); + console.log("Transparent Proxy Admin deployed at:", address(proxyAdmin)); + addresses.transparentProxyAdmin = address(proxyAdmin); + } + + function _deployBridgehubContract() internal { + address bridgehubImplementation = _deployViaCreate2(type(Bridgehub).creationCode); + console.log("Bridgehub Implementation deployed at:", bridgehubImplementation); + addresses.bridgehub.bridgehubImplementation = bridgehubImplementation; + + bytes memory bytecode = abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode( + bridgehubImplementation, + addresses.transparentProxyAdmin, + abi.encodeCall(Bridgehub.initialize, (config.deployerAddress)) + ) + ); + address bridgehubProxy = _deployViaCreate2(bytecode); + console.log("Bridgehub Proxy deployed at:", bridgehubProxy); + addresses.bridgehub.bridgehubProxy = bridgehubProxy; + } + + function _deployBlobVersionedHashRetriever() internal { + // solc contracts/state-transition/utils/blobVersionedHashRetriever.yul --strict-assembly --bin + bytes memory bytecode = hex"600b600b5f39600b5ff3fe5f358049805f5260205ff3"; + address contractAddress = _deployViaCreate2(bytecode); + console.log("BlobVersionedHashRetriever deployed at:", contractAddress); + addresses.blobVersionedHashRetriever = contractAddress; + } + + function _deployStateTransitionManagerContract() internal { + _deployStateTransitionDiamondFacets(); + _deployStateTransitionManagerImplementation(); + _deployStateTransitionManagerProxy(); + _registerStateTransitionManager(); + } + + function _deployStateTransitionDiamondFacets() internal { + address executorFacet = _deployViaCreate2(type(ExecutorFacet).creationCode); + console.log("ExecutorFacet deployed at:", executorFacet); + addresses.stateTransition.executorFacet = executorFacet; + + address adminFacet = _deployViaCreate2(type(AdminFacet).creationCode); + console.log("AdminFacet deployed at:", adminFacet); + addresses.stateTransition.adminFacet = adminFacet; + + address mailboxFacet = _deployViaCreate2( + abi.encodePacked(type(MailboxFacet).creationCode, abi.encode(config.eraChainId)) + ); + console.log("MailboxFacet deployed at:", mailboxFacet); + addresses.stateTransition.mailboxFacet = mailboxFacet; + + address gettersFacet = _deployViaCreate2(type(GettersFacet).creationCode); + console.log("GettersFacet deployed at:", gettersFacet); + addresses.stateTransition.gettersFacet = gettersFacet; + + address diamondInit = _deployViaCreate2(type(DiamondInit).creationCode); + console.log("DiamondInit deployed at:", diamondInit); + addresses.stateTransition.diamondInit = diamondInit; + } + + function _deployStateTransitionManagerImplementation() internal { + bytes memory bytecode = abi.encodePacked( + type(StateTransitionManager).creationCode, + abi.encode(addresses.bridgehub.bridgehubProxy), + abi.encode(config.contracts.maxNumberOfChains) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("StateTransitionManagerImplementation deployed at:", contractAddress); + addresses.stateTransition.stateTransitionImplementation = contractAddress; + } + + function _deployStateTransitionManagerProxy() internal { + Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](4); + facetCuts[0] = Diamond.FacetCut({ + facet: addresses.stateTransition.adminFacet, + action: Diamond.Action.Add, + isFreezable: false, + selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) + }); + facetCuts[1] = Diamond.FacetCut({ + facet: addresses.stateTransition.gettersFacet, + action: Diamond.Action.Add, + isFreezable: false, + selectors: Utils.getAllSelectors(addresses.stateTransition.gettersFacet.code) + }); + facetCuts[2] = Diamond.FacetCut({ + facet: addresses.stateTransition.mailboxFacet, + action: Diamond.Action.Add, + isFreezable: true, + selectors: Utils.getAllSelectors(addresses.stateTransition.mailboxFacet.code) + }); + facetCuts[3] = Diamond.FacetCut({ + facet: addresses.stateTransition.executorFacet, + action: Diamond.Action.Add, + isFreezable: true, + selectors: Utils.getAllSelectors(addresses.stateTransition.executorFacet.code) + }); + + VerifierParams memory verifierParams = VerifierParams({ + recursionNodeLevelVkHash: config.contracts.recursionNodeLevelVkHash, + recursionLeafLevelVkHash: config.contracts.recursionLeafLevelVkHash, + recursionCircuitsSetVksHash: config.contracts.recursionCircuitsSetVksHash + }); + + FeeParams memory feeParams = FeeParams({ + pubdataPricingMode: config.contracts.diamondInitPubdataPricingMode, + batchOverheadL1Gas: uint32(config.contracts.diamondInitBatchOverheadL1Gas), + maxPubdataPerBatch: uint32(config.contracts.diamondInitMaxPubdataPerBatch), + maxL2GasPerBatch: uint32(config.contracts.diamondInitMaxL2GasPerBatch), + priorityTxMaxPubdata: uint32(config.contracts.diamondInitPriorityTxMaxPubdata), + minimalL2GasPrice: uint64(config.contracts.diamondInitMinimalL2GasPrice) + }); + + DiamondInitializeDataNewChain memory initializeData = DiamondInitializeDataNewChain({ + verifier: IVerifier(addresses.stateTransition.verifier), + verifierParams: verifierParams, + l2BootloaderBytecodeHash: config.contracts.bootloaderHash, + l2DefaultAccountBytecodeHash: config.contracts.defaultAAHash, + priorityTxMaxGasLimit: config.contracts.priorityTxMaxGasLimit, + feeParams: feeParams, + blobVersionedHashRetriever: addresses.blobVersionedHashRetriever + }); + + Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ + facetCuts: facetCuts, + initAddress: addresses.stateTransition.diamondInit, + initCalldata: abi.encode(initializeData) + }); + + config.contracts.diamondCutData = abi.encode(diamondCut); + + ChainCreationParams memory chainCreationParams = ChainCreationParams({ + genesisUpgrade: addresses.stateTransition.genesisUpgrade, + genesisBatchHash: config.contracts.genesisRoot, + genesisIndexRepeatedStorageChanges: uint64(config.contracts.genesisRollupLeafIndex), + genesisBatchCommitment: config.contracts.genesisBatchCommitment, + diamondCut: diamondCut + }); + + StateTransitionManagerInitializeData memory diamondInitData = StateTransitionManagerInitializeData({ + owner: config.ownerAddress, + validatorTimelock: addresses.validatorTimelock, + chainCreationParams: chainCreationParams, + protocolVersion: config.contracts.latestProtocolVersion + }); + + address contractAddress = _deployViaCreate2( + abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode( + addresses.stateTransition.stateTransitionImplementation, + addresses.transparentProxyAdmin, + abi.encodeCall(StateTransitionManager.initialize, (diamondInitData)) + ) + ) + ); + console.log("StateTransitionManagerProxy deployed at:", contractAddress); + addresses.stateTransition.stateTransitionProxy = contractAddress; + } + + function _registerStateTransitionManager() internal { + Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); + vm.broadcast(msg.sender); + bridgehub.addStateTransitionManager(addresses.stateTransition.stateTransitionProxy); + console.log("StateTransitionManager registered"); + } + + function _setStateTransitionManagerInValidatorTimelock() internal { + ValidatorTimelock validatorTimelock = ValidatorTimelock(addresses.validatorTimelock); + vm.broadcast(msg.sender); + validatorTimelock.setStateTransitionManager( + IStateTransitionManager(addresses.stateTransition.stateTransitionProxy) + ); + console.log("StateTransitionManager set in ValidatorTimelock"); + } + + function _deployDiamondProxy() internal { + Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](1); + facetCuts[0] = Diamond.FacetCut({ + facet: addresses.stateTransition.adminFacet, + action: Diamond.Action.Add, + isFreezable: false, + selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) + }); + Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ + facetCuts: facetCuts, + initAddress: address(0), + initCalldata: "" + }); + bytes memory bytecode = abi.encodePacked( + type(DiamondProxy).creationCode, + abi.encode(config.l1ChainId, diamondCut) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("DiamondProxy deployed at:", contractAddress); + addresses.stateTransition.diamondProxy = contractAddress; + } + + function _deploySharedBridgeContracts() internal { + _deploySharedBridgeImplementation(); + _deploySharedBridgeProxy(); + _registerSharedBridge(); + } + + function _deploySharedBridgeImplementation() internal { + bytes memory bytecode = abi.encodePacked( + type(L1SharedBridge).creationCode, + // solhint-disable-next-line func-named-parameters + abi.encode( + config.tokens.tokenWethAddress, + addresses.bridgehub.bridgehubProxy, + config.eraChainId, + addresses.stateTransition.diamondProxy + ) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("SharedBridgeImplementation deployed at:", contractAddress); + addresses.bridges.sharedBridgeImplementation = contractAddress; + } + + function _deploySharedBridgeProxy() internal { + bytes memory initCalldata = abi.encodeCall(L1SharedBridge.initialize, (config.deployerAddress)); + bytes memory bytecode = abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(addresses.bridges.sharedBridgeImplementation, addresses.transparentProxyAdmin, initCalldata) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("SharedBridgeProxy deployed at:", contractAddress); + addresses.bridges.sharedBridgeProxy = contractAddress; + } + + function _registerSharedBridge() internal { + Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); + vm.startBroadcast(msg.sender); + bridgehub.addToken(ADDRESS_ONE); + bridgehub.setSharedBridge(addresses.bridges.sharedBridgeProxy); + vm.stopBroadcast(); + console.log("SharedBridge registered"); + } + + function _deployErc20BridgeImplementation() internal { + bytes memory bytecode = abi.encodePacked( + type(L1ERC20Bridge).creationCode, + abi.encode(addresses.bridges.sharedBridgeProxy) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("Erc20BridgeImplementation deployed at:", contractAddress); + addresses.bridges.erc20BridgeImplementation = contractAddress; + } + + function _deployErc20BridgeProxy() internal { + bytes memory initCalldata = abi.encodeCall(L1ERC20Bridge.initialize, ()); + bytes memory bytecode = abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(addresses.bridges.erc20BridgeImplementation, addresses.transparentProxyAdmin, initCalldata) + ); + address contractAddress = _deployViaCreate2(bytecode); + console.log("Erc20BridgeProxy deployed at:", contractAddress); + addresses.bridges.erc20BridgeProxy = contractAddress; + } + + function _updateSharedBridge() internal { + L1SharedBridge sharedBridge = L1SharedBridge(addresses.bridges.sharedBridgeProxy); + vm.broadcast(msg.sender); + sharedBridge.setL1Erc20Bridge(addresses.bridges.erc20BridgeProxy); + console.log("SharedBridge updated with ERC20Bridge address"); + } + + function _updateOwners() internal { + vm.startBroadcast(msg.sender); + + ValidatorTimelock validatorTimelock = ValidatorTimelock(addresses.validatorTimelock); + validatorTimelock.transferOwnership(config.ownerAddress); + + Bridgehub bridgehub = Bridgehub(addresses.bridgehub.bridgehubProxy); + bridgehub.transferOwnership(addresses.governance); + + L1SharedBridge sharedBridge = L1SharedBridge(addresses.bridges.sharedBridgeProxy); + sharedBridge.transferOwnership(addresses.governance); + + vm.stopBroadcast(); + + console.log("Owners updated"); + } + + function _saveOutput() internal { + vm.serializeAddress("bridgehub", "bridgehub_proxy_addr", addresses.bridgehub.bridgehubProxy); + string memory bridgehub = vm.serializeAddress( + "bridgehub", + "bridgehub_implementation_addr", + addresses.bridgehub.bridgehubImplementation + ); + + vm.serializeAddress( + "state_transition", + "state_transition_proxy_addr", + addresses.stateTransition.stateTransitionProxy + ); + vm.serializeAddress( + "state_transition", + "state_transition_implementation_addr", + addresses.stateTransition.stateTransitionImplementation + ); + vm.serializeAddress("state_transition", "verifier_addr", addresses.stateTransition.verifier); + vm.serializeAddress("state_transition", "admin_facet_addr", addresses.stateTransition.adminFacet); + vm.serializeAddress("state_transition", "mailbox_facet_addr", addresses.stateTransition.mailboxFacet); + vm.serializeAddress("state_transition", "executor_facet_addr", addresses.stateTransition.executorFacet); + vm.serializeAddress("state_transition", "getters_facet_addr", addresses.stateTransition.gettersFacet); + vm.serializeAddress("state_transition", "diamond_init_addr", addresses.stateTransition.diamondInit); + vm.serializeAddress("state_transition", "genesis_upgrade_addr", addresses.stateTransition.genesisUpgrade); + vm.serializeAddress("state_transition", "default_upgrade_addr", addresses.stateTransition.defaultUpgrade); + string memory stateTransition = vm.serializeAddress( + "state_transition", + "diamond_proxy_addr", + addresses.stateTransition.diamondProxy + ); + + vm.serializeAddress("bridges", "erc20_bridge_implementation_addr", addresses.bridges.erc20BridgeImplementation); + vm.serializeAddress("bridges", "erc20_bridge_proxy_addr", addresses.bridges.erc20BridgeProxy); + vm.serializeAddress( + "bridges", + "shared_bridge_implementation_addr", + addresses.bridges.sharedBridgeImplementation + ); + string memory bridges = vm.serializeAddress( + "bridges", + "shared_bridge_proxy_addr", + addresses.bridges.sharedBridgeProxy + ); + + vm.serializeUint( + "contracts_config", + "diamond_init_pubdata_pricing_mode", + uint256(config.contracts.diamondInitPubdataPricingMode) + ); + vm.serializeUint( + "contracts_config", + "diamond_init_batch_overhead_l1_gas", + config.contracts.diamondInitBatchOverheadL1Gas + ); + vm.serializeUint( + "contracts_config", + "diamond_init_max_pubdata_per_batch", + config.contracts.diamondInitMaxPubdataPerBatch + ); + vm.serializeUint( + "contracts_config", + "diamond_init_max_l2_gas_per_batch", + config.contracts.diamondInitMaxL2GasPerBatch + ); + vm.serializeUint( + "contracts_config", + "diamond_init_priority_tx_max_pubdata", + config.contracts.diamondInitPriorityTxMaxPubdata + ); + vm.serializeUint( + "contracts_config", + "diamond_init_minimal_l2_gas_price", + config.contracts.diamondInitMinimalL2GasPrice + ); + vm.serializeBytes32( + "contracts_config", + "recursion_node_level_vk_hash", + config.contracts.recursionNodeLevelVkHash + ); + vm.serializeBytes32( + "contracts_config", + "recursion_leaf_level_vk_hash", + config.contracts.recursionLeafLevelVkHash + ); + vm.serializeBytes32( + "contracts_config", + "recursion_circuits_set_vks_hash", + config.contracts.recursionCircuitsSetVksHash + ); + vm.serializeUint("contracts_config", "priority_tx_max_gas_limit", config.contracts.priorityTxMaxGasLimit); + string memory contractsConfig = vm.serializeBytes( + "contracts_config", + "diamond_cut_data", + config.contracts.diamondCutData + ); + + vm.serializeAddress("deployed_addresses", "transparent_proxy_admin_addr", addresses.transparentProxyAdmin); + vm.serializeAddress("deployed_addresses", "governance_addr", addresses.governance); + vm.serializeAddress( + "deployed_addresses", + "blob_versioned_hash_retriever_addr", + addresses.blobVersionedHashRetriever + ); + vm.serializeAddress("deployed_addresses", "validator_timelock_addr", addresses.validatorTimelock); + vm.serializeString("deployed_addresses", "bridgehub", bridgehub); + vm.serializeString("deployed_addresses", "state_transition", stateTransition); + string memory deployedAddresses = vm.serializeString("deployed_addresses", "bridges", bridges); + + vm.serializeAddress("root", "create2_factory_addr", addresses.create2Factory); + vm.serializeBytes32("root", "create2_factory_salt", config.contracts.create2FactorySalt); + vm.serializeAddress("root", "multicall3_addr", config.contracts.multicall3Addr); + vm.serializeUint("root", "l1_chain_id", config.l1ChainId); + vm.serializeUint("root", "era_chain_id", config.eraChainId); + vm.serializeAddress("root", "deployer_addr", config.deployerAddress); + vm.serializeString("root", "deployed_addresses", deployedAddresses); + vm.serializeString("root", "contracts_config", contractsConfig); + string memory toml = vm.serializeAddress("root", "owner_addr", config.ownerAddress); + + string memory path = string.concat(vm.projectRoot(), "/script-out/output-deploy-l1.toml"); + vm.writeToml(toml, path); + } + + function _deployViaCreate2(bytes memory _bytecode) internal returns (address) { + return Utils.deployViaCreate2(_bytecode, config.contracts.create2FactorySalt, addresses.create2Factory); + } +} \ No newline at end of file diff --git a/l1-contracts/foundry.toml b/l1-contracts/foundry.toml index 906e66d82..7b021c756 100644 --- a/l1-contracts/foundry.toml +++ b/l1-contracts/foundry.toml @@ -16,7 +16,11 @@ fs_permissions = [ { access = "read-write", path = "./script-out" }, { access = "read", path = "./out" }, { access = "read", path = "./deploy-script-config-template/config-deploy-paymaster.toml"}, - { access = "read", path = "../l2-contracts/artifacts-zk/contracts/TestnetPaymaster.sol/TestnetPaymaster.json"} + { access = "read", path = "../l2-contracts/artifacts-zk/contracts/TestnetPaymaster.sol/TestnetPaymaster.json"}, + { access = "read", path = "./deploy-script-config-template/config-deploy-l1.toml"}, + { access = "read-write", path = "./script-out/output-deploy-l1.toml"}, + { access = "read", path = "./deploy-script-config-template/register-hyperchain.toml"}, + { access = "read-write", path = "./script-out/output-register-hyperchain.toml"} ] cache_path = 'cache-forge' test = 'test/foundry' diff --git a/l1-contracts/test/foundry/unit/DeployPaymaster.t.sol b/l1-contracts/test/foundry/unit/DeployPaymaster.t.sol index eb7963fb7..6bd0a5618 100644 --- a/l1-contracts/test/foundry/unit/DeployPaymaster.t.sol +++ b/l1-contracts/test/foundry/unit/DeployPaymaster.t.sol @@ -4,6 +4,10 @@ pragma solidity 0.8.24; import {Test} from "forge-std/Test.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {DeployPaymaster} from "../../../deploy-scripts/DeployPaymaster.s.sol"; +import {RegisterHyperchainScript} from "../../../deploy-scripts/RegisterHyperchain.s.sol"; +import {DeployL1Script} from "../../../deploy-scripts/DeployL1.s.sol"; +import {_DeployL1Script} from "../../../deploy-scripts/_DeployL1.s.sol"; +import {Bridgehub} from "../../../contracts/bridgehub/Bridgehub.sol"; contract DeployPaymasterTest is Test { using stdToml for string; @@ -16,17 +20,40 @@ contract DeployPaymasterTest is Test { } Config config; + address bridgehubProxyAddress; + Bridgehub bridgeHub; - DeployPaymaster private deployScript; + DeployPaymaster private deployPaymaster; + DeployL1Script private deployL1; + _DeployL1Script private _deployL1; + RegisterHyperchainScript private deployHyperchain; + + function _acceptOwnership() private { + vm.startPrank(bridgeHub.pendingOwner()); + bridgeHub.acceptOwnership(); + vm.stopPrank(); + } function setUp() public { + deployL1 = new DeployL1Script(); + deployL1.run(); + + _deployL1 = new _DeployL1Script(); + _deployL1._run(); + + bridgehubProxyAddress = _deployL1._getBridgehubProxyAddress(); + bridgeHub = Bridgehub(bridgehubProxyAddress); + _acceptOwnership(); + + vm.warp(100); + deployHyperchain = new RegisterHyperchainScript(); + deployHyperchain.run(); + string memory url = getChain(1).rpcUrl; vm.createSelectFork({urlOrAlias: url, blockNumber: 16_428_900}); - vm.allowCheatcodes(0xEA785A9c91A07ED69b83EB165f4Ce2C30ecb4c0b); vm.deal(0xEA785A9c91A07ED69b83EB165f4Ce2C30ecb4c0b, 720000000000000); - vm.allowCheatcodes(0x51dE418cB7f5b630D5Ca9A49514e34E2420a66b3); - deployScript = new DeployPaymaster(); - deployScript.run(); + deployPaymaster = new DeployPaymaster(); + deployPaymaster.run(); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-out/output-deploy-paymaster.toml"); @@ -34,8 +61,8 @@ contract DeployPaymasterTest is Test { config.paymaster = toml.readAddress("$.paymaster"); } - function test() public { - address paymasterAddress = deployScript.getPaymasterAddress(); + function test_checkPaymasterAddress() public { + address paymasterAddress = deployPaymaster.getPaymasterAddress(); address paymasterAddressCheck = config.paymaster; assertEq(paymasterAddress, paymasterAddressCheck); }