diff --git a/l1-contracts-foundry/script/RegisterHyperchain.s.sol b/l1-contracts-foundry/script/RegisterHyperchain.s.sol deleted file mode 100644 index c0d776813..000000000 --- a/l1-contracts-foundry/script/RegisterHyperchain.s.sol +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.24; - -// solhint-disable no-console - -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 {Utils} from "./Utils.sol"; -import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; -import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; -import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; -import {VerifierParams, IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; -import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; -import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; -import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; -import {ZksyncContract, MissingAddress, AddressHasNoCode} from "./ZkSyncScriptErrors.sol"; - -contract RegisterHyperchainScript is Script { - using stdToml for string; - - address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; - bytes32 internal constant STATE_TRANSITION_NEW_CHAIN_HASH = keccak256("NewHyperchain(uint256,address)"); - - struct Config { - ContractsConfig contracts; - AddressesConfig addresses; - address deployerAddress; - address ownerAddress; - uint256 hyperchainChainId; - } - - struct ContractsConfig { - uint256 bridgehubCreateNewChainSalt; - PubdataPricingMode diamondInitPubdataPricingMode; - uint256 diamondInitBatchOverheadL1Gas; - uint256 diamondInitMaxPubdataPerBatch; - uint256 diamondInitMaxL2GasPerBatch; - uint256 diamondInitPriorityTxMaxPubdata; - uint256 diamondInitMinimalL2GasPrice; - bytes32 recursionNodeLevelVkHash; - bytes32 recursionLeafLevelVkHash; - bytes32 recursionCircuitsSetVksHash; - uint256 priorityTxMaxGasLimit; - bool validiumMode; - address validatorSenderOperatorCommitEth; - address validatorSenderOperatorBlobsEth; - uint128 baseTokenGasPriceMultiplierNominator; - uint128 baseTokenGasPriceMultiplierDenominator; - } - - // solhint-disable-next-line gas-struct-packing - struct AddressesConfig { - address baseToken; - address bridgehub; - address stateTransitionProxy; - address adminFacet; - address gettersFacet; - address mailboxFacet; - address executorFacet; - address verifier; - address blobVersionedHashRetriever; - address diamondInit; - address validatorTimelock; - address newDiamondProxy; - } - - Config internal config; - - function run() public { - console.log("Deploying Hyperchain"); - - initializeConfig(); - - checkTokenAddress(); - registerTokenOnBridgehub(); - registerHyperchain(); - addValidators(); - configureZkSyncStateTransition(); - } - - function initializeConfig() internal { - // Grab config from output of l1 deployment - string memory root = vm.projectRoot(); - string memory path = string.concat(root, "/script-out/output-deploy-l1.toml"); - string memory toml = vm.readFile(path); - - config.deployerAddress = msg.sender; - - // Config file must be parsed key by key, otherwise values returned - // are parsed alfabetically and not by key. - // https://book.getfoundry.sh/cheatcodes/parse-toml - config.ownerAddress = toml.readAddress("$.l1.owner_addr"); - - config.addresses.bridgehub = toml.readAddress("$.l1.bridgehub.bridgehub_proxy_addr"); - config.addresses.stateTransitionProxy = toml.readAddress("$.l1.state_transition.state_transition_proxy_addr"); - config.addresses.adminFacet = toml.readAddress("$.l1.state_transition.admin_facet_addr"); - config.addresses.gettersFacet = toml.readAddress("$.l1.state_transition.getters_facet_addr"); - config.addresses.mailboxFacet = toml.readAddress("$.l1.state_transition.mailbox_facet_addr"); - config.addresses.executorFacet = toml.readAddress("$.l1.state_transition.executor_facet_addr"); - config.addresses.verifier = toml.readAddress("$.l1.state_transition.verifier_addr"); - config.addresses.blobVersionedHashRetriever = toml.readAddress("$.l1.blob_versioned_hash_retriever_addr"); - config.addresses.diamondInit = toml.readAddress("$.l1.state_transition.diamond_init_addr"); - config.addresses.validatorTimelock = toml.readAddress("$.l1.validator_timelock_addr"); - - config.contracts.diamondInitPubdataPricingMode = PubdataPricingMode( - toml.readUint("$.l1.config.diamond_init_pubdata_pricing_mode") - ); - config.contracts.diamondInitBatchOverheadL1Gas = toml.readUint( - "$.l1.config.diamond_init_batch_overhead_l1_gas" - ); - config.contracts.diamondInitMaxPubdataPerBatch = toml.readUint( - "$.l1.config.diamond_init_max_pubdata_per_batch" - ); - config.contracts.diamondInitMaxL2GasPerBatch = toml.readUint("$.l1.config.diamond_init_max_l2_gas_per_batch"); - config.contracts.diamondInitPriorityTxMaxPubdata = toml.readUint( - "$.l1.config.diamond_init_priority_tx_max_pubdata" - ); - config.contracts.diamondInitMinimalL2GasPrice = toml.readUint("$.l1.config.diamond_init_minimal_l2_gas_price"); - config.contracts.recursionNodeLevelVkHash = toml.readBytes32("$.l1.config.recursion_node_level_vk_hash"); - config.contracts.recursionLeafLevelVkHash = toml.readBytes32("$.l1.config.recursion_leaf_level_vk_hash"); - config.contracts.recursionCircuitsSetVksHash = toml.readBytes32("$.l1.config.recursion_circuits_set_vks_hash"); - config.contracts.priorityTxMaxGasLimit = toml.readUint("$.l1.config.priority_tx_max_gas_limit"); - - // Grab config from l1 deployment config - root = vm.projectRoot(); - path = string.concat(root, "/script-config/config-deploy-l1.toml"); - toml = vm.readFile(path); - - config.hyperchainChainId = toml.readUint("$.hyperchain.hyperchain_chain_id"); - config.contracts.bridgehubCreateNewChainSalt = toml.readUint("$.hyperchain.bridgehub_create_new_chain_salt"); - config.addresses.baseToken = toml.readAddress("$.hyperchain.base_token_addr"); - config.contracts.validiumMode = toml.readBool("$.hyperchain.validium_mode"); - config.contracts.validatorSenderOperatorCommitEth = toml.readAddress( - "$.hyperchain.validator_sender_operator_commit_eth" - ); - config.contracts.validatorSenderOperatorBlobsEth = toml.readAddress( - "$.hyperchain.validator_sender_operator_blobs_eth" - ); - config.contracts.baseTokenGasPriceMultiplierNominator = uint128( - toml.readUint("$.hyperchain.base_token_gas_price_multiplier_nominator") - ); - config.contracts.baseTokenGasPriceMultiplierDenominator = uint128( - toml.readUint("$.hyperchain.base_token_gas_price_multiplier_denominator") - ); - } - - function checkTokenAddress() internal { - if (config.addresses.baseToken == address(0)) { - revert MissingAddress(ZksyncContract.BaseToken); - } - - // Check if it's ethereum address - if (config.addresses.baseToken == ADDRESS_ONE) { - return; - } - - if (config.addresses.baseToken.code.length == 0) { - revert AddressHasNoCode(config.addresses.baseToken); - } - - console.log("Using base token address:", config.addresses.baseToken); - } - - function registerTokenOnBridgehub() internal { - IBridgehub bridgehub = IBridgehub(config.addresses.bridgehub); - - if (bridgehub.tokenIsRegistered(config.addresses.baseToken)) { - console.log("Token already registered on Bridgehub"); - } else { - vm.broadcast(); - bridgehub.addToken(config.addresses.baseToken); - console.log("Token registered on Bridgehub"); - } - } - - function registerHyperchain() internal { - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](4); - facetCuts[0] = Diamond.FacetCut({ - facet: config.addresses.adminFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(config.addresses.adminFacet.code) - }); - facetCuts[1] = Diamond.FacetCut({ - facet: config.addresses.gettersFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(config.addresses.gettersFacet.code) - }); - facetCuts[2] = Diamond.FacetCut({ - facet: config.addresses.mailboxFacet, - action: Diamond.Action.Add, - isFreezable: true, - selectors: Utils.getAllSelectors(config.addresses.mailboxFacet.code) - }); - facetCuts[3] = Diamond.FacetCut({ - facet: config.addresses.executorFacet, - action: Diamond.Action.Add, - isFreezable: true, - selectors: Utils.getAllSelectors(config.addresses.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(config.addresses.verifier), - verifierParams: verifierParams, - l2BootloaderBytecodeHash: bytes32(Utils.getBatchBootloaderBytecodeHash()), - l2DefaultAccountBytecodeHash: bytes32(Utils.readSystemContractsBytecode("DefaultAccount")), - priorityTxMaxGasLimit: config.contracts.priorityTxMaxGasLimit, - feeParams: feeParams, - blobVersionedHashRetriever: config.addresses.blobVersionedHashRetriever - }); - - Diamond.DiamondCutData memory initData = Diamond.DiamondCutData({ - facetCuts: facetCuts, - initAddress: config.addresses.diamondInit, - initCalldata: abi.encode(initializeData) - }); - - IBridgehub bridgehub = IBridgehub(config.addresses.bridgehub); - - vm.broadcast(); - vm.recordLogs(); - bridgehub.createNewChain({ - _chainId: config.hyperchainChainId, - _stateTransitionManager: config.addresses.stateTransitionProxy, - _baseToken: config.addresses.baseToken, - _salt: config.contracts.bridgehubCreateNewChainSalt, - _admin: msg.sender, - _initData: abi.encode(initData) - }); - console.log("Hyperchain registered"); - - // Get new diamond proxy address from emitted events - Vm.Log[] memory logs = vm.getRecordedLogs(); - address diamondProxyAddress; - uint256 logsLength = logs.length; - for (uint256 i = 0; i < logsLength; ++i) { - if (logs[i].topics[0] == STATE_TRANSITION_NEW_CHAIN_HASH) { - diamondProxyAddress = address(uint160(uint256(logs[i].topics[2]))); - break; - } - } - if (diamondProxyAddress == address(0)) { - revert MissingAddress(ZksyncContract.DiamondProxy); - } - config.addresses.newDiamondProxy = diamondProxyAddress; - } - - function addValidators() internal { - ValidatorTimelock validatorTimelock = ValidatorTimelock(config.addresses.validatorTimelock); - - vm.startBroadcast(); - validatorTimelock.addValidator(config.hyperchainChainId, config.contracts.validatorSenderOperatorCommitEth); - validatorTimelock.addValidator(config.hyperchainChainId, config.contracts.validatorSenderOperatorBlobsEth); - vm.stopBroadcast(); - - console.log("Validators added"); - } - - function configureZkSyncStateTransition() internal { - IZkSyncHyperchain zkSyncStateTransition = IZkSyncHyperchain(config.addresses.newDiamondProxy); - - vm.startBroadcast(); - zkSyncStateTransition.setTokenMultiplier( - config.contracts.baseTokenGasPriceMultiplierNominator, - config.contracts.baseTokenGasPriceMultiplierDenominator - ); - - // TODO: support validium mode when available - // if (config.contractsMode) { - // zkSyncStateTransition.setValidiumMode(PubdataPricingMode.Validium); - // } - - vm.stopBroadcast(); - console.log("ZkSync State Transition configured"); - } -} diff --git a/l1-contracts-foundry/script/Utils.sol b/l1-contracts-foundry/script/Utils.sol deleted file mode 100644 index c694db463..000000000 --- a/l1-contracts-foundry/script/Utils.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.24; - -import {Vm} from "forge-std/Vm.sol"; -import {ZksyncContract, FailedToDeploy, BytecodeNotSet, FailedToDeployViaCreate2} from "./ZkSyncScriptErrors.sol"; - -library Utils { - // Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. - address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - // Create2Factory deterministic bytecode. - // https://github.com/Arachnid/deterministic-deployment-proxy - bytes internal constant CREATE2_FACTORY_BYTECODE = - hex"604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"; - - Vm internal constant vm = Vm(VM_ADDRESS); - - /** - * @dev Get all selectors from the bytecode. - * - * Selectors are extracted by calling `cast selectors ` from foundry. - * Then, the result is parsed to extract the selectors, removing - * the `getName()` selector if existing. - */ - function getAllSelectors(bytes memory bytecode) internal returns (bytes4[] memory) { - string[] memory input = new string[](3); - input[0] = "cast"; - input[1] = "selectors"; - input[2] = vm.toString(bytecode); - bytes memory result = vm.ffi(input); - string memory stringResult = string(abi.encodePacked(result)); - - // Extract selectors from the result - string[] memory parts = vm.split(stringResult, "\n"); - uint256 partsLength = parts.length; - bytes4[] memory selectors = new bytes4[](partsLength); - for (uint256 i = 0; i < partsLength; ++i) { - bytes memory part = bytes(parts[i]); - bytes memory extractedSelector = new bytes(10); - // Selector length 10 is 0x + 4 bytes - for (uint256 j = 0; j < 10; ++j) { - extractedSelector[j] = part[j]; - } - bytes4 selector = bytes4(vm.parseBytes(string(extractedSelector))); - selectors[i] = selector; - } - - // Remove `getName()` selector if existing - bool hasGetName = false; - uint256 selectorsLength = selectors.length; - for (uint256 i = 0; i < selectorsLength; ++i) { - if (selectors[i] == bytes4(keccak256("getName()"))) { - selectors[i] = selectors[selectorsLength - 1]; - hasGetName = true; - break; - } - } - if (hasGetName) { - bytes4[] memory newSelectors = new bytes4[](selectorsLength - 1); - for (uint256 i = 0; i < selectorsLength - 1; ++i) { - newSelectors[i] = selectors[i]; - } - return newSelectors; - } - - return selectors; - } - - /** - * @dev Extract an address from bytes. - */ - function bytesToAddress(bytes memory bys) internal pure returns (address addr) { - assembly { - addr := mload(add(bys, 20)) - } - } - - /** - * @dev Extract a uint256 from bytes. - */ - function bytesToUint256(bytes memory bys) internal pure returns (uint256 value) { - // Add left padding to 32 bytes if needed - uint256 bytesLength = bys.length; - if (bytesLength < 32) { - bytes memory padded = new bytes(32); - for (uint256 i = 0; i < bytesLength; ++i) { - padded[i + 32 - bytesLength] = bys[i]; - } - bys = padded; - } - - assembly { - value := mload(add(bys, 0x20)) - } - } - - /** - * @dev Returns the bytecode hash of the batch bootloader. - */ - function getBatchBootloaderBytecodeHash() internal view returns (bytes memory) { - return vm.readFileBinary("../system-contracts/bootloader/build/artifacts/proved_batch.yul.zbin"); - } - - /** - * @dev Returns the bytecode of a given system contract. - */ - function readSystemContractsBytecode(string memory filename) internal view returns (bytes memory) { - string memory file = vm.readFile( - // solhint-disable-next-line func-named-parameters - string.concat( - "../system-contracts/artifacts-zk/contracts-preprocessed/", - filename, - ".sol/", - filename, - ".json" - ) - ); - bytes memory bytecode = vm.parseJson(file, "$.bytecode"); - return bytecode; - } - - /** - * @dev Deploy a Create2Factory contract. - */ - function deployCreate2Factory() internal returns (address) { - address child; - bytes memory bytecode = CREATE2_FACTORY_BYTECODE; - vm.startBroadcast(); - assembly { - child := create(0, add(bytecode, 0x20), mload(bytecode)) - } - vm.stopBroadcast(); - if (child == address(0) || child.code.length == 0) { - revert FailedToDeploy(ZksyncContract.Create2Factory); - } - return child; - } - - /** - * @dev Deploys contract using CREATE2. - */ - function deployViaCreate2(bytes memory _bytecode, bytes32 _salt, address _factory) internal returns (address) { - if (_bytecode.length == 0) { - revert BytecodeNotSet(); - } - address contractAddress = vm.computeCreate2Address(_salt, keccak256(_bytecode), _factory); - if (contractAddress.code.length != 0) { - return contractAddress; - } - - vm.broadcast(); - (bool success, bytes memory data) = _factory.call(abi.encodePacked(_salt, _bytecode)); - contractAddress = Utils.bytesToAddress(data); - - if (!success || contractAddress == address(0) || contractAddress.code.length == 0) { - revert FailedToDeployViaCreate2(); - } - - return contractAddress; - } -}