diff --git a/.gitignore b/.gitignore index 88e59a65..574fbc45 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,9 @@ broadcast # Visual Studio Code .vscode + +# OS +.DS_Store + +# config +scripts/deterministic/config/config-contracts.toml \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index d2d6dd4b..5d7e99bf 100644 --- a/foundry.toml +++ b/foundry.toml @@ -14,8 +14,7 @@ optimizer = true # enable or disabl optimizer_runs = 200 # the number of optimizer runs verbosity = 2 # the verbosity of tests ignored_error_codes = [] # a list of ignored solc error codes -fuzz_runs = 256 # the number of fuzz runs for tests -ffi = false # whether to enable ffi or not +fuzz_runs = 256 # the number of fuzz runs for test sender = '0x00a329c0648769a73afac7f9381e08fb43dbea72' # the address of `msg.sender` in tests tx_origin = '0x00a329c0648769a73afac7f9381e08fb43dbea72' # the address of `tx.origin` in tests initial_balance = '0xffffffffffffffffffffffff' # the initial balance of the test contract @@ -28,3 +27,14 @@ block_timestamp = 0 # the value of `bl block_difficulty = 0 # the value of `block.difficulty` in tests gas_reports = ["L2GasPriceOracle"] + +# remove bytecode hash for reliable deterministic addresses +bytecode_hash = 'none' + +# file system permissions +ffi = true + +fs_permissions = [ + { access='read-write', path='./scripts/deterministic/config' }, + { access='read-write', path='../../config' }, +] \ No newline at end of file diff --git a/scripts/deterministic/Configuration.sol b/scripts/deterministic/Configuration.sol new file mode 100644 index 00000000..95ba45d7 --- /dev/null +++ b/scripts/deterministic/Configuration.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import {stdToml} from "forge-std/StdToml.sol"; + +import {CONFIG_PATH, CONFIG_CONTRACTS_PATH, CONFIG_CONTRACTS_TEMPLATE_PATH} from "./Constants.sol"; + +/// @notice Configuration allows inheriting contracts to read the TOML configuration file. +abstract contract Configuration is Script { + using stdToml for string; + + /******************* + * State variables * + *******************/ + + string internal cfg; + string internal contractsCfg; + + /**************************** + * Configuration parameters * + ****************************/ + + // general + string internal L1_RPC_ENDPOINT; + string internal L2_RPC_ENDPOINT; + + string internal CHAIN_NAME_L1; + string internal CHAIN_NAME_L2; + uint64 internal CHAIN_ID_L1; + uint64 internal CHAIN_ID_L2; + + uint256 internal MAX_TX_IN_CHUNK; + uint256 internal MAX_BLOCK_IN_CHUNK; + uint256 internal MAX_BATCH_IN_BUNDLE; + uint256 internal MAX_L1_MESSAGE_GAS_LIMIT; + uint256 internal FINALIZE_BATCH_DEADLINE_SEC; + uint256 internal RELAY_MESSAGE_DEADLINE_SEC; + + uint256 internal L1_CONTRACT_DEPLOYMENT_BLOCK; + + bool internal TEST_ENV_MOCK_FINALIZE_ENABLED; + uint256 internal TEST_ENV_MOCK_FINALIZE_TIMEOUT_SEC; + + // accounts + uint256 internal DEPLOYER_PRIVATE_KEY; + uint256 internal L1_COMMIT_SENDER_PRIVATE_KEY; + uint256 internal L1_FINALIZE_SENDER_PRIVATE_KEY; + uint256 internal L1_GAS_ORACLE_SENDER_PRIVATE_KEY; + uint256 internal L2_GAS_ORACLE_SENDER_PRIVATE_KEY; + + address internal DEPLOYER_ADDR; + address internal L1_COMMIT_SENDER_ADDR; + address internal L1_FINALIZE_SENDER_ADDR; + address internal L1_GAS_ORACLE_SENDER_ADDR; + address internal L2_GAS_ORACLE_SENDER_ADDR; + + address internal OWNER_ADDR; + + address internal L2GETH_SIGNER_ADDRESS; + + // db + string internal ROLLUP_EXPLORER_BACKEND_DB_CONNECTION_STRING; + + // genesis + uint256 internal L2_MAX_ETH_SUPPLY; + uint256 internal L2_DEPLOYER_INITIAL_BALANCE; + uint256 internal L2_SCROLL_MESSENGER_INITIAL_BALANCE; + + // contracts + string internal DEPLOYMENT_SALT; + + address internal L1_FEE_VAULT_ADDR; + + // coordinator + string internal CHUNK_COLLECTION_TIME_SEC; + string internal BATCH_COLLECTION_TIME_SEC; + string internal BUNDLE_COLLECTION_TIME_SEC; + string internal COORDINATOR_JWT_SECRET_KEY; + + // frontend + string internal EXTERNAL_RPC_URI_L1; + string internal EXTERNAL_RPC_URI_L2; + string internal BRIDGE_API_URI; + string internal ROLLUPSCAN_API_URI; + string internal EXTERNAL_EXPLORER_URI_L1; + string internal EXTERNAL_EXPLORER_URI_L2; + string internal ADMIN_SYSTEM_DASHBOARD_URI; + string internal GRAFANA_URI; + + /********************** + * Internal interface * + **********************/ + + function readConfig() internal { + if (!vm.exists(CONFIG_CONTRACTS_PATH)) { + string memory template = vm.readFile(CONFIG_CONTRACTS_TEMPLATE_PATH); + vm.writeFile(CONFIG_CONTRACTS_PATH, template); + } + + cfg = vm.readFile(CONFIG_PATH); + contractsCfg = vm.readFile(CONFIG_CONTRACTS_PATH); + + CHAIN_ID_L1 = uint64(cfg.readUint(".general.CHAIN_ID_L1")); + CHAIN_ID_L2 = uint64(cfg.readUint(".general.CHAIN_ID_L2")); + + MAX_TX_IN_CHUNK = cfg.readUint(".rollup.MAX_TX_IN_CHUNK"); + MAX_BLOCK_IN_CHUNK = cfg.readUint(".rollup.MAX_BLOCK_IN_CHUNK"); + MAX_BATCH_IN_BUNDLE = cfg.readUint(".rollup.MAX_BATCH_IN_BUNDLE"); + MAX_L1_MESSAGE_GAS_LIMIT = cfg.readUint(".rollup.MAX_L1_MESSAGE_GAS_LIMIT"); + FINALIZE_BATCH_DEADLINE_SEC = cfg.readUint(".rollup.FINALIZE_BATCH_DEADLINE_SEC"); + RELAY_MESSAGE_DEADLINE_SEC = cfg.readUint(".rollup.RELAY_MESSAGE_DEADLINE_SEC"); + + L1_CONTRACT_DEPLOYMENT_BLOCK = cfg.readUint(".general.L1_CONTRACT_DEPLOYMENT_BLOCK"); + + TEST_ENV_MOCK_FINALIZE_ENABLED = cfg.readBool(".rollup.TEST_ENV_MOCK_FINALIZE_ENABLED"); + TEST_ENV_MOCK_FINALIZE_TIMEOUT_SEC = cfg.readUint(".rollup.TEST_ENV_MOCK_FINALIZE_TIMEOUT_SEC"); + + DEPLOYER_PRIVATE_KEY = cfg.readUint(".accounts.DEPLOYER_PRIVATE_KEY"); + L1_COMMIT_SENDER_PRIVATE_KEY = cfg.readUint(".accounts.L1_COMMIT_SENDER_PRIVATE_KEY"); + L1_FINALIZE_SENDER_PRIVATE_KEY = cfg.readUint(".accounts.L1_FINALIZE_SENDER_PRIVATE_KEY"); + L1_GAS_ORACLE_SENDER_PRIVATE_KEY = cfg.readUint(".accounts.L1_GAS_ORACLE_SENDER_PRIVATE_KEY"); + L2_GAS_ORACLE_SENDER_PRIVATE_KEY = cfg.readUint(".accounts.L2_GAS_ORACLE_SENDER_PRIVATE_KEY"); + + DEPLOYER_ADDR = cfg.readAddress(".accounts.DEPLOYER_ADDR"); + L1_COMMIT_SENDER_ADDR = cfg.readAddress(".accounts.L1_COMMIT_SENDER_ADDR"); + L1_FINALIZE_SENDER_ADDR = cfg.readAddress(".accounts.L1_FINALIZE_SENDER_ADDR"); + L1_GAS_ORACLE_SENDER_ADDR = cfg.readAddress(".accounts.L1_GAS_ORACLE_SENDER_ADDR"); + L2_GAS_ORACLE_SENDER_ADDR = cfg.readAddress(".accounts.L2_GAS_ORACLE_SENDER_ADDR"); + + OWNER_ADDR = cfg.readAddress(".accounts.OWNER_ADDR"); + + L2GETH_SIGNER_ADDRESS = cfg.readAddress(".sequencer.L2GETH_SIGNER_ADDRESS"); + + L2_MAX_ETH_SUPPLY = cfg.readUint(".genesis.L2_MAX_ETH_SUPPLY"); + L2_DEPLOYER_INITIAL_BALANCE = cfg.readUint(".genesis.L2_DEPLOYER_INITIAL_BALANCE"); + L2_SCROLL_MESSENGER_INITIAL_BALANCE = L2_MAX_ETH_SUPPLY - L2_DEPLOYER_INITIAL_BALANCE; + + DEPLOYMENT_SALT = cfg.readString(".contracts.DEPLOYMENT_SALT"); + + L1_FEE_VAULT_ADDR = cfg.readAddress(".contracts.L1_FEE_VAULT_ADDR"); + + CHUNK_COLLECTION_TIME_SEC = cfg.readString(".coordinator.CHUNK_COLLECTION_TIME_SEC"); + BATCH_COLLECTION_TIME_SEC = cfg.readString(".coordinator.BATCH_COLLECTION_TIME_SEC"); + BUNDLE_COLLECTION_TIME_SEC = cfg.readString(".coordinator.BUNDLE_COLLECTION_TIME_SEC"); + COORDINATOR_JWT_SECRET_KEY = cfg.readString(".coordinator.COORDINATOR_JWT_SECRET_KEY"); + + runSanityCheck(); + } + + /// @dev Ensure that `addr` is not the zero address. + /// This helps catch bugs arising from incorrect deployment order. + function notnull(address addr) internal pure returns (address) { + require(addr != address(0), "null address"); + return addr; + } + + function tryGetOverride(string memory name) internal returns (address) { + address addr; + string memory key; + if (keccak256(abi.encodePacked(name)) == keccak256(abi.encodePacked("L1_GAS_TOKEN"))) { + key = string(abi.encodePacked(".gas-token.", name)); + } else { + key = string(abi.encodePacked(".contracts.overrides.", name)); + } + + if (!vm.keyExistsToml(cfg, key)) { + return address(0); + } + + addr = cfg.readAddress(key); + + if (addr.code.length == 0) { + (VmSafe.CallerMode callerMode, , ) = vm.readCallers(); + + // if we're ready to start broadcasting transactions, then we + // must ensure that the override contract has been deployed. + if (callerMode == VmSafe.CallerMode.Broadcast || callerMode == VmSafe.CallerMode.RecurrentBroadcast) { + revert( + string( + abi.encodePacked( + "[ERROR] override ", + name, + " = ", + vm.toString(addr), + " not deployed in broadcast mode" + ) + ) + ); + } + } + + return addr; + } + + /********************* + * Private functions * + *********************/ + + function runSanityCheck() private view { + verifyAccount("DEPLOYER", DEPLOYER_PRIVATE_KEY, DEPLOYER_ADDR); + verifyAccount("L1_COMMIT_SENDER", L1_COMMIT_SENDER_PRIVATE_KEY, L1_COMMIT_SENDER_ADDR); + verifyAccount("L1_FINALIZE_SENDER", L1_FINALIZE_SENDER_PRIVATE_KEY, L1_FINALIZE_SENDER_ADDR); + verifyAccount("L1_GAS_ORACLE_SENDER", L1_GAS_ORACLE_SENDER_PRIVATE_KEY, L1_GAS_ORACLE_SENDER_ADDR); + verifyAccount("L2_GAS_ORACLE_SENDER", L2_GAS_ORACLE_SENDER_PRIVATE_KEY, L2_GAS_ORACLE_SENDER_ADDR); + } + + function verifyAccount( + string memory name, + uint256 privateKey, + address addr + ) private pure { + if (vm.addr(privateKey) != addr) { + revert( + string( + abi.encodePacked( + "[ERROR] ", + name, + "_ADDR (", + vm.toString(addr), + ") does not match ", + name, + "_PRIVATE_KEY" + ) + ) + ); + } + } +} diff --git a/scripts/deterministic/Constants.sol b/scripts/deterministic/Constants.sol new file mode 100644 index 00000000..fb6781df --- /dev/null +++ b/scripts/deterministic/Constants.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +/// @dev The default deterministic deployment salt prefix. +string constant DEFAULT_DEPLOYMENT_SALT = "ScrollStack"; + +/// @dev The address of DeterministicDeploymentProxy. +/// See https://github.com/Arachnid/deterministic-deployment-proxy. +address constant DETERMINISTIC_DEPLOYMENT_PROXY_ADDR = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + +/// @dev The default minimum withdraw amount configured on L2TxFeeVault. +uint256 constant FEE_VAULT_MIN_WITHDRAW_AMOUNT = 1 ether; + +// input files +string constant CONFIG_PATH = "./scripts/deterministic/config/config.toml"; + +// template files +string constant CONFIG_CONTRACTS_TEMPLATE_PATH = "./scripts/deterministic/config/config-contracts.toml.template"; +string constant GENESIS_JSON_TEMPLATE_PATH = "../../config/genesis/config.json.template"; +string constant ROLLUP_CONFIG_TEMPLATE_PATH = "../../config/rollup-relayer/config.json.template"; +string constant COORDINATOR_CONFIG_TEMPLATE_PATH = "../../config/coordinator-api/config.json.template"; +string constant CHAIN_MONITOR_CONFIG_TEMPLATE_PATH = "../../config/chain-monitorv2/config.json.template"; +string constant BRIDGE_HISTORY_CONFIG_TEMPLATE_PATH = "../../config/bridge-historyv2-fetcher/config.json.template"; +string constant BALANCE_CHECKER_CONFIG_TEMPLATE_PATH = "../../config/balance-checker/config.json.template"; +string constant ROLLUP_EXPLORER_BACKEND_CONFIG_TEMPLATE_PATH = "../../config/rollup-explorer-backend/config.json.template"; +string constant ADMIN_SYSTEM_BACKEND_CONFIG_TEMPLATE_PATH = "../../config/scroll-admin-backend/config.json.template"; + +// output files +string constant CONFIG_CONTRACTS_PATH = "./scripts/deterministic/config/config-contracts.toml"; +string constant GENESIS_ALLOC_JSON_PATH = "../../config/__genesis-alloc.json"; +string constant GENESIS_JSON_PATH = "../../config/genesis/config.json"; +string constant ROLLUP_CONFIG_PATH = "../../config/rollup-relayer/config.json"; +string constant GAS_ORACLE_CONFIG_PATH = "../../config/rollup-relayer/config.json"; +string constant COORDINATOR_API_CONFIG_PATH = "../../config/coordinator-api/config.json"; +string constant COORDINATOR_CRON_CONFIG_PATH = "../../config/coordinator-cron/config.json"; +string constant CHAIN_MONITOR_CONFIG_PATH = "../../config/chain-monitorv2/config.json"; +string constant BRIDGE_HISTORY_API_CONFIG_PATH = "../../config/bridge-historyv2-api/config.json"; +string constant BRIDGE_HISTORY_FETCHER_CONFIG_PATH = "../../config/bridge-historyv2-fetcher/config.json"; +string constant BALANCE_CHECKER_CONFIG_PATH = "../../config/balance-checker/config.json"; +string constant ROLLUP_EXPLORER_BACKEND_CONFIG_PATH = "../../config/rollup-explorer-backend/config.json"; +string constant ADMIN_SYSTEM_BACKEND_CONFIG_PATH = "../../config/scroll-admin-backend/config.json"; +string constant ADMIN_SYSTEM_CRON_CONFIG_PATH = "../../config/scroll-admin-cron/config.json"; + +// verifier 0.2.0 VERIFIER_DIGEST +// https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.2.0/bundle/digest_2.hex +bytes32 constant VERIFIER_DIGEST = 0x0038553adf417a6a3df35d2fdfd14b892f1e49ba18937ece7960c1e7cee6e3dc; + +// openvm verifier 0.2.0 creation code +// https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/0.2.0/bundle/verifier.bin +bytes constant PLONK_VERIFIER_CREATION_CODE = hex"608060405234801561001057600080fd5b50614842806100206000396000f3fe608060405234801561001057600080fd5b5060003660606040516080811461002657600080fd5b60017f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd477f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610162565b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4782107f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478410808216925050507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478384097f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478384097f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478482097f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47600382088381148086169550505050505092915050565b806000350660a052806020350660c052806040350660e0528060603506610100528060803506610120528060a03506610140528060c03506610160528060e03506610180528061010035066101a0528061012035066101c0528061014035066101e0528061016035066102005280610180350661022052806101a0350661024052806101c0350661026052806101e03506610280528061020035066102a0528061022035066102c0528061024035066102e0528061026035066103005280610280350661032052806102a0350661034052806102c0350661036052806102e03506610380528061030035066103a0528061032035066103c0528061034035066103e0528061036035066104005280610380350661042052806103a0350661044052806103c0350661046052806103e03506610480528061040035066104a0528061042035066104c0528061044035066104e0528061046035066105005280610480350661052052806104a0350661054052806104c0350661056052806104e03506610580528061050035066105a0528061052035066105c0528061054035066105e0528061056035066106005280610580350661062052806105a03506610640527f2afa0dd006fb6a9768832d01002e379b45e16c96954f9531f4045dd440c668386080526105c03580610660526105e035806106805284610364828461006f565b16945050506106206080206106a0526106a0518181066106c052806106e05250610600358061070052610620358061072052846103a1828461006f565b1694505050610640358061074052610660358061076052846103c3828461006f565b169450505060a06106e02061078052610780518181066107a052806107c0525060016107e05360216107c0206107e0526107e051818106610800528061082052506106803580610840526106a035806108605284610421828461006f565b16945050506106c03580610880526106e035806108a05284610443828461006f565b169450505061070035806108c05261072035806108e05284610465828461006f565b169450505060e061082020610900526109005181810661092052806109405250610740358061096052610760358061098052846104a2828461006f565b169450505061078035806109a0526107a035806109c052846104c4828461006f565b16945050506107c035806109e0526107e03580610a0052846104e6828461006f565b16945050506108003580610a20526108203580610a405284610508828461006f565b169450505061012061094020610a6052610a6051818106610a805280610aa05250806108403506610ac052806108603506610ae052806108803506610b0052806108a03506610b2052806108c03506610b4052806108e03506610b6052806109003506610b8052806109203506610ba052806109403506610bc052806109603506610be052806109803506610c0052806109a03506610c2052806109c03506610c4052806109e03506610c605280610a003506610c805280610a203506610ca05280610a403506610cc05280610a603506610ce05280610a803506610d0052610280610aa020610d2052610d2051818106610d405280610d6052506001610d80536021610d6020610d8052610d8051818106610da05280610dc05250610aa03580610de052610ac03580610e005284610641828461006f565b16945050506060610dc020610e2052610e2051818106610e405280610e605250610ae03580610e8052610b003580610ea0528461067e828461006f565b169450505060a05160c05160581b8101905060e05160b01b8101905080610ec052610100516101205160581b810190506101405160b01b8101905080610ee052846106c9828461006f565b1694505050610160516101805160581b810190506101a05160b01b8101905080610f00526101c0516101e05160581b810190506102005160b01b8101905080610f205284610717828461006f565b169450505080610a8051610a805109610f405280610f4051610f405109610f605280610f6051610f605109610f805280610f8051610f805109610fa05280610fa051610fa05109610fc05280610fc051610fc05109610fe05280610fe051610fe05109611000528061100051611000510961102052806110205161102051096110405280611040516110405109611060528061106051611060510961108052806110805161108051096110a052806110a0516110a051096110c052806110c0516110c051096110e052806110e0516110e05109611100528061110051611100510961112052806111205161112051096111405280611140516111405109611160528061116051611160510961118052806111805161118051096111a052806111a0516111a051096111c052806111c0516111c051096111e052807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000006111e0510861120052807f30644db14ff7d4a4f1cf9ed5406a7e5722d273a7aa184eaa5e1fb0846829b041611200510961122052807f1d3d878f52016737bda697d23b0cee81488efd02d67b27eae3edab5f39ef347d611220510961124052807f1326c6e38f3038f1faa9ade4467469dbdfa4eb45a33e48a65ff44a34b610cb84610a80510861126052807f182fa146dab5070e1897c235ff7425a25d09f820206545e69bf946c2f6057429611220510961128052807f1834ad2c067c991b9fb88380820d32bacb29f02859542aaaa7e8aed0f9fa8bd8610a8051086112a052807f185afb17aed5e3d828526ac8e534436afa30f7196772de397fd9b6be79fe8c9361122051096112c052807f1809535b325bbc518ffddaed9c4d14f22e02f12f12469257c4083ed57601736e610a8051086112e052807f220db0d8bf832baf9eecbf4fa49947e0b2a3d31df0a733ea5ae8abbdab442d5f611220510961130052807f0e569d9a21ae747a19638666dce8107c7590152a89123ca6e8f949d644bbd2a2610a80510861132052807f2fffa2b50d66f628412d9782f09d3386d766a1168304babe2165fe7ec962e65b611220510961134052807e64abbdd3caaa017722ae3390e424d650cd4731f6b4b5d3227bf715269d19a6610a80510861136052807f06288b9d40ec1915c3a20817de7179beeccf4c4fd02f202c064a0cc13e38c2f8611220510961138052807f2a3bc2d5a0458713f4ae3d9ea30fde9e3b649bf8a98a50653d97e8d2b1c73d09610a8051086113a052807f134f571fe34eb8c7b1685e875b324820e199bd70157493377cd65b204d1a396461122051096113c052807f1d14f752fde2e76206e7e72f264f103c469a2ad86444dd59c70b9a73a2e5c69d610a8051086113e052806001611220510961140052807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000610a80510861142052807f18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bede611220510961144052807f179aef57fae05218169d35deef48109728652313faa28775f60ba17d6cd94123610a80510861146052807f032750f8f3c2493d0828c7285d0258e1bdcaa463f4442a52747b5c96639659bb611220510961148052807f2d3cfd79ed6f56ecb0277e8e247eff7b6a6943e48575463ecf6698fd8c69a646610a8051086114a052807f1be6734ccb6588d60d469def6bf0b0f39af67bb568a3b63e3773e3dd306ba07061122051096114c052807f147ddb2615cc1753ab09a7c71590a7698d3d6c931115ba530c6e11b6bf945f91610a8051086114e052807f2a14464f1ff42de3856402b62520e670745e39fada049d5b2f0e1e3182673378611220510961150052807f06500823c13d724632ec43005c6071ecb3d5ae4d9fb4d33614d3d7626d98cc89610a80510861152052807f0205f4c81bd8bfadd87e3771dc61e489caf1a2f61f6fe94419612b1039f806ba611220510961154052807f2e5e59aac558e07bdfd20e44a51f73d35d4245525a49874d2a80ca83b607f947610a80510861156052807f085386d3273d6903e6ca9388a9b29e81643977d523db6f6db1fdc5acf965b809611220510961158052807f2810c79fb9f43725d185b22dd7ceb9dbc3fa707355de012391e42fe6f69a47f8610a8051086115a052807f0962d59f2fea9851331073aa7b9a65add88e25cdcf9a7908665722e5c57e1c2561122051096115c052807f270178d3b14707d8853fd20c05e6f2af4fa5c27aaa1ef788dd8ad2ae2a81e3dc610a8051086115e052807f0cf1526aaafac6bacbb67d11a4077806b123f767e4b0883d14cc0193568fc082611220510961160052807f2372fc083636d96eec99c8a4dd79e056770ff0e09508e8542f15f40099703f7f610a80510861162052807f0d38d63833e51358021fc5aeb30483105d8b48022cd28fc4ccc55739e57166f4611220510961164052807f232b783aad4c8cd1b6308007ce7cd54ccaa8a0464ce6e0cc771c9e5a0a8e990d610a80510861166052807f202efdf29fbbf7251b99f728e6317b3a58a0e579b827f9d622ab713b5d76ba5e611220510961168052807f103550804175a9049cb64e8d9b4fdd22cf9302cec19176bb21368458928945a3610a8051086116a052807f1df73deb96a4785f63b25489c52178d4b3f95e41d1a1d6aec678d35d2d2095b861122051096116c052807f126d10874a8d27ca549df12cbc5fdf88743a8a06a81799e27d692236c2df6a49610a8051086116e052807f157057e61fa68c20f015bccca35a72daa53b29abd151cfa1431a92029ece5c0e611220510961170052807f1af3f68cc18b1408c83a88e9de26e58282f8be9ca867a0f000c763915131a3f3610a80510861172052807f17e4f62c667b201826284c6918cfd09f571a62f09dfca2d54702a220c92f178b611220510961174052807f187f58467ab680119227f94d68b187bdd1198557dbbccdbbfcdf537326d0e876610a80510861176052807f1b8c0911077b8645a2dcd11044ecedef18d199a893d5f3814f789252af93e53c611220510961178052807f14d84561d9b619e4157374a63c946a6e0f624e9fe5e37d0ff4696341406c1ac5610a8051086117a052807f23755b45f23db9743c690e5570b1e2983e8369f76981f85609c5154a03a922df61122051096117c052807f0ceef32ceef3e6b57be7376110cf75c4e9b07e511037783b3a1ce049ec56dd22610a8051086117e052807f0f60c8fe0414cb9379b2d39267945f6bd60d06a05216231b26a9fcf88ddbfebe611220510961180052807f21038574dd1cd4963e9d722419ecf8f15226e1a827a34d761d37f89b62240143610a80510861182052807f1dd804edc273c3b32894f7d1f5ad573c785b068883b719276149bcfcbd7c8735611220510961184052807f128c49851ebddc768fbb4de48bd40120afd8e1bff6025769e2983897328378cc610a80510861186052807f2cfb3ee365fa96d90152e17588a5c8109aba50a36f0e6cc5d38caa708844f09d611220510961188052807f03690f8f7b370950b6fd6440f8db904c8d7997a50aab03cb70554b2367bb0f64610a8051086118a052807f01bf77e1640452989576495d56797caee1f6c4a3529d7ad6cf9f068ba23f509561122051096118c052807f2ea4d6917d2d4d9122d9fc592b07dbae463d23a5271bf5ba7442ef084dc0af6c610a8051086118e052807f0bb1b800e0fc2016082cf25a117ee7ebc61bdc048d093fbf025ec0794556abea611220510961190052807f24b2967200358013b023535c7002707162180c43ecb030d24183351aaaa95417610a80510861192052807f2184edd1ba10180eb3174c08e41cd0981126e96545bbe8fa6be74d0f5139a939611220510961194052807f0edf60a12721881b0538f9ad9d6487c5170cfee333fd8796d7faa8849ec656c8610a80510861196052807f013b926b615dadae89c76ce93dbd4b79cd3fad8e402744b6151a79df33fb48e3611220510961198052807f2f28bc077fd3f27b2e88d8cd43c40ce35af43aba39922bdb2ec77bb4bc04b71e610a8051086119a052807f24b9e65b23e30a1fb8b8ea2a50caa34abf79322f88ecc1e5c72c863f6fbebd1761122051096119c052807f0baa6817bd4e9609ff975b8c30b6b51268bab618f0ccaeab7cb56f54804142ea610a8051086119e052807f09f83b8b9c5b192f9193a231814c3163b9b8c636b1d40961a83ac1f42dc63b266112205109611a0052807f266c12e744d686fa26bca385003526f96e7b2211c7e5672f9ba7339fc239c4db610a805108611a2052807f0f2e46e84503e0bec563379085b7d3ef78102bd590fbd619be21ce2c1b9945bf6112205109611a4052807f2136078a9c2dbf6af2ed0e25fbc9846db023bc72e8bd9a7785c02767d466ba42610a805108611a6052807f2c9741ded62f041c7cc95ad55d1d3649468d8a5ec530f048bbeeffdfd0a9d6526112205109611a8052807f03cd0c940b029c0d3b86eae124642213e1a65de9b488804887f2f5b41f5629af610a805108611aa052807f20e2808bc9ff5d255ed9de0f29147692fff955773b6ad07c69f232bfd55f00596112205109611ac052807f0f81cde717324304597667a7586ce1ca283a92d13e4ea014d9efc2d41aa0ffa8610a805108611ae052807f05b432e46216fc6bed772f92cde45c9ebc2d8703af094c331522356351ce2c776112205109611b0052807f2ab01b8e7f1aa3bdcad91623b39cfbbe6c066144cab0245e2ebfc0309e31d38a610a805108611b2052807f259c031d10081ea697e9997cdcf8c47964c227e4fb4e77e807713f00585956de6112205109611b4052807f0ac84b55d12981832066ac39a48893e3c371c0637e6af8a93c70b69397a6a923610a805108611b6052807f04290a1d7601de8e3c98923f48b2304f4ca974f5376d42c80bbec5eb53070bc56112205109611b8052807f2c3b44556b2fc19b7bb7b37738cf280ddb8a7353424c2dc938232fa89cf8f43c610a805108611ba052807f2fe46b4c6e0df90591d8336da5638fb4c1859ede12103bc04dd0e995a9d8e77d6112205109611bc052807e7fe3267323a72426781248dc1dc8a866ae496a67a934d0f6110bfe46271884610a805108611be052807f304cd1e79cfa5b0f054e981a27ed7706e7ea6b06a7f266ef8db819c179c2c3ea6112205109611c0052807e177c8b4437451ab301ad9c5993e15640497d41d1c709a1b629dbd2763d3c17610a805108611c2052807f1a05ef04e20b042a06c61577a4a9b54771c327c3672c0357d55d04e22aa2f1c96112205109611c4052807f165e5f6dff269bffb18a303edcd7a315b670c085128d6d396e84f0b1c55d0e38610a805108611c6052807f1cc839f9cc5012a73f3b56e2417eb951f46c04af98489f776d1dd847b247f2b56112205109611c8052807f139c147914e18d827914eed440029f0b33c7e398e170d119d6c41d4c3db80d4c610a805108611ca052807f0baa43683ba5a5fa31558c98a045a4b0109b2efb97fe1e2d352c28456d499def6112205109611cc052807f24ba0b0aa58bfa2f86fab91de13bb3ad1798b94ce1bb52640eb5cd4e82b66212610a805108611ce052807f033a1069fe5e06d412520dc1eb795e5c1a9fbf099908ee0d7891c86e2e2746c56112205109611d0052807f2d2a3e08e2d39955a5fe37f49607fa010d94293ee0b08283cb502d25c1d8b93c610a805108611d2052807f07102fcd8e37f581514a697a842c2f7a57aa1ca017fd7c2c81c4481ef51a4af86112205109611d4052807f29541ea552f9aaa86705dc3bfd5528e2d089cba861bbf464c21dad74fae5b509610a805108611d6052807f06d5223674254f4051450d63a7815877be218cff2ae41bf96a519f97d5f893696112205109611d8052807f298f2c3c6d0c50e9670b3852d9ffffe56a125b494ed55497d99055fc1a076c98610a805108611da052807f2336c94d73c29901a712ac079b7f50d62e10f1d075badfbbf438f74afbbabe9d6112205109611dc052807f0d2d85256d6f0728113d99aee6020786fa22f67803fe90d54fa8fe48f4454164610a805108611de052807f2fbe09de40a6ef2c32ad177045a51c5033c7186172461c2658a0f93cf36bfa3f6112205109611e0052807ea64494a08ab0fd85a32e463bdc3c0cf46ccfe70773546aeb40fc56fc9405c2610a805108611e2052807f292ec9ad99cfce95b2da745a36ddf7b05337dd83ece3597760f62c2ebf21c3106112205109611e4052807f073584c54761d1940575d15c4aa360acd4fc0ac48cd61719e2ebc96530de3cf1610a805108611e6052807f21ae116f5f57a4cc6e3f8d02345f04778d257b7e8200f6cfe5c69aa1692cc8fb6112205109611e8052807f0eb63d0381d9fb5d4a10b8b44d2253e59b0e6cc9f7b879c15e1b5af286d33706610a805108611ea052807f1bfee385b2c5cfc01238741207046900bb91b5598bc6cc1cf2f5c1019ec024016112205109611ec052807f14656aed2e6bd069a617d1a47a7cef5c6ca232eeedf2a47450ec3492513fdc00610a805108611ee052807f146723ce0d2732187545ca1441a36f872027c0262cd646a42fa20c7f648a061e6112205109611f0052807f1bfd2aa4d40a6e11430a7ba23fdde8d6080c28224ce329ed143fe9148b75f9e3610a805108611f2052807f0f4411b99f1a27148940c80178d5446f0c54afb342542fd6b7d56e8c8c4cb5cc6112205109611f4052807f21203cb9421779152f0f7db508ac13ee1bdf3895376540ba8c0c870763b34a35610a805108611f60526112605181816112a05109905080611f805281816112e05109905080611fa05281816113205109905080611fc05281816113605109905080611fe05281816113a051099050806120005281816113e05109905080612020528181611420510990508061204052818161146051099050806120605281816114a051099050806120805281816114e051099050806120a052818161152051099050806120c052818161156051099050806120e05281816115a051099050806121005281816115e05109905080612120528181611620510990508061214052818161166051099050806121605281816116a051099050806121805281816116e051099050806121a052818161172051099050806121c052818161176051099050806121e05281816117a051099050806122005281816117e05109905080612220528181611820510990508061224052818161186051099050806122605281816118a051099050806122805281816118e051099050806122a052818161192051099050806122c052818161196051099050806122e05281816119a051099050806123005281816119e05109905080612320528181611a205109905080612340528181611a605109905080612360528181611aa05109905080612380528181611ae051099050806123a0528181611b2051099050806123c0528181611b6051099050806123e0528181611ba05109905080612400528181611be05109905080612420528181611c205109905080612440528181611c605109905080612460528181611ca05109905080612480528181611ce051099050806124a0528181611d2051099050806124c0528181611d6051099050806124e0528181611da05109905080612500528181611de05109905080612520528181611e205109905080612540528181611e605109905080612560528181611ea05109905080612580528181611ee051099050806125a0528181611f2051099050806125c0528181611f6051099050806125e052818161120051099050806126005250602061264052602061266052602061268052612600516126a0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff6126c0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016126e052826001602061262060c061264060055afa1416925061262051600061120051905082826125e0510961120052828282099150611f6051905082826125c05109611f6052828282099150611f2051905082826125a05109611f2052828282099150611ee051905082826125805109611ee052828282099150611ea051905082826125605109611ea052828282099150611e6051905082826125405109611e6052828282099150611e2051905082826125205109611e2052828282099150611de051905082826125005109611de052828282099150611da051905082826124e05109611da052828282099150611d6051905082826124c05109611d6052828282099150611d2051905082826124a05109611d2052828282099150611ce051905082826124805109611ce052828282099150611ca051905082826124605109611ca052828282099150611c6051905082826124405109611c6052828282099150611c2051905082826124205109611c2052828282099150611be051905082826124005109611be052828282099150611ba051905082826123e05109611ba052828282099150611b6051905082826123c05109611b6052828282099150611b2051905082826123a05109611b2052828282099150611ae051905082826123805109611ae052828282099150611aa051905082826123605109611aa052828282099150611a6051905082826123405109611a6052828282099150611a2051905082826123205109611a20528282820991506119e0519050828261230051096119e0528282820991506119a051905082826122e051096119a05282828209915061196051905082826122c051096119605282828209915061192051905082826122a05109611920528282820991506118e0519050828261228051096118e0528282820991506118a0519050828261226051096118a052828282099150611860519050828261224051096118605282828209915061182051905082826122205109611820528282820991506117e0519050828261220051096117e0528282820991506117a051905082826121e051096117a05282828209915061176051905082826121c051096117605282828209915061172051905082826121a05109611720528282820991506116e0519050828261218051096116e0528282820991506116a0519050828261216051096116a052828282099150611660519050828261214051096116605282828209915061162051905082826121205109611620528282820991506115e0519050828261210051096115e0528282820991506115a051905082826120e051096115a05282828209915061156051905082826120c051096115605282828209915061152051905082826120a05109611520528282820991506114e0519050828261208051096114e0528282820991506114a0519050828261206051096114a052828282099150611460519050828261204051096114605282828209915061142051905082826120205109611420528282820991506113e0519050828261200051096113e0528282820991506113a05190508282611fe051096113a0528282820991506113605190508282611fc05109611360528282820991506113205190508282611fa05109611320528282820991506112e05190508282611f8051096112e0528282820991506112a0519050828261126051096112a052828282099150816112605250508061126051611240510961270052806112a051611280510961272052806112e0516112c051096127405280611320516113005109612760528061136051611340510961278052806113a05161138051096127a052806113e0516113c051096127c052806114205161140051096127e0528061146051611440510961280052806114a051611480510961282052806114e0516114c051096128405280611520516115005109612860528061156051611540510961288052806115a05161158051096128a052806115e0516115c051096128c052806116205161160051096128e0528061166051611640510961290052806116a051611680510961292052806116e0516116c051096129405280611720516117005109612960528061176051611740510961298052806117a05161178051096129a052806117e0516117c051096129c052806118205161180051096129e05280611860516118405109612a0052806118a0516118805109612a2052806118e0516118c05109612a405280611920516119005109612a605280611960516119405109612a8052806119a0516119805109612aa052806119e0516119c05109612ac05280611a2051611a005109612ae05280611a6051611a405109612b005280611aa051611a805109612b205280611ae051611ac05109612b405280611b2051611b005109612b605280611b6051611b405109612b805280611ba051611b805109612ba05280611be051611bc05109612bc05280611c2051611c005109612be05280611c6051611c405109612c005280611ca051611c805109612c205280611ce051611cc05109612c405280611d2051611d005109612c605280611d6051611d405109612c805280611da051611d805109612ca05280611de051611dc05109612cc05280611e2051611e005109612ce05280611e6051611e405109612d005280611ea051611e805109612d205280611ee051611ec05109612d405280611f2051611f005109612d605280611f6051611f405109612d80528060a0516127e0510981818360c051612800510908905081818360e0516128205109089050818183610100516128405109089050818183610120516128605109089050818183610140516128805109089050818183610160516128a05109089050818183610180516128c051090890508181836101a0516128e051090890508181836101c05161290051090890508181836101e0516129205109089050818183610200516129405109089050818183610220516129605109089050818183610240516129805109089050818183610260516129a05109089050818183610280516129c051090890508181836102a0516129e051090890508181836102c051612a0051090890508181836102e051612a20510908905081818361030051612a40510908905081818361032051612a60510908905081818361034051612a80510908905081818361036051612aa0510908905081818361038051612ac051090890508181836103a051612ae051090890508181836103c051612b0051090890508181836103e051612b20510908905081818361040051612b40510908905081818361042051612b60510908905081818361044051612b80510908905081818361046051612ba0510908905081818361048051612bc051090890508181836104a051612be051090890508181836104c051612c0051090890508181836104e051612c20510908905081818361050051612c40510908905081818361052051612c60510908905081818361054051612c80510908905081818361056051612ca0510908905081818361058051612cc051090890508181836105a051612ce051090890508181836105c051612d0051090890508181836105e051612d20510908905081818361060051612d40510908905081818361062051612d60510908905081818361064051612d80510908905080612da0525080610ae051610b005109612dc05280612dc051610ac05108612de05280610b20518203612de05108612e005280610b8051612e005109612e205280612e20516109205109612e405280610c40518203600108612e6052806127e051612e605109612e805280612e8051612e405108612ea05280612ea0516109205109612ec05280610c4051610c405109612ee05280610c40518203612ee05108612f00528061270051612f005109612f205280612f2051612ec05108612f405280612f40516109205109612f605280612700518203600108612f805280612740516127205108612fa0528061276051612fa05108612fc0528061278051612fc05108612fe052806127a051612fe0510861300052806127c05161300051086130205280613020518203612f80510861304052806107a051610be05109613060528061306051610b40510861308052806108005161308051086130a052806107a051610c0051096130c052806130c051610ac051086130e05280610800516130e0510861310052806130a051613100510961312052806107a051610c205109613140528061314051612da05108613160528061080051613160510861318052806131205161318051096131a05280610c60516131a051096131c052806107a0516001096131e052806131e051610a805109613200528061320051610b405108613220528061080051613220510861324052806107a0517f09226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a209613260528061326051610a805109613280528061328051610ac051086132a05280610800516132a051086132c05280613240516132c051096132e052806107a0517f13b360d4e82fe915fed16081038f98c211427b87a281bd733c277dbadf10372b09613300528061330051610a805109613320528061332051612da05108613340528061080051613340510861336052806132e05161336051096133805280610c405161338051096133a052806133a05182036131c051086133c05280613040516133c051096133e052806133e051612f60510861340052806134005161092051096134205280610c8051820360010861344052806127e0516134405109613460528061346051613420510861348052806134805161092051096134a05280610c8051610c8051096134c05280610c805182036134c051086134e05280612700516134e051096135005280613500516134a05108613520528061352051610920510961354052806107a051610cc051086135605280610ca0516135605109613580528061080051610d0051086135a05280613580516135a051096135c05280610ba051610ac051096135e052806107a0516135e051086136005280610c80516136005109613620528061080051610b605108613640528061362051613640510961366052806136605182036135c0510861368052806130405161368051096136a052806136a05161354051086136c052806136c05161092051096136e05280610d00518203610cc0510861370052806127e05161370051096137205280613720516136e05108613740528061374051610920510961376052806130405161370051096137805280610ce0518203610cc051086137a05280613780516137a051096137c052806137c05161376051086137e052806111e0516111e0510961380052806111e051613800510961382052806111e051613820510961384052806111e0516001096138605280613800516001096138805280613820516001096138a05280611200516137e051096138c05280610a8051610f4051096138e05280610a80516138e0510961390052807f134f571fe34eb8c7b1685e875b324820e199bd70157493377cd65b204d1a3964610a8051096139205280613920518203610e40510861394052806001610a8051096139605280613960518203610e40510861398052807f18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bede610a8051096139a052806139a0518203610e4051086139c052807f032750f8f3c2493d0828c7285d0258e1bdcaa463f4442a52747b5c96639659bb610a8051096139e052806139e0518203610e405108613a0052807f1be6734ccb6588d60d469def6bf0b0f39af67bb568a3b63e3773e3dd306ba070610a805109613a205280613a20518203610e405108613a4052806138e0517f07d604303a7bed3ecd3bcf9f68948bd11d7cfb83623e03c3d41fd2e7dc3c699109613a6052806001613a605109613a805280613a6051610e405109818183613a80518503610a80510908905080613aa05250806138e0517f0888e470b16311ed8fe253a4ea4c86161e449ca748456e7e35c5e51c92b691b909613ac052807f18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bede613ac05109613ae05280613ac051610e405109818183613ae0518503610a80510908905080613b005250806138e0517f2fcabb9b6c70a7190da3d756fc7c6c21f286a22d2029c27d5ebffb1638ea8d6f09613b2052807f032750f8f3c2493d0828c7285d0258e1bdcaa463f4442a52747b5c96639659bb613b205109613b405280613b2051610e405109818183613b40518503610a80510908905080613b605250806138e0517f071875f8c967190753f4712b28f4bf6278328c0809585ee0629d98255557240f09613b8052807f1be6734ccb6588d60d469def6bf0b0f39af67bb568a3b63e3773e3dd306ba070613b805109613ba05280613b8051610e405109818183613ba0518503610a80510908905080613bc052508061398051600109613be052806139c051613be05109613c005280613a0051613c005109613c205280613a4051613c205109613c405280610a80517f179aef57fae05218169d35deef48109728652313faa28775f60ba17d6cd9412409613c6052806001613c605109613c805280613c6051610e405109818183613c80518503610a80510908905080613ca0525080610a80517f18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bedd09613cc052807f18c95f1ae6514e11a1b30fd7923947c5ffcec5347f16e91b4dd654168326bede613cc05109613ce05280613cc051610e405109818183613ce0518503610a80510908905080613d00525080610a80517f1d14f752fde2e76206e7e72f264f103c469a2ad86444dd59c70b9a73a2e5c69e09613d2052806001613d205109613d405280613d2051610e405109818183613d40518503610a80510908905080613d60525080610a80517f134f571fe34eb8c7b1685e875b324820e199bd70157493377cd65b204d1a396309613d8052807f134f571fe34eb8c7b1685e875b324820e199bd70157493377cd65b204d1a3964613d805109613da05280613d8051610e405109818183613da0518503610a80510908905080613dc052508061394051613be05109613de052806001610e4051098181837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000610a80510908905080613e005250613aa0518181613b005109905080613e20528181613b605109905080613e40528181613bc05109905080613e60528181613ca05109905080613e80528181613d005109905080613ea0528181613c005109905080613ec0528181613d605109905080613ee0528181613dc05109905080613f00528181613de05109905080613f20528181613e005109905080613f40528181613be05109905080613f6052506020613fa0526020613fc0526020613fe052613f6051614000527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff614020527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001614040528260016020613f8060c0613fa060055afa14169250613f80516000613be05190508282613f405109613be052828282099150613e005190508282613f205109613e0052828282099150613de05190508282613f005109613de052828282099150613dc05190508282613ee05109613dc052828282099150613d605190508282613ec05109613d6052828282099150613c005190508282613ea05109613c0052828282099150613d005190508282613e805109613d0052828282099150613ca05190508282613e605109613ca052828282099150613bc05190508282613e405109613bc052828282099150613b605190508282613e205109613b6052828282099150613b005190508282613aa05109613b005282828209915081613aa0525050613aa0518181613b00510890508181613b60510890508181613bc05108905080614060525080613c0051613c40510961408052613ca0518181613d0051089050806140a0525080613de051613c4051096140c052613d60518181613dc051089050806140e0525080613be051613c40510961410052613e00518061412052506140605181816140a051099050806141405281816140e051099050806141605281816141205109905080614180525060206141c05260206141e05260206142005261418051614220527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff614240527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016142605282600160206141a060c06141c060055afa141692506141a051600061412051905082826141605109614120528282820991506140e0519050828261414051096140e0528282820991506140a0519050828261406051096140a05282828209915081614060525050806140a051614080510961428052806140e0516140c051096142a052806141205161410051096142c05280610d4051610d4051096142e05280610d40516142e051096143005280610d405161430051096143205280610d405161432051096143405280610d405161434051096143605280610d405161436051096143805280610d405161438051096143a05280610d40516143a051096143c05280610d40516143c051096143e05280610da051610da051096144005280610da05161440051096144205280610da05161442051096144405280613aa051610ac05109818183613b0051610ae05109089050818183613b6051610b005109089050818183613bc051610b2051090890508061446052508061406051614460510961448052806001614480518303096144a0528060016144a051096144c05280614080516001096144e05280613ca051610c405109818183613d0051610c605109089050806145005250806142805161450051096145205280600161452051830309614540528060016144e051096145605280613ca051610c805109818183613d0051610ca05109089050806145805250806142805161458051096145a05280610d40516145a0518303096145c05280610d40516144e051096145e052806145c05161454051086146005280610da05161460051096146205280610da05161456051096146405280610da0516145e051096146605280614620516144c0510861468052806140c0516001096146a05280613d6051610cc05109818183613dc051610ce05109089050806146c05250806142a0516146c051096146e0528060016146e051830309614700528060016146a051096147205280614400516147005109614740528061440051614720510961476052806147405161468051086147805280614100516001096147a05280613e0051610d005109806147c05250806142c0516147c051096147e0528060016147e051830309614800528060016147a051096148205280613e0051610b405109806148405250806142c05161484051096148605280610d4051614860518303096148805280610d40516147a051096148a052806148805161480051086148c05280613e0051610b605109806148e05250806142c0516148e0510961490052806142e0516149005183030961492052806142e0516147a051096149405280614920516148c051086149605280613e0051610b805109806149805250806142c05161498051096149a05280614300516149a0518303096149c05280614300516147a051096149e052806149c0516149605108614a005280613e0051610ba0510980614a205250806142c051614a205109614a40528061432051614a4051830309614a605280614320516147a05109614a805280614a6051614a005108614aa05280613e0051610be0510980614ac05250806142c051614ac05109614ae0528061434051614ae051830309614b005280614340516147a05109614b205280614b0051614aa05108614b405280613e0051610c00510980614b605250806142c051614b605109614b80528061436051614b8051830309614ba05280614360516147a05109614bc05280614ba051614b405108614be05280613e0051610c20510980614c005250806142c051614c005109614c20528061438051614c2051830309614c405280614380516147a05109614c605280614c4051614be05108614c805280614100516138605109614ca05280614100516138805109614cc05280614100516138a05109614ce05280613e00516138c0510980614d005250806142c051614d005109614d2052806143a051614d2051830309614d4052806143a0516147a05109614d6052806143a051614ca05109614d8052806143a051614cc05109614da052806143a051614ce05109614dc05280614d4051614c805108614de05280613e0051610bc0510980614e005250806142c051614e005109614e2052806143c051614e2051830309614e4052806143c0516147a05109614e605280614e4051614de05108614e80528061442051614e805109614ea05280614420516148205109614ec05280614420516148a05109614ee05280614420516149405109614f005280614420516149e05109614f20528061442051614a805109614f40528061442051614b205109614f60528061442051614bc05109614f80528061442051614c605109614fa0528061442051614d605109614fc0528061442051614d805109614fe0528061442051614da05109615000528061442051614dc05109615020528061442051614e6051096150405280614ea05161478051086150605280613c40516001096150805280610e40516001096150a05260016150c05260026150e052615060516151005282600160406150c060606150c060075afa141692506150c051615120526150e05161514052610660516151605261068051615180528260016040615120608061512060065afa14169250610840516151a052610860516151c052614640516151e05282600160406151a060606151a060075afa14169250615120516152005261514051615220526151a051615240526151c051615260528260016040615200608061520060065afa1416925061088051615280526108a0516152a052614660516152c0528260016040615280606061528060075afa14169250615200516152e052615220516153005261528051615320526152a0516153405282600160406152e060806152e060065afa1416925061070051615360526107205161538052614760516153a0528260016040615360606061536060075afa141692506152e0516153c052615300516153e0526153605161540052615380516154205282600160406153c060806153c060065afa1416925061074051615440526107605161546052614ec051615480528260016040615440606061544060075afa141692506153c0516154a0526153e0516154c052615440516154e052615460516155005282600160406154a060806154a060065afa141692507f1701d83c9ad410f3d61886c39b7b8a618f42219a1404264208f838c1672b8e71615520527f0868e69339d5d3bbd747b6e7772a9760a7277c0993a420c2848808b15de0424c61554052614ee051615560528260016040615520606061552060075afa141692506154a051615580526154c0516155a052615520516155c052615540516155e0528260016040615580608061558060065afa141692507f21c6ea7d6dbcd767ffb9d9beeb4f9c2f8243bc65290f2d75a59aea4f65ba8f3d615600527f24d0a0acb031c9a5687da08cdaf96650aae5c60435739bda8bbd574eb962622c61562052614f0051615640528260016040615600606061560060075afa1416925061558051615660526155a05161568052615600516156a052615620516156c0528260016040615660608061566060065afa141692507f289feda4952fe4464c9716d071e291bbecdcd5432356042dc79b76ed38cbbb0d6156e0527f07f3ca14a8801fa413462ad72ea448da5d7cf8c5218534cdc39bb23779b70bb961570052614f20516157205282600160406156e060606156e060075afa14169250615660516157405261568051615760526156e05161578052615700516157a0528260016040615740608061574060065afa141692507f259670bd2f2f6fce3b18100f92a2e59874da3b66a9ddd61e163eb4b071e24a976157c0527f097f07272f7ca89070ad9c06d9a3da1bb6e91d0e69bf7872f44cc5d332291eb56157e052614f40516158005282600160406157c060606157c060075afa14169250615740516158205261576051615840526157c051615860526157e051615880528260016040615820608061582060065afa141692507f26eaa658ef237183330c716cf9d5d978d8618788db2551142e1a9af837ecc8106158a0527f1fa793c6b0f3df4a8a1017daa531a45fdfa8b5da433308f71716565f8b85aa7d6158c052614f60516158e05282600160406158a060606158a060075afa14169250615820516159005261584051615920526158a051615940526158c051615960528260016040615900608061590060065afa141692507f186694283d847cec7609ca9b642f46fc751a61e3ac330841cdf6a938a3439c02615980527f16eb0141342ab5f9ca76fcaef38c222f51dd1afd5d45943e3676ba0c2ceb4f6d6159a052614f80516159c0528260016040615980606061598060075afa14169250615900516159e05261592051615a005261598051615a20526159a051615a405282600160406159e060806159e060065afa141692507f0f76818adad3c635f139fde306f33aba7249952bdbbf72cf477a51f9d84f3ccc615a60527f23f89f9896b1cc39de92659098ea839186ff2e997ffa3413c1a7af4f31abe4ce615a8052614fa051615aa0528260016040615a606060615a6060075afa141692506159e051615ac052615a0051615ae052615a6051615b0052615a8051615b20528260016040615ac06080615ac060065afa1416925061096051615b405261098051615b6052614fc051615b80528260016040615b406060615b4060075afa14169250615ac051615ba052615ae051615bc052615b4051615be052615b6051615c00528260016040615ba06080615ba060065afa141692506109a051615c20526109c051615c4052614fe051615c60528260016040615c206060615c2060075afa14169250615ba051615c8052615bc051615ca052615c2051615cc052615c4051615ce0528260016040615c806080615c8060065afa141692506109e051615d0052610a0051615d205261500051615d40528260016040615d006060615d0060075afa14169250615c8051615d6052615ca051615d8052615d0051615da052615d2051615dc0528260016040615d606080615d6060065afa14169250610a2051615de052610a4051615e005261502051615e20528260016040615de06060615de060075afa14169250615d6051615e4052615d8051615e6052615de051615e8052615e0051615ea0528260016040615e406080615e4060065afa141692506108c051615ec0526108e051615ee05261504051615f00528260016040615ec06060615ec060075afa14169250615e4051615f2052615e6051615f4052615ec051615f6052615ee051615f80528260016040615f206080615f2060065afa14169250610de051615fa052610e0051615fc052615080518103615fe0528260016040615fa06060615fa060075afa14169250615f205161600052615f405161602052615fa05161604052615fc051616060528260016040616000608061600060065afa14169250610e805161608052610ea0516160a0526150a0516160c0528260016040616080606061608060075afa14169250616000516160e052616020516161005261608051616120526160a0516161405282600160406160e060806160e060065afa141692506160e051616160526161005161618052610e80516161a052610ea0516161c052610ec0516161e052610ee05161620052610f005161622052610f205161624052610100616160206162605280616260510661628052806162805161628051096162a05280616280516001096162c0526161e0516162e05261620051616300526162c0516163205282600160406162e060606162e060075afa14169250616160516163405261618051616360526162e05161638052616300516163a0528260016040616340608061634060065afa14169250616220516163c052616240516163e0526162c0516164005282600160406163c060606163c060075afa141692506161a051616420526161c051616440526163c051616460526163e051616480528260016040616420608061642060065afa14169250616340516164a052616360516164c0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26164e0527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed616500527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b616520527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa61654052616420516165605261644051616580527f172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b6165a0527f2ae0c8c3a090f7200ff398ee9845bbae8f8c1445ae7b632212775f60a0e216006165c0527f190fa476a5b352809ed41d7a0d7fe12b8f685e3c12a6d83855dba27aaf4696436165e0527f1c0a500618907df9e4273d5181e31088deb1f05132de037cbfe73888f97f77c96166005282600160206164a06101806164a060085afa141692508260016164a051141692508261480757600080fd5b600080f3fea264697066735822122026e891e5d925cf339bec37559839722b8fe67c5fbcb9bf916360d10c4212867164736f6c63430008130033"; diff --git a/scripts/deterministic/DeployScroll.s.sol b/scripts/deterministic/DeployScroll.s.sol new file mode 100644 index 00000000..394d4725 --- /dev/null +++ b/scripts/deterministic/DeployScroll.s.sol @@ -0,0 +1,1412 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {ProxyAdminSetOwner} from "./contracts/ProxyAdminSetOwner.sol"; +import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +import {EmptyContract} from "../../src/misc/EmptyContract.sol"; + +import {EnforcedTxGateway} from "../../src/L1/gateways/EnforcedTxGateway.sol"; +import {L1CustomERC20Gateway} from "../../src/L1/gateways/L1CustomERC20Gateway.sol"; +import {L1ERC1155Gateway} from "../../src/L1/gateways/L1ERC1155Gateway.sol"; +import {L1ERC721Gateway} from "../../src/L1/gateways/L1ERC721Gateway.sol"; +import {L1ETHGateway} from "../../src/L1/gateways/L1ETHGateway.sol"; +import {L1GatewayRouter} from "../../src/L1/gateways/L1GatewayRouter.sol"; +import {L1MessageQueueV1WithGasPriceOracle} from "../../src/L1/rollup/L1MessageQueueV1WithGasPriceOracle.sol"; +import {L1MessageQueueV2} from "../../src/L1/rollup/L1MessageQueueV2.sol"; +import {SystemConfig} from "../../src/L1/system-contract/SystemConfig.sol"; +import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol"; +import {L1StandardERC20Gateway} from "../../src/L1/gateways/L1StandardERC20Gateway.sol"; +import {L1WETHGateway} from "../../src/L1/gateways/L1WETHGateway.sol"; +import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol"; +import {MultipleVersionRollupVerifierSetOwner} from "./contracts/MultipleVersionRollupVerifierSetOwner.sol"; +import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol"; +import {ZkEvmVerifierV2} from "../../src/libraries/verifier/ZkEvmVerifierV2.sol"; +import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol"; +import {L2ERC1155Gateway} from "../../src/L2/gateways/L2ERC1155Gateway.sol"; +import {L2ERC721Gateway} from "../../src/L2/gateways/L2ERC721Gateway.sol"; +import {L2ETHGateway} from "../../src/L2/gateways/L2ETHGateway.sol"; +import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol"; +import {L2ScrollMessenger} from "../../src/L2/L2ScrollMessenger.sol"; +import {L2StandardERC20Gateway} from "../../src/L2/gateways/L2StandardERC20Gateway.sol"; +import {L2WETHGateway} from "../../src/L2/gateways/L2WETHGateway.sol"; +import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol"; +import {L2MessageQueue} from "../../src/L2/predeploys/L2MessageQueue.sol"; +import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol"; +import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol"; +import {WrappedEther} from "../../src/L2/predeploys/WrappedEther.sol"; +import {ScrollStandardERC20} from "../../src/libraries/token/ScrollStandardERC20.sol"; +import {ScrollStandardERC20FactorySetOwner} from "./contracts/ScrollStandardERC20FactorySetOwner.sol"; + +import {ScrollChainMockFinalize} from "../../src/mocks/ScrollChainMockFinalize.sol"; + +import "./Constants.sol"; +import "./Configuration.sol"; +import "./DeterministicDeployment.sol"; + +/// @dev The minimum deployer account balance. +uint256 constant MINIMUM_DEPLOYER_BALANCE = 0.1 ether; + +contract DeployScroll is DeterministicDeployment { + using stdToml for string; + + /********* + * Types * + *********/ + + enum Layer { + None, + L1, + L2 + } + + /******************* + * State variables * + *******************/ + + // general configurations + Layer private broadcastLayer = Layer.None; + + /*********************** + * Contracts to deploy * + ***********************/ + + // L1 addresses + address internal L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR; + address internal L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_ENFORCED_TX_GATEWAY_PROXY_ADDR; + address internal L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_ERC1155_GATEWAY_PROXY_ADDR; + address internal L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_ERC721_GATEWAY_PROXY_ADDR; + address internal L1_ETH_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_ETH_GATEWAY_PROXY_ADDR; + address internal L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR; + address internal L1_GATEWAY_ROUTER_PROXY_ADDR; + address internal L1_MESSAGE_QUEUE_V1_IMPLEMENTATION_ADDR; + address internal L1_MESSAGE_QUEUE_V1_PROXY_ADDR; + address internal L1_MESSAGE_QUEUE_V2_IMPLEMENTATION_ADDR; + address internal L1_MESSAGE_QUEUE_V2_PROXY_ADDR; + address internal L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR; + address internal L1_PROXY_ADMIN_ADDR; + address internal L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR; + address internal L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR; + address internal L1_SCROLL_CHAIN_PROXY_ADDR; + address internal L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR; + address internal L1_SCROLL_MESSENGER_PROXY_ADDR; + address internal L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR; + address internal L1_WETH_ADDR; + address internal L1_WETH_GATEWAY_IMPLEMENTATION_ADDR; + address internal L1_WETH_GATEWAY_PROXY_ADDR; + address internal L1_WHITELIST_ADDR; + address internal L1_PLONK_VERIFIER_ADDR; + address internal L1_ZKEVM_VERIFIER_V2_ADDR; + address internal L1_WRAPPED_TOKEN_GATEWAY_ADDR; + address internal SYSTEM_CONFIG_IMPLEMENTATION_ADDR; + address internal SYSTEM_CONFIG_PROXY_ADDR; + + // L2 addresses + address internal L1_GAS_PRICE_ORACLE_ADDR; + address internal L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR; + address internal L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR; + address internal L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR; + address internal L2_ERC1155_GATEWAY_PROXY_ADDR; + address internal L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR; + address internal L2_ERC721_GATEWAY_PROXY_ADDR; + address internal L2_ETH_GATEWAY_IMPLEMENTATION_ADDR; + address internal L2_ETH_GATEWAY_PROXY_ADDR; + address internal L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR; + address internal L2_GATEWAY_ROUTER_PROXY_ADDR; + address internal L2_MESSAGE_QUEUE_ADDR; + address internal L2_PROXY_ADMIN_ADDR; + address internal L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR; + address internal L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR; + address internal L2_SCROLL_MESSENGER_PROXY_ADDR; + address internal L2_SCROLL_STANDARD_ERC20_ADDR; + address internal L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR; + address internal L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR; + address internal L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR; + address internal L2_TX_FEE_VAULT_ADDR; + address internal L2_WETH_ADDR; + address internal L2_WETH_GATEWAY_IMPLEMENTATION_ADDR; + address internal L2_WETH_GATEWAY_PROXY_ADDR; + address internal L2_WHITELIST_ADDR; + + /************* + * Utilities * + *************/ + + /// @dev Only broadcast code block if we run the script on the specified layer. + modifier broadcast(Layer layer) { + if (broadcastLayer == layer) { + vm.startBroadcast(DEPLOYER_PRIVATE_KEY); + } else { + // make sure we use the correct sender in simulation + vm.startPrank(DEPLOYER_ADDR); + } + + _; + + if (broadcastLayer == layer) { + vm.stopBroadcast(); + } else { + vm.stopPrank(); + } + } + + /// @dev Only execute block if we run the script on the specified layer. + modifier only(Layer layer) { + if (broadcastLayer != layer) { + return; + } + _; + } + + /// @dev Do not execute block if we run the script on the specified layer. + modifier skip(Layer layer) { + if (broadcastLayer == layer) { + return; + } + _; + } + + /*************** + * Entry point * + ***************/ + + function run(string memory layer, string memory scriptMode) public { + broadcastLayer = parseLayer(layer); + ScriptMode mode = parseScriptMode(scriptMode); + + DeterministicDeployment.initialize(mode); + + checkDeployerBalance(); + deployAllContracts(); + initializeL1Contracts(); + initializeL2Contracts(); + } + + /********************** + * Internal interface * + **********************/ + + function predictAllContracts() internal { + skipDeployment(); + deployAllContracts(); + } + + /********************* + * Private functions * + *********************/ + + function parseLayer(string memory raw) private pure returns (Layer) { + if (keccak256(bytes(raw)) == keccak256(bytes("L1"))) { + return Layer.L1; + } else if (keccak256(bytes(raw)) == keccak256(bytes("L2"))) { + return Layer.L2; + } else { + return Layer.None; + } + } + + function checkDeployerBalance() private { + // ignore balance during simulation + if (broadcastLayer == Layer.None) { + return; + } + + // check funds for deployment (L1 & L2) + if (DEPLOYER_ADDR.balance < MINIMUM_DEPLOYER_BALANCE) { + revert( + string( + abi.encodePacked( + "[ERROR] insufficient funds on deployer account for contract deployment (", + vm.toString(DEPLOYER_ADDR), + ") minimum ETH balance (in wei): ", + vm.toString(MINIMUM_DEPLOYER_BALANCE) + ) + ) + ); + } + + // check funds for initial deposit (L1, ETH as gas token) + if (broadcastLayer == Layer.L1) { + // note: L1_SCROLL_MESSENGER_PROXY_ADDR is not known at this point, + // so we read it directly from the generated configuration file. + address l1MessengerProxyAddr = notnull(contractsCfg.readAddress(".L1_SCROLL_MESSENGER_PROXY_ADDR")); + + uint256 l1MessengerBalance = l1MessengerProxyAddr.balance; + uint256 amountToLock = L2_DEPLOYER_INITIAL_BALANCE; + + uint256 amountToSend = 0; + if (l1MessengerBalance < amountToLock) { + amountToSend = amountToLock - l1MessengerBalance; + } + + uint256 minBalance = MINIMUM_DEPLOYER_BALANCE + amountToSend; + + if (DEPLOYER_ADDR.balance < minBalance) { + revert( + string( + abi.encodePacked( + "[ERROR] insufficient funds on deployer account for initial deposit (", + vm.toString(DEPLOYER_ADDR), + ") minimum ETH balance (in wei): ", + vm.toString(minBalance) + ) + ) + ); + } + } + } + + function transferOwnership(address addr, address newOwner) private { + if (Ownable(addr).owner() != newOwner) { + Ownable(addr).transferOwnership(newOwner); + } + } + + function deployAllContracts() private { + deployL1Contracts1stPass(); + deployL2Contracts1stPass(); + deployL1Contracts2ndPass(); + deployL2Contracts2ndPass(); + } + + // @notice deployL1Contracts1stPass deploys L1 contracts whose initialization does not depend on any L2 addresses. + function deployL1Contracts1stPass() private broadcast(Layer.L1) { + deployL1Weth(); + deployL1ProxyAdmin(); + deployL1PlaceHolder(); + deployL1Whitelist(); + deployL1ScrollChainProxy(); + deployL1ScrollMessengerProxy(); + deployL1EnforcedTxGatewayProxy(); + deployL1PlonkVerifier(); + deployL1ZkEvmVerifier(); + deployL1MultipleVersionRollupVerifier(); + deploySystemConfig(); + deployL1MessageQueue(); + deployL1ScrollChain(); + deployL1GatewayRouter(); + deployL1ETHGatewayProxy(); + deployL1WETHGatewayProxy(); + deployL1StandardERC20GatewayProxy(); + deployL1CustomERC20GatewayProxy(); + deployL1ERC721GatewayProxy(); + deployL1ERC1155GatewayProxy(); + } + + // @notice deployL2Contracts1stPass deploys L2 contracts whose initialization does not depend on any L1 addresses. + function deployL2Contracts1stPass() private broadcast(Layer.L2) { + deployL2MessageQueue(); + deployL1GasPriceOracle(); + deployL2Whitelist(); + deployL2Weth(); + deployTxFeeVault(); + deployL2ProxyAdmin(); + deployL2PlaceHolder(); + deployL2ScrollMessengerProxy(); + deployL2ETHGatewayProxy(); + deployL2WETHGatewayProxy(); + deployL2StandardERC20GatewayProxy(); + deployL2CustomERC20GatewayProxy(); + deployL2ERC721GatewayProxy(); + deployL2ERC1155GatewayProxy(); + deployScrollStandardERC20Factory(); + } + + // @notice deployL1Contracts2ndPass deploys L1 contracts whose initialization depends on some L2 addresses. + function deployL1Contracts2ndPass() private broadcast(Layer.L1) { + deployL1EnforcedTxGateway(); + deployL1ScrollMessenger(); + deployL1StandardERC20Gateway(); + deployL1ETHGateway(); + deployL1WETHGateway(); + deployL1CustomERC20Gateway(); + deployL1ERC721Gateway(); + deployL1ERC1155Gateway(); + } + + // @notice deployL2Contracts2ndPass deploys L2 contracts whose initialization depends on some L1 addresses. + function deployL2Contracts2ndPass() private broadcast(Layer.L2) { + // upgradable + deployL2ScrollMessenger(); + deployL2GatewayRouter(); + deployL2StandardERC20Gateway(); + deployL2ETHGateway(); + deployL2WETHGateway(); + deployL2CustomERC20Gateway(); + deployL2ERC721Gateway(); + deployL2ERC1155Gateway(); + } + + // @notice initializeL1Contracts initializes contracts deployed on L1. + function initializeL1Contracts() private broadcast(Layer.L1) only(Layer.L1) { + initializeScrollChain(); + initializeSystemConfig(); + initializeL1MessageQueue(); + initializeL1ScrollMessenger(); + initializeEnforcedTxGateway(); + initializeL1GatewayRouter(); + initializeL1CustomERC20Gateway(); + initializeL1ERC1155Gateway(); + initializeL1ERC721Gateway(); + initializeL1ETHGateway(); + initializeL1StandardERC20Gateway(); + initializeL1WETHGateway(); + initializeL1Whitelist(); + + // lock tokens on L1 to ensure bridge parity, + // we lock ETH in L1ScrollMessenger + // note: this can only be done before transferring ownership + lockTokensOnL1(); + + transferL1ContractOwnership(); + } + + // @notice initializeL2Contracts initializes contracts deployed on L2. + function initializeL2Contracts() private broadcast(Layer.L2) only(Layer.L2) { + initializeL2MessageQueue(); + initializeL2TxFeeVault(); + initializeL1GasPriceOracle(); + initializeL2ScrollMessenger(); + initializeL2GatewayRouter(); + initializeL2CustomERC20Gateway(); + initializeL2ERC1155Gateway(); + initializeL2ERC721Gateway(); + initializeL2ETHGateway(); + initializeL2StandardERC20Gateway(); + initializeL2WETHGateway(); + initializeScrollStandardERC20Factory(); + initializeL2Whitelist(); + + transferL2ContractOwnership(); + } + + /*************************** + * L1: 1st pass deployment * + ***************************/ + + function deployL1Weth() private { + L1_WETH_ADDR = deploy("L1_WETH", type(WrappedEther).creationCode); + } + + function deployL1ProxyAdmin() private { + bytes memory args = abi.encode(DEPLOYER_ADDR); + L1_PROXY_ADMIN_ADDR = deploy("L1_PROXY_ADMIN", type(ProxyAdminSetOwner).creationCode, args); + } + + function deployL1PlaceHolder() private { + L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR = deploy( + "L1_PROXY_IMPLEMENTATION_PLACEHOLDER", + type(EmptyContract).creationCode + ); + } + + function deployL1Whitelist() private { + bytes memory args = abi.encode(DEPLOYER_ADDR); + L1_WHITELIST_ADDR = deploy("L1_WHITELIST", type(Whitelist).creationCode, args); + } + + function deployL1ScrollChainProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_SCROLL_CHAIN_PROXY_ADDR = deploy( + "L1_SCROLL_CHAIN_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1ScrollMessengerProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_SCROLL_MESSENGER_PROXY_ADDR = deploy( + "L1_SCROLL_MESSENGER_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1EnforcedTxGatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = deploy( + "L1_ENFORCED_TX_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1EnforcedTxGateway() private { + bytes memory args = abi.encode(notnull(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), notnull(L1_FEE_VAULT_ADDR)); + + L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION", + type(EnforcedTxGateway).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_ENFORCED_TX_GATEWAY_PROXY_ADDR, L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL1PlonkVerifier() private { + L1_PLONK_VERIFIER_ADDR = deploy("L1_PLONK_VERIFIER", PLONK_VERIFIER_CREATION_CODE); + } + + function deployL1ZkEvmVerifier() private { + bytes memory args = abi.encode(notnull(L1_PLONK_VERIFIER_ADDR), VERIFIER_DIGEST); + L1_ZKEVM_VERIFIER_V2_ADDR = deploy("L1_ZKEVM_VERIFIER_V2", type(ZkEvmVerifierV2).creationCode, args); + } + + function deployL1MultipleVersionRollupVerifier() private { + uint256[] memory _versions = new uint256[](1); + address[] memory _verifiers = new address[](1); + + // register V4 verifier: DarwinV2 upgrade, plonk verifier v0.13.1 + _versions[0] = 4; + _verifiers[0] = notnull(L1_ZKEVM_VERIFIER_V2_ADDR); + + bytes memory args = abi.encode(DEPLOYER_ADDR, _versions, _verifiers); + + L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = deploy( + "L1_MULTIPLE_VERSION_ROLLUP_VERIFIER", + type(MultipleVersionRollupVerifierSetOwner).creationCode, + args + ); + } + + function deploySystemConfig() private { + SYSTEM_CONFIG_IMPLEMENTATION_ADDR = deploy("SYSTEM_CONFIG_IMPLEMENTATION", type(SystemConfig).creationCode); + + bytes memory args = abi.encode( + notnull(SYSTEM_CONFIG_IMPLEMENTATION_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + SYSTEM_CONFIG_PROXY_ADDR = deploy("SYSTEM_CONFIG_PROXY", type(TransparentUpgradeableProxy).creationCode, args); + } + + function deployL1MessageQueue() private { + // deploy L1MessageQueueV1 + bytes memory args = abi.encode( + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L1_SCROLL_CHAIN_PROXY_ADDR), + notnull(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR) + ); + + L1_MESSAGE_QUEUE_V1_IMPLEMENTATION_ADDR = deploy( + "L1_MESSAGE_QUEUE_V1_IMPLEMENTATION", + type(L1MessageQueueV1WithGasPriceOracle).creationCode, + args + ); + + bytes memory args2 = abi.encode( + notnull(L1_MESSAGE_QUEUE_V1_IMPLEMENTATION_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_MESSAGE_QUEUE_V1_PROXY_ADDR = deploy( + "L1_MESSAGE_QUEUE_V1_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args2 + ); + + // deploy L1MessageQueueV2 + bytes memory args3 = abi.encode( + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L1_SCROLL_CHAIN_PROXY_ADDR), + notnull(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR), + notnull(L1_MESSAGE_QUEUE_V1_PROXY_ADDR), + notnull(SYSTEM_CONFIG_PROXY_ADDR) + ); + + L1_MESSAGE_QUEUE_V2_IMPLEMENTATION_ADDR = deploy( + "L1_MESSAGE_QUEUE_V2_IMPLEMENTATION", + type(L1MessageQueueV2).creationCode, + args3 + ); + + bytes memory args4 = abi.encode( + notnull(L1_MESSAGE_QUEUE_V2_IMPLEMENTATION_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_MESSAGE_QUEUE_V2_PROXY_ADDR = deploy( + "L1_MESSAGE_QUEUE_V2_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args4 + ); + } + + function deployL1ScrollChain() private { + bytes memory args = abi.encode( + CHAIN_ID_L2, + notnull(L1_MESSAGE_QUEUE_V1_PROXY_ADDR), + notnull(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), + notnull(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR), + notnull(SYSTEM_CONFIG_PROXY_ADDR) + ); + + bytes memory creationCode = type(ScrollChain).creationCode; + + if (TEST_ENV_MOCK_FINALIZE_ENABLED) { + creationCode = type(ScrollChainMockFinalize).creationCode; + } + + L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR = deploy("L1_SCROLL_CHAIN_IMPLEMENTATION", creationCode, args); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_SCROLL_CHAIN_PROXY_ADDR, L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR); + } + + function deployL1GatewayRouter() private { + L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR = deploy( + "L1_GATEWAY_ROUTER_IMPLEMENTATION", + type(L1GatewayRouter).creationCode + ); + + bytes memory args = abi.encode( + notnull(L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_GATEWAY_ROUTER_PROXY_ADDR = deploy( + "L1_GATEWAY_ROUTER_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1ETHGatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_ETH_GATEWAY_PROXY_ADDR = deploy( + "L1_ETH_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1WETHGatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_WETH_GATEWAY_PROXY_ADDR = deploy( + "L1_WETH_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1StandardERC20GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = deploy( + "L1_STANDARD_ERC20_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1CustomERC20GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = deploy( + "L1_CUSTOM_ERC20_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1ERC721GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_ERC721_GATEWAY_PROXY_ADDR = deploy( + "L1_ERC721_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL1ERC1155GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L1_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L1_ERC1155_GATEWAY_PROXY_ADDR = deploy( + "L1_ERC1155_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + /*************************** + * L2: 1st pass deployment * + ***************************/ + + function deployL2MessageQueue() private { + bytes memory args = abi.encode(DEPLOYER_ADDR); + L2_MESSAGE_QUEUE_ADDR = deploy("L2_MESSAGE_QUEUE", type(L2MessageQueue).creationCode, args); + } + + function deployL1GasPriceOracle() private { + bytes memory args = abi.encode(DEPLOYER_ADDR, true); + L1_GAS_PRICE_ORACLE_ADDR = deploy("L1_GAS_PRICE_ORACLE", type(L1GasPriceOracle).creationCode, args); + } + + function deployL2Whitelist() private { + bytes memory args = abi.encode(DEPLOYER_ADDR); + L2_WHITELIST_ADDR = deploy("L2_WHITELIST", type(Whitelist).creationCode, args); + } + + function deployL2Weth() private { + L2_WETH_ADDR = deploy("L2_WETH", type(WrappedEther).creationCode); + } + + function deployTxFeeVault() private { + bytes memory args = abi.encode(DEPLOYER_ADDR, L1_FEE_VAULT_ADDR, FEE_VAULT_MIN_WITHDRAW_AMOUNT); + L2_TX_FEE_VAULT_ADDR = deploy("L2_TX_FEE_VAULT", type(L2TxFeeVault).creationCode, args); + } + + function deployL2ProxyAdmin() private { + bytes memory args = abi.encode(DEPLOYER_ADDR); + L2_PROXY_ADMIN_ADDR = deploy("L2_PROXY_ADMIN", type(ProxyAdminSetOwner).creationCode, args); + } + + function deployL2PlaceHolder() private { + L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR = deploy( + "L2_PROXY_IMPLEMENTATION_PLACEHOLDER", + type(EmptyContract).creationCode + ); + } + + function deployL2ScrollMessengerProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_SCROLL_MESSENGER_PROXY_ADDR = deploy( + "L2_SCROLL_MESSENGER_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2StandardERC20GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = deploy( + "L2_STANDARD_ERC20_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2ETHGatewayProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_ETH_GATEWAY_PROXY_ADDR = deploy( + "L2_ETH_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2WETHGatewayProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_WETH_GATEWAY_PROXY_ADDR = deploy( + "L2_WETH_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2CustomERC20GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = deploy( + "L2_CUSTOM_ERC20_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2ERC721GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_ERC721_GATEWAY_PROXY_ADDR = deploy( + "L2_ERC721_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2ERC1155GatewayProxy() private { + bytes memory args = abi.encode( + notnull(L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_ERC1155_GATEWAY_PROXY_ADDR = deploy( + "L2_ERC1155_GATEWAY_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployScrollStandardERC20Factory() private { + L2_SCROLL_STANDARD_ERC20_ADDR = deploy("L2_SCROLL_STANDARD_ERC20", type(ScrollStandardERC20).creationCode); + bytes memory args = abi.encode(DEPLOYER_ADDR, notnull(L2_SCROLL_STANDARD_ERC20_ADDR)); + + L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = deploy( + "L2_SCROLL_STANDARD_ERC20_FACTORY", + type(ScrollStandardERC20FactorySetOwner).creationCode, + args + ); + } + + /*************************** + * L1: 2nd pass deployment * + ***************************/ + + function deployL1ScrollMessenger() private { + bytes memory args = abi.encode( + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L1_SCROLL_CHAIN_PROXY_ADDR), + notnull(L1_MESSAGE_QUEUE_V1_PROXY_ADDR), + notnull(L1_MESSAGE_QUEUE_V2_PROXY_ADDR) + ); + + L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = deploy( + "L1_SCROLL_MESSENGER_IMPLEMENTATION", + type(L1ScrollMessenger).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_SCROLL_MESSENGER_PROXY_ADDR, L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR); + } + + function deployL1ETHGateway() private { + bytes memory args = abi.encode( + notnull(L2_ETH_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + + L1_ETH_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_ETH_GATEWAY_IMPLEMENTATION", + type(L1ETHGateway).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_ETH_GATEWAY_PROXY_ADDR, L1_ETH_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL1WETHGateway() private { + bytes memory args = abi.encode( + notnull(L1_WETH_ADDR), + notnull(L2_WETH_ADDR), + notnull(L2_WETH_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + + L1_WETH_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_WETH_GATEWAY_IMPLEMENTATION", + type(L1WETHGateway).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_WETH_GATEWAY_PROXY_ADDR, L1_WETH_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL1StandardERC20Gateway() private { + bytes memory args = abi.encode( + notnull(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L2_SCROLL_STANDARD_ERC20_ADDR), + notnull(L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR) + ); + + L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION", + type(L1StandardERC20Gateway).creationCode, + args + ); + + upgrade( + L1_PROXY_ADMIN_ADDR, + L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR, + L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR + ); + } + + function deployL1CustomERC20Gateway() private { + bytes memory args = abi.encode( + notnull(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + + L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION", + type(L1CustomERC20Gateway).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL1ERC721Gateway() private { + bytes memory args = abi.encode(notnull(L2_ERC721_GATEWAY_PROXY_ADDR), notnull(L1_SCROLL_MESSENGER_PROXY_ADDR)); + + L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_ERC721_GATEWAY_IMPLEMENTATION", + type(L1ERC721Gateway).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_ERC721_GATEWAY_PROXY_ADDR, L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL1ERC1155Gateway() private { + bytes memory args = abi.encode(notnull(L2_ERC1155_GATEWAY_PROXY_ADDR), notnull(L1_SCROLL_MESSENGER_PROXY_ADDR)); + + L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L1_ERC1155_GATEWAY_IMPLEMENTATION", + type(L1ERC1155Gateway).creationCode, + args + ); + + upgrade(L1_PROXY_ADMIN_ADDR, L1_ERC1155_GATEWAY_PROXY_ADDR, L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR); + } + + /*************************** + * L2: 2nd pass deployment * + ***************************/ + + function deployL2ScrollMessenger() private { + bytes memory args = abi.encode(notnull(L1_SCROLL_MESSENGER_PROXY_ADDR), notnull(L2_MESSAGE_QUEUE_ADDR)); + + L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = deploy( + "L2_SCROLL_MESSENGER_IMPLEMENTATION", + type(L2ScrollMessenger).creationCode, + args + ); + + upgrade(L2_PROXY_ADMIN_ADDR, L2_SCROLL_MESSENGER_PROXY_ADDR, L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR); + } + + function deployL2GatewayRouter() private { + L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR = deploy( + "L2_GATEWAY_ROUTER_IMPLEMENTATION", + type(L2GatewayRouter).creationCode + ); + + bytes memory args = abi.encode( + notnull(L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR), + notnull(L2_PROXY_ADMIN_ADDR), + new bytes(0) + ); + + L2_GATEWAY_ROUTER_PROXY_ADDR = deploy( + "L2_GATEWAY_ROUTER_PROXY", + type(TransparentUpgradeableProxy).creationCode, + args + ); + } + + function deployL2StandardERC20Gateway() private { + bytes memory args = abi.encode( + notnull(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR) + ); + + L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION", + type(L2StandardERC20Gateway).creationCode, + args + ); + + upgrade( + L2_PROXY_ADMIN_ADDR, + L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR, + L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR + ); + } + + function deployL2ETHGateway() private { + address COUNTERPART = L1_ETH_GATEWAY_PROXY_ADDR; + bytes memory args = abi.encode( + notnull(COUNTERPART), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + + L2_ETH_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L2_ETH_GATEWAY_IMPLEMENTATION", + type(L2ETHGateway).creationCode, + args + ); + + upgrade(L2_PROXY_ADMIN_ADDR, L2_ETH_GATEWAY_PROXY_ADDR, L2_ETH_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL2WETHGateway() private { + bytes memory args = abi.encode( + notnull(L2_WETH_ADDR), + notnull(L1_WETH_ADDR), + notnull(L1_WETH_GATEWAY_PROXY_ADDR), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + + L2_WETH_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L2_WETH_GATEWAY_IMPLEMENTATION", + type(L2WETHGateway).creationCode, + args + ); + + upgrade(L2_PROXY_ADMIN_ADDR, L2_WETH_GATEWAY_PROXY_ADDR, L2_WETH_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL2CustomERC20Gateway() private { + bytes memory args = abi.encode( + notnull(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + + L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION", + type(L2CustomERC20Gateway).creationCode, + args + ); + + upgrade(L2_PROXY_ADMIN_ADDR, L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL2ERC721Gateway() private { + bytes memory args = abi.encode(notnull(L1_ERC721_GATEWAY_PROXY_ADDR), notnull(L2_SCROLL_MESSENGER_PROXY_ADDR)); + + L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L2_ERC721_GATEWAY_IMPLEMENTATION", + type(L2ERC721Gateway).creationCode, + args + ); + + upgrade(L2_PROXY_ADMIN_ADDR, L2_ERC721_GATEWAY_PROXY_ADDR, L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR); + } + + function deployL2ERC1155Gateway() private { + bytes memory args = abi.encode(notnull(L1_ERC1155_GATEWAY_PROXY_ADDR), notnull(L2_SCROLL_MESSENGER_PROXY_ADDR)); + + L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = deploy( + "L2_ERC1155_GATEWAY_IMPLEMENTATION", + type(L2ERC1155Gateway).creationCode, + args + ); + + upgrade(L2_PROXY_ADMIN_ADDR, L2_ERC1155_GATEWAY_PROXY_ADDR, L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR); + } + + /********************** + * L1: initialization * + **********************/ + + function initializeScrollChain() private { + if (getInitializeCount(L1_SCROLL_CHAIN_PROXY_ADDR) == 0) { + ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).initialize( + notnull(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), + notnull(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR), + MAX_TX_IN_CHUNK + ); + } + + if (!ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).isSequencer(L1_COMMIT_SENDER_ADDR)) { + ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addSequencer(L1_COMMIT_SENDER_ADDR); + } + + if (!ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).isProver(L1_FINALIZE_SENDER_ADDR)) { + ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addProver(L1_FINALIZE_SENDER_ADDR); + } + } + + function initializeSystemConfig() private { + address owner = L1_PROXY_ADMIN_ADDR; + address signer = L2GETH_SIGNER_ADDRESS; + SystemConfig.MessageQueueParameters memory messageQueueParameters = SystemConfig.MessageQueueParameters({ + maxGasLimit: uint32(MAX_L1_MESSAGE_GAS_LIMIT), + baseFeeOverhead: 1000000000, + baseFeeScalar: 1000000000 + }); + SystemConfig.EnforcedBatchParameters memory enforcedBatchParameters = SystemConfig.EnforcedBatchParameters({ + maxDelayEnterEnforcedMode: uint24(FINALIZE_BATCH_DEADLINE_SEC), + maxDelayMessageQueue: uint24(RELAY_MESSAGE_DEADLINE_SEC) + }); + + if (getInitializeCount(SYSTEM_CONFIG_PROXY_ADDR) == 0) { + SystemConfig(SYSTEM_CONFIG_PROXY_ADDR).initialize( + owner, + signer, + messageQueueParameters, + enforcedBatchParameters + ); + } + } + + function initializeL1MessageQueue() private { + if (getInitializeCount(L1_MESSAGE_QUEUE_V2_PROXY_ADDR) == 0) { + L1MessageQueueV2(L1_MESSAGE_QUEUE_V2_PROXY_ADDR).initialize(); + } + } + + function initializeL1ScrollMessenger() private { + if (getInitializeCount(L1_SCROLL_MESSENGER_PROXY_ADDR) == 0) { + L1ScrollMessenger(payable(L1_SCROLL_MESSENGER_PROXY_ADDR)).initialize( + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L1_FEE_VAULT_ADDR), + notnull(L1_SCROLL_CHAIN_PROXY_ADDR), + notnull(L1_MESSAGE_QUEUE_V2_PROXY_ADDR) + ); + } + } + + function initializeEnforcedTxGateway() private { + if (getInitializeCount(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR) == 0) { + EnforcedTxGateway(payable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR)).initialize(); + } + + // disable gateway + if (!EnforcedTxGateway(payable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR)).paused()) { + EnforcedTxGateway(payable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR)).setPause(true); + } + } + + function initializeL1GatewayRouter() private { + address L2_ETH_GATEWAY_COUNTERPART = L1_ETH_GATEWAY_PROXY_ADDR; + if (getInitializeCount(L1_GATEWAY_ROUTER_PROXY_ADDR) == 0) { + L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).initialize( + notnull(L2_ETH_GATEWAY_COUNTERPART), + notnull(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR) + ); + } + } + + function initializeL1CustomERC20Gateway() private { + if (getInitializeCount(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR) == 0) { + L1CustomERC20Gateway(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).initialize( + notnull(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL1ERC1155Gateway() private { + if (getInitializeCount(L1_ERC1155_GATEWAY_PROXY_ADDR) == 0) { + L1ERC1155Gateway(L1_ERC1155_GATEWAY_PROXY_ADDR).initialize( + notnull(L2_ERC1155_GATEWAY_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL1ERC721Gateway() private { + if (getInitializeCount(L1_ERC721_GATEWAY_PROXY_ADDR) == 0) { + L1ERC721Gateway(L1_ERC721_GATEWAY_PROXY_ADDR).initialize( + notnull(L2_ERC721_GATEWAY_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL1ETHGateway() private { + if (getInitializeCount(L1_ETH_GATEWAY_PROXY_ADDR) == 0) { + L1ETHGateway(L1_ETH_GATEWAY_PROXY_ADDR).initialize( + notnull(L2_ETH_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL1StandardERC20Gateway() private { + if (getInitializeCount(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR) == 0) { + L1StandardERC20Gateway(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR).initialize( + notnull(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L2_SCROLL_STANDARD_ERC20_ADDR), + notnull(L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR) + ); + } + } + + function initializeL1WETHGateway() private { + if (getInitializeCount(L1_WETH_GATEWAY_PROXY_ADDR) == 0) { + L1WETHGateway(payable(L1_WETH_GATEWAY_PROXY_ADDR)).initialize( + notnull(L2_WETH_GATEWAY_PROXY_ADDR), + notnull(L1_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + + // set WETH gateway in router + address[] memory _tokens = new address[](1); + _tokens[0] = notnull(L1_WETH_ADDR); + address[] memory _gateways = new address[](1); + _gateways[0] = notnull(L1_WETH_GATEWAY_PROXY_ADDR); + + if (L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).ERC20Gateway(_tokens[0]) != _gateways[0]) { + L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways); + } + } + + function initializeL1Whitelist() private { + address[] memory accounts = new address[](1); + accounts[0] = L1_GAS_ORACLE_SENDER_ADDR; + + if (!Whitelist(L1_WHITELIST_ADDR).isSenderAllowed(accounts[0])) { + Whitelist(L1_WHITELIST_ADDR).updateWhitelistStatus(accounts, true); + } + } + + function lockTokensOnL1() private { + uint256 l1MessengerBalance = address(L1_SCROLL_MESSENGER_PROXY_ADDR).balance; + uint256 amountToLock = L2_DEPLOYER_INITIAL_BALANCE; + + if (l1MessengerBalance < amountToLock) { + uint256 amountToSend = amountToLock - l1MessengerBalance; + (bool sent, bytes memory data) = payable(L1_SCROLL_MESSENGER_PROXY_ADDR).call{value: amountToSend}(""); + require(sent, "[ERROR] failed to lock tokens on layer 1"); + } + } + + function transferL1ContractOwnership() private { + transferOwnership(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_ERC1155_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_ERC721_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_GATEWAY_ROUTER_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_MESSAGE_QUEUE_V2_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_SCROLL_MESSENGER_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR, OWNER_ADDR); + transferOwnership(L1_PROXY_ADMIN_ADDR, OWNER_ADDR); + transferOwnership(L1_SCROLL_CHAIN_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_WHITELIST_ADDR, OWNER_ADDR); + transferOwnership(L1_ETH_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L1_WETH_GATEWAY_PROXY_ADDR, OWNER_ADDR); + } + + /********************** + * L2: initialization * + **********************/ + + function initializeL2MessageQueue() private { + if (L2MessageQueue(L2_MESSAGE_QUEUE_ADDR).messenger() != notnull(L2_SCROLL_MESSENGER_PROXY_ADDR)) { + L2MessageQueue(L2_MESSAGE_QUEUE_ADDR).initialize(L2_SCROLL_MESSENGER_PROXY_ADDR); + } + } + + function initializeL2TxFeeVault() private { + if (L2TxFeeVault(payable(L2_TX_FEE_VAULT_ADDR)).messenger() != notnull(L2_SCROLL_MESSENGER_PROXY_ADDR)) { + L2TxFeeVault(payable(L2_TX_FEE_VAULT_ADDR)).updateMessenger(L2_SCROLL_MESSENGER_PROXY_ADDR); + } + } + + function initializeL1GasPriceOracle() private { + if (address(L1GasPriceOracle(L1_GAS_PRICE_ORACLE_ADDR).whitelist()) != notnull(L2_WHITELIST_ADDR)) { + L1GasPriceOracle(L1_GAS_PRICE_ORACLE_ADDR).updateWhitelist(L2_WHITELIST_ADDR); + } + } + + function initializeL2ScrollMessenger() private { + if (getInitializeCount(L2_SCROLL_MESSENGER_PROXY_ADDR) == 0) { + L2ScrollMessenger(payable(L2_SCROLL_MESSENGER_PROXY_ADDR)).initialize( + notnull(L1_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL2GatewayRouter() private { + if (getInitializeCount(L2_GATEWAY_ROUTER_PROXY_ADDR) == 0) { + L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).initialize( + notnull(L2_ETH_GATEWAY_PROXY_ADDR), + notnull(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR) + ); + } + } + + function initializeL2CustomERC20Gateway() private { + if (getInitializeCount(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR) == 0) { + L2CustomERC20Gateway(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).initialize( + notnull(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL2ERC1155Gateway() private { + if (getInitializeCount(L2_ERC1155_GATEWAY_PROXY_ADDR) == 0) { + L2ERC1155Gateway(L2_ERC1155_GATEWAY_PROXY_ADDR).initialize( + notnull(L1_ERC1155_GATEWAY_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL2ERC721Gateway() private { + if (getInitializeCount(L2_ERC721_GATEWAY_PROXY_ADDR) == 0) { + L2ERC721Gateway(L2_ERC721_GATEWAY_PROXY_ADDR).initialize( + notnull(L1_ERC721_GATEWAY_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL2ETHGateway() private { + address COUNTERPART = L1_ETH_GATEWAY_PROXY_ADDR; + if (getInitializeCount(L2_ETH_GATEWAY_PROXY_ADDR) == 0) { + L2ETHGateway(L2_ETH_GATEWAY_PROXY_ADDR).initialize( + notnull(COUNTERPART), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + } + + function initializeL2StandardERC20Gateway() private { + if (getInitializeCount(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR) == 0) { + L2StandardERC20Gateway(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR).initialize( + notnull(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR), + notnull(L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR) + ); + } + } + + function initializeL2WETHGateway() private { + if (getInitializeCount(L2_WETH_GATEWAY_PROXY_ADDR) == 0) { + L2WETHGateway(payable(L2_WETH_GATEWAY_PROXY_ADDR)).initialize( + notnull(L1_WETH_GATEWAY_PROXY_ADDR), + notnull(L2_GATEWAY_ROUTER_PROXY_ADDR), + notnull(L2_SCROLL_MESSENGER_PROXY_ADDR) + ); + } + + // set WETH gateway in router + address[] memory _tokens = new address[](1); + _tokens[0] = notnull(L2_WETH_ADDR); + address[] memory _gateways = new address[](1); + _gateways[0] = notnull(L2_WETH_GATEWAY_PROXY_ADDR); + + if (L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).ERC20Gateway(_tokens[0]) != _gateways[0]) { + L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways); + } + } + + function initializeScrollStandardERC20Factory() private { + transferOwnership( + notnull(L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR), + notnull(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR) + ); + } + + function initializeL2Whitelist() private { + address[] memory accounts = new address[](1); + accounts[0] = L2_GAS_ORACLE_SENDER_ADDR; + + if (!Whitelist(L2_WHITELIST_ADDR).isSenderAllowed(accounts[0])) { + Whitelist(L2_WHITELIST_ADDR).updateWhitelistStatus(accounts, true); + } + } + + function transferL2ContractOwnership() private { + transferOwnership(L1_GAS_PRICE_ORACLE_ADDR, OWNER_ADDR); + transferOwnership(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_ERC1155_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_ERC721_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_ETH_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_GATEWAY_ROUTER_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_MESSAGE_QUEUE_ADDR, OWNER_ADDR); + transferOwnership(L2_SCROLL_MESSENGER_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR, OWNER_ADDR); + transferOwnership(L2_TX_FEE_VAULT_ADDR, OWNER_ADDR); + transferOwnership(L2_PROXY_ADMIN_ADDR, OWNER_ADDR); + transferOwnership(L2_WHITELIST_ADDR, OWNER_ADDR); + transferOwnership(L2_WETH_GATEWAY_PROXY_ADDR, OWNER_ADDR); + } +} diff --git a/scripts/deterministic/DeterministicDeployment.sol b/scripts/deterministic/DeterministicDeployment.sol new file mode 100644 index 00000000..98390508 --- /dev/null +++ b/scripts/deterministic/DeterministicDeployment.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; + +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ERC1967Upgrade} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; + +import {CONFIG_CONTRACTS_PATH, DEFAULT_DEPLOYMENT_SALT, DETERMINISTIC_DEPLOYMENT_PROXY_ADDR} from "./Constants.sol"; +import {Configuration} from "./Configuration.sol"; + +/// @notice DeterministicDeployment provides utilities for deterministic contract deployments. +abstract contract DeterministicDeployment is Configuration { + using stdToml for string; + + /********* + * Types * + *********/ + + enum ScriptMode { + None, + LogAddresses, + WriteConfig, + VerifyConfig, + EmptyConfig + } + + /******************* + * State variables * + *******************/ + + ScriptMode private mode; + string private saltPrefix; + bool private skipDeploy; + + /********************** + * Internal interface * + **********************/ + + function initialize(ScriptMode _mode) internal { + mode = _mode; + skipDeploy = false; + + if (mode != ScriptMode.EmptyConfig) { + readConfig(); + } + + // salt prefix used for deterministic deployments + if (bytes(DEPLOYMENT_SALT).length != 0) { + saltPrefix = DEPLOYMENT_SALT; + } else { + saltPrefix = DEFAULT_DEPLOYMENT_SALT; + } + + // sanity check: make sure DeterministicDeploymentProxy exists + if (DETERMINISTIC_DEPLOYMENT_PROXY_ADDR.code.length == 0) { + revert( + string( + abi.encodePacked( + "[ERROR] DeterministicDeploymentProxy (", + vm.toString(DETERMINISTIC_DEPLOYMENT_PROXY_ADDR), + ") is not available" + ) + ) + ); + } + } + + function parseScriptMode(string memory scriptMode) internal pure returns (ScriptMode) { + if (keccak256(bytes(scriptMode)) == keccak256(bytes("log-addresses"))) { + return ScriptMode.LogAddresses; + } else if (keccak256(bytes(scriptMode)) == keccak256(bytes("write-config"))) { + return ScriptMode.WriteConfig; + } else if (keccak256(bytes(scriptMode)) == keccak256(bytes("verify-config"))) { + return ScriptMode.VerifyConfig; + } else { + return ScriptMode.None; + } + } + + function skipDeployment() internal { + skipDeploy = true; + } + + function deploy(string memory name, bytes memory codeWithArgs) internal returns (address) { + return _deploy(name, codeWithArgs); + } + + function deploy( + string memory name, + bytes memory code, + bytes memory args + ) internal returns (address) { + return _deploy(name, abi.encodePacked(code, args)); + } + + function predict(string memory name, bytes memory codeWithArgs) internal view returns (address) { + return _predict(name, codeWithArgs); + } + + function predict( + string memory name, + bytes memory code, + bytes memory args + ) internal view returns (address) { + return _predict(name, abi.encodePacked(code, args)); + } + + function upgrade( + address proxyAdminAddr, + address proxyAddr, + address implAddr + ) internal { + address addr = _getImplementation(proxyAddr); + + if (!skipDeploy && addr != implAddr) { + ProxyAdmin(notnull(proxyAdminAddr)).upgrade( + ITransparentUpgradeableProxy(notnull(proxyAddr)), + notnull(implAddr) + ); + } + } + + function getInitializeCount(address contractAddr) internal view returns (uint8) { + bytes32 slotValue = vm.load(address(contractAddr), bytes32(uint256(0))); + return uint8(uint256(slotValue)); + } + + /********************* + * Private functions * + *********************/ + + function _getSalt(string memory name) private view returns (bytes32) { + return keccak256(abi.encodePacked(saltPrefix, name)); + } + + function _deploy(string memory name, bytes memory codeWithArgs) private returns (address) { + // check override (mainly used with predeploys) + address addr = tryGetOverride(name); + + if (addr != address(0)) { + _label(name, addr); + return addr; + } + + // predict determinstic deployment address + addr = _predict(name, codeWithArgs); + _label(name, addr); + + if (skipDeploy) { + return addr; + } + + // skip if the contract is already deployed + if (addr.code.length > 0) { + return addr; + } + + // deploy contract + bytes32 salt = _getSalt(name); + bytes memory data = abi.encodePacked(salt, codeWithArgs); + (bool success, ) = DETERMINISTIC_DEPLOYMENT_PROXY_ADDR.call(data); + require(success, "call failed"); + require(addr.code.length != 0, "deployment address mismatch"); + + return addr; + } + + function _predict(string memory name, bytes memory codeWithArgs) private view returns (address) { + bytes32 salt = _getSalt(name); + + return + address( + uint160( + uint256( + keccak256( + abi.encodePacked( + bytes1(0xff), + DETERMINISTIC_DEPLOYMENT_PROXY_ADDR, + salt, + keccak256(codeWithArgs) + ) + ) + ) + ) + ); + } + + function _label(string memory name, address addr) internal { + vm.label(addr, name); + + if (mode == ScriptMode.None) { + return; + } + + if (mode == ScriptMode.LogAddresses) { + console.log(string(abi.encodePacked(name, "_ADDR=", vm.toString(address(addr))))); + return; + } + + string memory tomlPath = string(abi.encodePacked(".", name, "_ADDR")); + + if (mode == ScriptMode.WriteConfig) { + vm.writeToml(vm.toString(addr), CONFIG_CONTRACTS_PATH, tomlPath); + return; + } + + if (mode == ScriptMode.VerifyConfig) { + address expectedAddr = contractsCfg.readAddress(tomlPath); + + if (addr != expectedAddr) { + revert( + string( + abi.encodePacked( + "[ERROR] unexpected address for ", + name, + ", expected = ", + vm.toString(expectedAddr), + " (from toml config), got = ", + vm.toString(addr) + ) + ) + ); + } + } + } + + function _getImplementation(address proxyAddr) private view returns (address) { + // ERC1967Upgrade implementation slot + bytes32 _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + // get implementation address + return address(uint160(uint256(vm.load(address(proxyAddr), _IMPLEMENTATION_SLOT)))); + } +} diff --git a/scripts/deterministic/GenerateConfigs.s.sol b/scripts/deterministic/GenerateConfigs.s.sol new file mode 100644 index 00000000..cc3485f4 --- /dev/null +++ b/scripts/deterministic/GenerateConfigs.s.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {stdToml} from "forge-std/StdToml.sol"; + +import {ADMIN_SYSTEM_BACKEND_CONFIG_PATH, ADMIN_SYSTEM_CRON_CONFIG_PATH, BALANCE_CHECKER_CONFIG_PATH, BALANCE_CHECKER_CONFIG_TEMPLATE_PATH, BRIDGE_HISTORY_API_CONFIG_PATH, BRIDGE_HISTORY_CONFIG_TEMPLATE_PATH, BRIDGE_HISTORY_FETCHER_CONFIG_PATH, CHAIN_MONITOR_CONFIG_PATH, CHAIN_MONITOR_CONFIG_TEMPLATE_PATH, COORDINATOR_API_CONFIG_PATH, COORDINATOR_CONFIG_TEMPLATE_PATH, COORDINATOR_CRON_CONFIG_PATH, GAS_ORACLE_CONFIG_PATH, GENESIS_ALLOC_JSON_PATH, GENESIS_JSON_PATH, ROLLUP_CONFIG_PATH, ROLLUP_CONFIG_TEMPLATE_PATH, ROLLUP_EXPLORER_BACKEND_CONFIG_PATH} from "./Constants.sol"; +import {DeployScroll} from "./DeployScroll.s.sol"; +import {DeterministicDeployment} from "./DeterministicDeployment.sol"; + +contract GenerateRollupConfig is DeployScroll { + using stdToml for string; + + /*************** + * Entry point * + ***************/ + + function run() public { + DeterministicDeployment.initialize(ScriptMode.VerifyConfig); + predictAllContracts(); + + generateRollupConfig(ROLLUP_CONFIG_PATH); + generateRollupConfig(GAS_ORACLE_CONFIG_PATH); + } + + /********************* + * Private functions * + *********************/ + + // prettier-ignore + function generateRollupConfig(string memory PATH) private { + // initialize template file + if (vm.exists(PATH)) { + vm.removeFile(PATH); + } + + string memory template = vm.readFile(ROLLUP_CONFIG_TEMPLATE_PATH); + vm.writeFile(PATH, template); + + // contracts + vm.writeJson(vm.toString(L1_GAS_PRICE_ORACLE_ADDR), PATH, ".l1_config.relayer_config.gas_price_oracle_contract_address"); + vm.writeJson(vm.toString(L2_MESSAGE_QUEUE_ADDR), PATH, ".l2_config.l2_message_queue_address"); + vm.writeJson(vm.toString(L1_SCROLL_CHAIN_PROXY_ADDR), PATH, ".l2_config.relayer_config.rollup_contract_address"); + vm.writeJson(vm.toString(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), PATH, ".l2_config.relayer_config.gas_price_oracle_contract_address"); + + // other + vm.writeJson(vm.toString(TEST_ENV_MOCK_FINALIZE_ENABLED), PATH, ".l2_config.relayer_config.enable_test_env_bypass_features"); + vm.writeJson(vm.toString(TEST_ENV_MOCK_FINALIZE_TIMEOUT_SEC), PATH, ".l2_config.relayer_config.finalize_batch_without_proof_timeout_sec"); + vm.writeJson(vm.toString(TEST_ENV_MOCK_FINALIZE_TIMEOUT_SEC), PATH, ".l2_config.relayer_config.finalize_bundle_without_proof_timeout_sec"); + + vm.writeJson(vm.toString(MAX_BLOCK_IN_CHUNK), PATH, ".l2_config.chunk_proposer_config.max_block_num_per_chunk"); + vm.writeJson(vm.toString(MAX_TX_IN_CHUNK), PATH, ".l2_config.chunk_proposer_config.max_tx_num_per_chunk"); + vm.writeJson(vm.toString(MAX_BATCH_IN_BUNDLE), PATH, ".l2_config.bundle_proposer_config.max_batch_num_per_bundle"); + } +} + +contract GenerateCoordinatorConfig is DeployScroll { + /*************** + * Entry point * + ***************/ + + function run() public { + DeterministicDeployment.initialize(ScriptMode.VerifyConfig); + predictAllContracts(); + + generateCoordinatorConfig(COORDINATOR_API_CONFIG_PATH); + generateCoordinatorConfig(COORDINATOR_CRON_CONFIG_PATH); + } + + /********************* + * Private functions * + *********************/ + + function generateCoordinatorConfig(string memory PATH) private { + // initialize template file + if (vm.exists(PATH)) { + vm.removeFile(PATH); + } + + string memory template = vm.readFile(COORDINATOR_CONFIG_TEMPLATE_PATH); + vm.writeFile(PATH, template); + + // coordinator api + vm.writeJson(CHUNK_COLLECTION_TIME_SEC, PATH, ".prover_manager.chunk_collection_time_sec"); + vm.writeJson(BATCH_COLLECTION_TIME_SEC, PATH, ".prover_manager.batch_collection_time_sec"); + vm.writeJson(BUNDLE_COLLECTION_TIME_SEC, PATH, ".prover_manager.bundle_collection_time_sec"); + vm.writeJson(vm.toString(CHAIN_ID_L2), PATH, ".l2.chain_id"); + vm.writeJson(COORDINATOR_JWT_SECRET_KEY, PATH, ".auth.secret"); + + // coordinator cron + vm.writeJson(CHUNK_COLLECTION_TIME_SEC, PATH, ".prover_manager.chunk_collection_time_sec"); + vm.writeJson(BATCH_COLLECTION_TIME_SEC, PATH, ".prover_manager.batch_collection_time_sec"); + vm.writeJson(BUNDLE_COLLECTION_TIME_SEC, PATH, ".prover_manager.bundle_collection_time_sec"); + vm.writeJson(vm.toString(CHAIN_ID_L2), PATH, ".l2.chain_id"); + vm.writeJson(COORDINATOR_JWT_SECRET_KEY, PATH, ".auth.secret"); + } +} + +contract GenerateChainMonitorConfig is DeployScroll { + /*************** + * Entry point * + ***************/ + + function run() public { + DeterministicDeployment.initialize(ScriptMode.VerifyConfig); + predictAllContracts(); + + generateChainMonitorConfig(CHAIN_MONITOR_CONFIG_PATH); + } + + /********************* + * Private functions * + *********************/ + + // prettier-ignore + function generateChainMonitorConfig(string memory PATH) private { + // initialize template file + if (vm.exists(PATH)) { + vm.removeFile(PATH); + } + + string memory template = vm.readFile(CHAIN_MONITOR_CONFIG_TEMPLATE_PATH); + vm.writeFile(PATH, template); + + // L1 + vm.writeJson(L1_RPC_ENDPOINT, PATH, ".l1_config.l1_url"); + vm.writeJson(vm.toString(L1_CONTRACT_DEPLOYMENT_BLOCK), PATH, ".l1_config.start_number"); + vm.writeJson(vm.toString(L1_ETH_GATEWAY_PROXY_ADDR), PATH, ".l1_config.l1_contracts.l1_gateways.eth_gateway"); + vm.writeJson(vm.toString(L1_WETH_GATEWAY_PROXY_ADDR), PATH, ".l1_config.l1_contracts.l1_gateways.weth_gateway"); + vm.writeJson(vm.toString(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR), PATH, ".l1_config.l1_contracts.l1_gateways.standard_erc20_gateway"); + vm.writeJson(vm.toString(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), PATH, ".l1_config.l1_contracts.l1_gateways.custom_erc20_gateway"); + vm.writeJson(vm.toString(L1_ERC721_GATEWAY_PROXY_ADDR), PATH, ".l1_config.l1_contracts.l1_gateways.erc721_gateway"); + vm.writeJson(vm.toString(L1_ERC1155_GATEWAY_PROXY_ADDR), PATH, ".l1_config.l1_contracts.l1_gateways.erc1155_gateway"); + vm.writeJson(vm.toString(L1_SCROLL_MESSENGER_PROXY_ADDR), PATH, ".l1_config.l1_contracts.scroll_messenger"); + vm.writeJson(vm.toString(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), PATH, ".l1_config.l1_contracts.message_queue"); + vm.writeJson(vm.toString(L1_SCROLL_CHAIN_PROXY_ADDR), PATH, ".l1_config.l1_contracts.scroll_chain"); + vm.writeJson(vm.toString(L2_DEPLOYER_INITIAL_BALANCE), PATH, ".l1_config.start_messenger_balance"); + + // L2 + vm.writeJson(L2_RPC_ENDPOINT, PATH, ".l2_config.l2_url"); + vm.writeJson(vm.toString(L2_ETH_GATEWAY_PROXY_ADDR), PATH, ".l2_config.l2_contracts.l2_gateways.eth_gateway"); + vm.writeJson(vm.toString(L2_WETH_GATEWAY_PROXY_ADDR), PATH, ".l2_config.l2_contracts.l2_gateways.weth_gateway"); + vm.writeJson(vm.toString(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR), PATH, ".l2_config.l2_contracts.l2_gateways.standard_erc20_gateway"); + vm.writeJson(vm.toString(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), PATH, ".l2_config.l2_contracts.l2_gateways.custom_erc20_gateway"); + vm.writeJson(vm.toString(L2_ERC721_GATEWAY_PROXY_ADDR), PATH, ".l2_config.l2_contracts.l2_gateways.erc721_gateway"); + vm.writeJson(vm.toString(L2_ERC1155_GATEWAY_PROXY_ADDR), PATH, ".l2_config.l2_contracts.l2_gateways.erc1155_gateway"); + vm.writeJson(vm.toString(L2_SCROLL_MESSENGER_PROXY_ADDR), PATH, ".l2_config.l2_contracts.scroll_messenger"); + vm.writeJson(vm.toString(L2_MESSAGE_QUEUE_ADDR), PATH, ".l2_config.l2_contracts.message_queue"); + } +} + +contract GenerateBridgeHistoryConfig is DeployScroll { + /*************** + * Entry point * + ***************/ + + function run() public { + DeterministicDeployment.initialize(ScriptMode.VerifyConfig); + predictAllContracts(); + + generateBridgeHistoryConfig(BRIDGE_HISTORY_API_CONFIG_PATH); + generateBridgeHistoryConfig(BRIDGE_HISTORY_FETCHER_CONFIG_PATH); + } + + /********************* + * Private functions * + *********************/ + + // prettier-ignore + function generateBridgeHistoryConfig(string memory PATH) private { + // initialize template file + if (vm.exists(PATH)) { + vm.removeFile(PATH); + } + + string memory template = vm.readFile(BRIDGE_HISTORY_CONFIG_TEMPLATE_PATH); + vm.writeFile(PATH, template); + + // L1 contracts + vm.writeJson(vm.toString(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), PATH, ".L1.MessageQueueAddr"); + vm.writeJson(vm.toString(L1_SCROLL_MESSENGER_PROXY_ADDR), PATH, ".L1.MessengerAddr"); + vm.writeJson(vm.toString(L1_SCROLL_CHAIN_PROXY_ADDR), PATH, ".L1.ScrollChainAddr"); + vm.writeJson(vm.toString(L1_GATEWAY_ROUTER_PROXY_ADDR), PATH, ".L1.GatewayRouterAddr"); + vm.writeJson(vm.toString(L1_ETH_GATEWAY_PROXY_ADDR), PATH, ".L1.ETHGatewayAddr"); + vm.writeJson(vm.toString(L1_WETH_GATEWAY_PROXY_ADDR), PATH, ".L1.WETHGatewayAddr"); + vm.writeJson(vm.toString(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR), PATH, ".L1.StandardERC20GatewayAddr"); + vm.writeJson(vm.toString(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), PATH, ".L1.CustomERC20GatewayAddr"); + vm.writeJson(vm.toString(L1_ERC721_GATEWAY_PROXY_ADDR), PATH, ".L1.ERC721GatewayAddr"); + vm.writeJson(vm.toString(L1_ERC1155_GATEWAY_PROXY_ADDR), PATH, ".L1.ERC1155GatewayAddr"); + vm.writeJson(vm.toString(L1_WRAPPED_TOKEN_GATEWAY_ADDR), PATH, ".L1.WrappedTokenGatewayAddr"); + + // L2 contracts + vm.writeJson(vm.toString(L2_MESSAGE_QUEUE_ADDR), PATH, ".L2.MessageQueueAddr"); + vm.writeJson(vm.toString(L2_SCROLL_MESSENGER_PROXY_ADDR), PATH, ".L2.MessengerAddr"); + vm.writeJson(vm.toString(L2_GATEWAY_ROUTER_PROXY_ADDR), PATH, ".L2.GatewayRouterAddr"); + vm.writeJson(vm.toString(L2_ETH_GATEWAY_PROXY_ADDR), PATH, ".L2.ETHGatewayAddr"); + vm.writeJson(vm.toString(L2_WETH_GATEWAY_PROXY_ADDR), PATH, ".L2.WETHGatewayAddr"); + vm.writeJson(vm.toString(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR), PATH, ".L2.StandardERC20GatewayAddr"); + vm.writeJson(vm.toString(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR), PATH, ".L2.CustomERC20GatewayAddr"); + vm.writeJson(vm.toString(L2_ERC721_GATEWAY_PROXY_ADDR), PATH, ".L2.ERC721GatewayAddr"); + vm.writeJson(vm.toString(L2_ERC1155_GATEWAY_PROXY_ADDR), PATH, ".L2.ERC1155GatewayAddr"); + + // others + vm.writeJson(vm.toString(L1_CONTRACT_DEPLOYMENT_BLOCK), PATH, ".L1.startHeight"); + } +} + +contract GenerateBalanceCheckerConfig is DeployScroll { + /*************** + * Entry point * + ***************/ + + function run() public { + DeterministicDeployment.initialize(ScriptMode.VerifyConfig); + predictAllContracts(); + + generateBalanceCheckerConfig(BALANCE_CHECKER_CONFIG_PATH); + } + + /********************* + * Private functions * + *********************/ + + function generateBalanceCheckerConfig(string memory PATH) private { + // initialize template file + if (vm.exists(PATH)) { + vm.removeFile(PATH); + } + + string memory template = vm.readFile(BALANCE_CHECKER_CONFIG_TEMPLATE_PATH); + vm.writeFile(PATH, template); + + vm.writeJson(vm.toString(L1_COMMIT_SENDER_ADDR), PATH, ".addresses[0].address"); + vm.writeJson(vm.toString(L1_FINALIZE_SENDER_ADDR), PATH, ".addresses[1].address"); + vm.writeJson(vm.toString(L1_GAS_ORACLE_SENDER_ADDR), PATH, ".addresses[2].address"); + vm.writeJson(vm.toString(L1_FEE_VAULT_ADDR), PATH, ".addresses[3].address"); + vm.writeJson(vm.toString(L2_GAS_ORACLE_SENDER_ADDR), PATH, ".addresses[4].address"); + vm.writeJson(vm.toString(L2_TX_FEE_VAULT_ADDR), PATH, ".addresses[5].address"); + } +} diff --git a/scripts/deterministic/GenerateGenesis.s.sol b/scripts/deterministic/GenerateGenesis.s.sol new file mode 100644 index 00000000..d36ed5c6 --- /dev/null +++ b/scripts/deterministic/GenerateGenesis.s.sol @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol"; +import {L2MessageQueue} from "../../src/L2/predeploys/L2MessageQueue.sol"; +import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol"; +import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol"; +import {WrappedEther} from "../../src/L2/predeploys/WrappedEther.sol"; + +import {DETERMINISTIC_DEPLOYMENT_PROXY_ADDR, FEE_VAULT_MIN_WITHDRAW_AMOUNT, GENESIS_ALLOC_JSON_PATH, GENESIS_JSON_PATH, GENESIS_JSON_TEMPLATE_PATH} from "./Constants.sol"; +import {DeployScroll} from "./DeployScroll.s.sol"; +import {DeterministicDeployment} from "./DeterministicDeployment.sol"; + +contract GenerateGenesis is DeployScroll { + /*************** + * Entry point * + ***************/ + + function run() public { + DeterministicDeployment.initialize(ScriptMode.VerifyConfig); + predictAllContracts(); + + generateGenesisAlloc(); + generateGenesisJson(); + + // clean up temporary files + vm.removeFile(GENESIS_ALLOC_JSON_PATH); + } + + /********************* + * Private functions * + *********************/ + + function generateGenesisAlloc() private { + if (vm.exists(GENESIS_ALLOC_JSON_PATH)) { + vm.removeFile(GENESIS_ALLOC_JSON_PATH); + } + + // Scroll predeploys + setL2MessageQueue(); + setL1GasPriceOracle(); + setL2Whitelist(); + setL2Weth(); + setL2FeeVault(); + + // other predeploys + setDeterministicDeploymentProxy(); + + // reset sender + vm.resetNonce(msg.sender); + + // prefunded accounts + setL2ScrollMessenger(); + setL2Deployer(); + + // write to file + vm.dumpState(GENESIS_ALLOC_JSON_PATH); + sortJsonByKeys(GENESIS_ALLOC_JSON_PATH); + } + + function setL2MessageQueue() internal { + address predeployAddr = tryGetOverride("L2_MESSAGE_QUEUE"); + + if (predeployAddr == address(0)) { + return; + } + + // set code + L2MessageQueue _queue = new L2MessageQueue(DEPLOYER_ADDR); + vm.etch(predeployAddr, address(_queue).code); + + // set storage + bytes32 _ownerSlot = hex"0000000000000000000000000000000000000000000000000000000000000052"; + vm.store(predeployAddr, _ownerSlot, vm.load(address(_queue), _ownerSlot)); + + // reset so its not included state dump + vm.etch(address(_queue), ""); + vm.resetNonce(address(_queue)); + } + + function setL1GasPriceOracle() internal { + address predeployAddr = tryGetOverride("L1_GAS_PRICE_ORACLE"); + + if (predeployAddr == address(0)) { + return; + } + + // set code + L1GasPriceOracle _oracle = new L1GasPriceOracle(DEPLOYER_ADDR); + vm.etch(predeployAddr, address(_oracle).code); + + // set storage + bytes32 _ownerSlot = hex"0000000000000000000000000000000000000000000000000000000000000000"; + vm.store(predeployAddr, _ownerSlot, vm.load(address(_oracle), _ownerSlot)); + + bytes32 _isCurieSlot = hex"0000000000000000000000000000000000000000000000000000000000000008"; + vm.store(predeployAddr, _isCurieSlot, bytes32(uint256(1))); + + // reset so its not included state dump + vm.etch(address(_oracle), ""); + vm.resetNonce(address(_oracle)); + } + + function setL2Whitelist() internal { + address predeployAddr = tryGetOverride("L2_WHITELIST"); + + if (predeployAddr == address(0)) { + return; + } + + // set code + Whitelist _whitelist = new Whitelist(DEPLOYER_ADDR); + vm.etch(predeployAddr, address(_whitelist).code); + + // set storage + bytes32 _ownerSlot = hex"0000000000000000000000000000000000000000000000000000000000000000"; + vm.store(predeployAddr, _ownerSlot, vm.load(address(_whitelist), _ownerSlot)); + + // reset so its not included state dump + vm.etch(address(_whitelist), ""); + vm.resetNonce(address(_whitelist)); + } + + function setL2Weth() internal { + address predeployAddr = tryGetOverride("L2_WETH"); + + if (predeployAddr == address(0)) { + return; + } + + // set code + WrappedEther _weth = new WrappedEther(); + vm.etch(predeployAddr, address(_weth).code); + + // set storage + bytes32 _nameSlot = hex"0000000000000000000000000000000000000000000000000000000000000003"; + vm.store(predeployAddr, _nameSlot, vm.load(address(_weth), _nameSlot)); + + bytes32 _symbolSlot = hex"0000000000000000000000000000000000000000000000000000000000000004"; + vm.store(predeployAddr, _symbolSlot, vm.load(address(_weth), _symbolSlot)); + + // reset so its not included state dump + vm.etch(address(_weth), ""); + vm.resetNonce(address(_weth)); + } + + function setL2FeeVault() internal { + address predeployAddr = tryGetOverride("L2_TX_FEE_VAULT"); + + if (predeployAddr == address(0)) { + return; + } + + // set code + address _vaultAddr; + vm.prank(DEPLOYER_ADDR); + L2TxFeeVault _vault = new L2TxFeeVault(DEPLOYER_ADDR, L1_FEE_VAULT_ADDR, FEE_VAULT_MIN_WITHDRAW_AMOUNT); + vm.prank(DEPLOYER_ADDR); + _vault.updateMessenger(L2_SCROLL_MESSENGER_PROXY_ADDR); + _vaultAddr = address(_vault); + + vm.etch(predeployAddr, _vaultAddr.code); + + // set storage + bytes32 _ownerSlot = hex"0000000000000000000000000000000000000000000000000000000000000000"; + vm.store(predeployAddr, _ownerSlot, vm.load(_vaultAddr, _ownerSlot)); + + bytes32 _minWithdrawAmountSlot = hex"0000000000000000000000000000000000000000000000000000000000000001"; + vm.store(predeployAddr, _minWithdrawAmountSlot, vm.load(_vaultAddr, _minWithdrawAmountSlot)); + + bytes32 _messengerSlot = hex"0000000000000000000000000000000000000000000000000000000000000002"; + vm.store(predeployAddr, _messengerSlot, vm.load(_vaultAddr, _messengerSlot)); + + bytes32 _recipientSlot = hex"0000000000000000000000000000000000000000000000000000000000000003"; + vm.store(predeployAddr, _recipientSlot, vm.load(_vaultAddr, _recipientSlot)); + + bytes32 _ETHGatewaySlot = hex"0000000000000000000000000000000000000000000000000000000000000005"; + vm.store(predeployAddr, _ETHGatewaySlot, vm.load(_vaultAddr, _ETHGatewaySlot)); + + // reset so its not included state dump + vm.etch(_vaultAddr, ""); + vm.resetNonce(_vaultAddr); + } + + function setDeterministicDeploymentProxy() internal { + bytes + memory code = hex"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"; + vm.etch(DETERMINISTIC_DEPLOYMENT_PROXY_ADDR, code); + } + + function setL2ScrollMessenger() internal { + vm.deal(L2_SCROLL_MESSENGER_PROXY_ADDR, L2_SCROLL_MESSENGER_INITIAL_BALANCE); + } + + function setL2Deployer() internal { + vm.deal(DEPLOYER_ADDR, L2_DEPLOYER_INITIAL_BALANCE); + } + + function generateGenesisJson() private { + // initialize template file + if (vm.exists(GENESIS_JSON_PATH)) { + vm.removeFile(GENESIS_JSON_PATH); + } + + string memory template = vm.readFile(GENESIS_JSON_TEMPLATE_PATH); + vm.writeFile(GENESIS_JSON_PATH, template); + + // general config + vm.writeJson(vm.toString(CHAIN_ID_L2), GENESIS_JSON_PATH, ".config.chainId"); + + uint256 timestamp = vm.unixTime() / 1000; + vm.writeJson(vm.toString(bytes32(timestamp)), GENESIS_JSON_PATH, ".timestamp"); + + string memory extraData = string( + abi.encodePacked( + "0x0000000000000000000000000000000000000000000000000000000000000000", + vm.replace(vm.toString(L2GETH_SIGNER_ADDRESS), "0x", ""), + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) + ); + + vm.writeJson(extraData, GENESIS_JSON_PATH, ".extraData"); + + // scroll-specific config + vm.writeJson(vm.toString(MAX_TX_IN_CHUNK), GENESIS_JSON_PATH, ".config.scroll.maxTxPerBlock"); + vm.writeJson(vm.toString(L2_TX_FEE_VAULT_ADDR), GENESIS_JSON_PATH, ".config.scroll.feeVaultAddress"); + + // serialize explicitly as string, otherwise foundry will serialize it as number + string memory l1ChainId = string(abi.encodePacked('"', vm.toString(CHAIN_ID_L1), '"')); + vm.writeJson(l1ChainId, GENESIS_JSON_PATH, ".config.scroll.l1Config.l1ChainId"); + + vm.writeJson( + vm.toString(SYSTEM_CONFIG_PROXY_ADDR), + GENESIS_JSON_PATH, + ".config.systemContract.system_contract_address" + ); + + vm.writeJson( + vm.toString(L1_MESSAGE_QUEUE_V1_PROXY_ADDR), + GENESIS_JSON_PATH, + ".config.scroll.l1Config.l1MessageQueueAddress" + ); + + vm.writeJson( + vm.toString(L1_MESSAGE_QUEUE_V2_PROXY_ADDR), + GENESIS_JSON_PATH, + ".config.scroll.l1Config.l1MessageQueueV2Address" + ); + + vm.writeJson( + vm.toString(L1_SCROLL_CHAIN_PROXY_ADDR), + GENESIS_JSON_PATH, + ".config.scroll.l1Config.scrollChainAddress" + ); + + // predeploys and prefunded accounts + string memory alloc = vm.readFile(GENESIS_ALLOC_JSON_PATH); + vm.writeJson(alloc, GENESIS_JSON_PATH, ".alloc"); + } + + /// @notice Sorts the allocs by address + // source: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/scripts/L2Genesis.s.sol + function sortJsonByKeys(string memory _path) private { + string[] memory commands = new string[](3); + commands[0] = "/bin/bash"; + commands[1] = "-c"; + commands[2] = string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path); + vm.ffi(commands); + } +} diff --git a/scripts/deterministic/config/config-contracts.toml b/scripts/deterministic/config/config-contracts.toml new file mode 100644 index 00000000..974a30ab --- /dev/null +++ b/scripts/deterministic/config/config-contracts.toml @@ -0,0 +1,58 @@ +L1_WETH_ADDR = "" +L1_PROXY_ADMIN_ADDR = "" +L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR = "" +L1_WHITELIST_ADDR = "" +L1_SCROLL_CHAIN_PROXY_ADDR = "" +L1_SCROLL_MESSENGER_PROXY_ADDR = "" +L1_MESSAGE_QUEUE_V1_IMPLEMENTATION_ADDR = "" +L1_MESSAGE_QUEUE_V1_PROXY_ADDR = "" +L1_MESSAGE_QUEUE_V2_IMPLEMENTATION_ADDR = "" +L1_MESSAGE_QUEUE_V2_PROXY_ADDR = "" +L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = "" +L1_PLONK_VERIFIER_ADDR = "" +L1_ZKEVM_VERIFIER_V2_ADDR = "" +L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = "" +L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR = "" +L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR = "" +L1_GATEWAY_ROUTER_PROXY_ADDR = "" +L1_ETH_GATEWAY_PROXY_ADDR = "" +L1_WETH_GATEWAY_PROXY_ADDR = "" +L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = "" +L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = "" +L1_ERC721_GATEWAY_PROXY_ADDR = "" +L1_ERC1155_GATEWAY_PROXY_ADDR = "" +L2_MESSAGE_QUEUE_ADDR = "" +L1_GAS_PRICE_ORACLE_ADDR = "" +L2_WHITELIST_ADDR = "" +L2_WETH_ADDR = "" +L2_TX_FEE_VAULT_ADDR = "" +L2_PROXY_ADMIN_ADDR = "" +L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR = "" +L2_SCROLL_MESSENGER_PROXY_ADDR = "" +L2_ETH_GATEWAY_PROXY_ADDR = "" +L2_WETH_GATEWAY_PROXY_ADDR = "" +L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = "" +L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = "" +L2_ERC721_GATEWAY_PROXY_ADDR = "" +L2_ERC1155_GATEWAY_PROXY_ADDR = "" +L2_SCROLL_STANDARD_ERC20_ADDR = "" +L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = "" +L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = "" +L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_WETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = "" +L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR = "" +L2_GATEWAY_ROUTER_PROXY_ADDR = "" +L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_ETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_WETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = "" +SYSTEM_CONFIG_IMPLEMENTATION_ADDR = "" +SYSTEM_CONFIG_PROXY_ADDR = "" \ No newline at end of file diff --git a/scripts/deterministic/config/config-contracts.toml.template b/scripts/deterministic/config/config-contracts.toml.template new file mode 100644 index 00000000..974a30ab --- /dev/null +++ b/scripts/deterministic/config/config-contracts.toml.template @@ -0,0 +1,58 @@ +L1_WETH_ADDR = "" +L1_PROXY_ADMIN_ADDR = "" +L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR = "" +L1_WHITELIST_ADDR = "" +L1_SCROLL_CHAIN_PROXY_ADDR = "" +L1_SCROLL_MESSENGER_PROXY_ADDR = "" +L1_MESSAGE_QUEUE_V1_IMPLEMENTATION_ADDR = "" +L1_MESSAGE_QUEUE_V1_PROXY_ADDR = "" +L1_MESSAGE_QUEUE_V2_IMPLEMENTATION_ADDR = "" +L1_MESSAGE_QUEUE_V2_PROXY_ADDR = "" +L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = "" +L1_PLONK_VERIFIER_ADDR = "" +L1_ZKEVM_VERIFIER_V2_ADDR = "" +L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = "" +L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR = "" +L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR = "" +L1_GATEWAY_ROUTER_PROXY_ADDR = "" +L1_ETH_GATEWAY_PROXY_ADDR = "" +L1_WETH_GATEWAY_PROXY_ADDR = "" +L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = "" +L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = "" +L1_ERC721_GATEWAY_PROXY_ADDR = "" +L1_ERC1155_GATEWAY_PROXY_ADDR = "" +L2_MESSAGE_QUEUE_ADDR = "" +L1_GAS_PRICE_ORACLE_ADDR = "" +L2_WHITELIST_ADDR = "" +L2_WETH_ADDR = "" +L2_TX_FEE_VAULT_ADDR = "" +L2_PROXY_ADMIN_ADDR = "" +L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR = "" +L2_SCROLL_MESSENGER_PROXY_ADDR = "" +L2_ETH_GATEWAY_PROXY_ADDR = "" +L2_WETH_GATEWAY_PROXY_ADDR = "" +L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = "" +L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = "" +L2_ERC721_GATEWAY_PROXY_ADDR = "" +L2_ERC1155_GATEWAY_PROXY_ADDR = "" +L2_SCROLL_STANDARD_ERC20_ADDR = "" +L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = "" +L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = "" +L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_WETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR = "" +L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = "" +L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR = "" +L2_GATEWAY_ROUTER_PROXY_ADDR = "" +L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_ETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_WETH_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR = "" +L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = "" +SYSTEM_CONFIG_IMPLEMENTATION_ADDR = "" +SYSTEM_CONFIG_PROXY_ADDR = "" \ No newline at end of file diff --git a/scripts/deterministic/config/config.toml b/scripts/deterministic/config/config.toml new file mode 100644 index 00000000..0d477685 --- /dev/null +++ b/scripts/deterministic/config/config.toml @@ -0,0 +1,74 @@ +[general] + +CHAIN_ID_L1 = 111111 +CHAIN_ID_L2 = 221122 + +L1_CONTRACT_DEPLOYMENT_BLOCK = 0 + +[accounts] + +# note: for now we simply use Anvil's dev accounts + +DEPLOYER_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + +L1_COMMIT_SENDER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" +L1_FINALIZE_SENDER_PRIVATE_KEY = "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" +L1_GAS_ORACLE_SENDER_PRIVATE_KEY = "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" +L2_GAS_ORACLE_SENDER_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + +DEPLOYER_ADDR = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +OWNER_ADDR = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +L1_COMMIT_SENDER_ADDR = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +L1_FINALIZE_SENDER_ADDR = "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" +L1_GAS_ORACLE_SENDER_ADDR = "0x90F79bf6EB2c4f870365E785982E1f101E93b906" +L2_GAS_ORACLE_SENDER_ADDR = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[sequencer] + +L2GETH_SIGNER_ADDRESS = "0x756EA06BDEe36de11F22DCca45a31d8a178eF3c6" +L2GETH_KEYSTORE = '{"address":"756ea06bdee36de11f22dcca45a31d8a178ef3c6","crypto":{"cipher":"aes-128-ctr","ciphertext":"8bfb4e48c6b172f1f5794d2874476ca62f8184507c0916dbd45fe77a0056114c","cipherparams":{"iv":"509eb70e7379a776e0779634b6668277"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ef0f0334e5db7c12d76993e1e9627593fd0d7cd44444b689e792c86bc8a5d75f"},"mac":"d766cac11d0bd563316f5655ebf07550b6fce98ba0ca3c13acdc1b65f5f185ca"},"id":"4459ad67-f2ce-48b2-8940-c0582106a4c6","version":3}' +L2GETH_PASSWORD = "scroll2022" +L2GETH_NODEKEY = "2f59ff2fdee1c42a3d8c8980c313bc8fd6c2557463f7bb92b0f0bc89a6d3cbf01" +L2_GETH_STATIC_PEERS = '["enode://848a7d59dd8f60dd1a51160e6bc15c194937855443de9be4b2abd83e11a5c4ac21d61d065448c5c520826fe83f1f29eb5a452daccca27b8113aa897074132507@l2-sequencer:30303"]' + +[rollup] + +MAX_TX_IN_CHUNK = 100 +MAX_BLOCK_IN_CHUNK = 100 +MAX_BATCH_IN_BUNDLE = 30 +MAX_L1_MESSAGE_GAS_LIMIT = 10_000_000 +FINALIZE_BATCH_DEADLINE_SEC = 600 +RELAY_MESSAGE_DEADLINE_SEC = 600 +TEST_ENV_MOCK_FINALIZE_ENABLED = true +TEST_ENV_MOCK_FINALIZE_TIMEOUT_SEC = 300 + +[genesis] + +L2_MAX_ETH_SUPPLY = "226156424291633194186662080095093570025917938800079226639565593765455331328" +L2_DEPLOYER_INITIAL_BALANCE = 1000000000000000000 + +[contracts] + +DEPLOYMENT_SALT = "devnetSalt-000" + +# contracts deployed outside this script +L1_FEE_VAULT_ADDR = "0x0000000000000000000000000000000000000001" + +[contracts.overrides] + +# L1_WETH = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" +# L1_PLONK_VERIFIER = "0x0000000000000000000000000000000000000001" + +L2_MESSAGE_QUEUE = "0x5300000000000000000000000000000000000000" +L1_GAS_PRICE_ORACLE = "0x5300000000000000000000000000000000000002" +L2_WHITELIST = "0x5300000000000000000000000000000000000003" +L2_WETH = "0x5300000000000000000000000000000000000004" +L2_TX_FEE_VAULT = "0x5300000000000000000000000000000000000005" + +[coordinator] + +CHUNK_COLLECTION_TIME_SEC = 3600 +BATCH_COLLECTION_TIME_SEC = 1800 +BUNDLE_COLLECTION_TIME_SEC = 600 +COORDINATOR_JWT_SECRET_KEY = "e788b62d39254928a821ac1c76b274a8c835aa1e20ecfb6f50eb10e87847de44" \ No newline at end of file diff --git a/scripts/deterministic/contracts/MultipleVersionRollupVerifierSetOwner.sol b/scripts/deterministic/contracts/MultipleVersionRollupVerifierSetOwner.sol new file mode 100644 index 00000000..21eecac3 --- /dev/null +++ b/scripts/deterministic/contracts/MultipleVersionRollupVerifierSetOwner.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {MultipleVersionRollupVerifier} from "../../../src/L1/rollup/MultipleVersionRollupVerifier.sol"; + +contract MultipleVersionRollupVerifierSetOwner is MultipleVersionRollupVerifier { + /// @dev allow setting the owner in the constructor, otherwise + /// DeterministicDeploymentProxy would become the owner. + constructor( + address owner, + uint256[] memory _versions, + address[] memory _verifiers + ) MultipleVersionRollupVerifier(_versions, _verifiers) { + _transferOwnership(owner); + } +} diff --git a/scripts/deterministic/contracts/ProxyAdminSetOwner.sol b/scripts/deterministic/contracts/ProxyAdminSetOwner.sol new file mode 100644 index 00000000..a3283346 --- /dev/null +++ b/scripts/deterministic/contracts/ProxyAdminSetOwner.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +contract ProxyAdminSetOwner is ProxyAdmin { + /// @dev allow setting the owner in the constructor, otherwise + /// DeterministicDeploymentProxy would become the owner. + constructor(address owner) { + _transferOwnership(owner); + } +} diff --git a/scripts/deterministic/contracts/ScrollStandardERC20FactorySetOwner.sol b/scripts/deterministic/contracts/ScrollStandardERC20FactorySetOwner.sol new file mode 100644 index 00000000..7b18d8cf --- /dev/null +++ b/scripts/deterministic/contracts/ScrollStandardERC20FactorySetOwner.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity =0.8.24; + +import {ScrollStandardERC20Factory} from "../../../src/libraries/token/ScrollStandardERC20Factory.sol"; + +contract ScrollStandardERC20FactorySetOwner is ScrollStandardERC20Factory { + /// @dev allow setting the owner in the constructor, otherwise + /// DeterministicDeploymentProxy would become the owner. + constructor(address owner, address _implementation) ScrollStandardERC20Factory(_implementation) { + _transferOwnership(owner); + } +} diff --git a/scripts/deterministic/shell/deploy.sh b/scripts/deterministic/shell/deploy.sh new file mode 100755 index 00000000..e7319a48 --- /dev/null +++ b/scripts/deterministic/shell/deploy.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +export FOUNDRY_EVM_VERSION="cancun" +export FOUNDRY_BYTECODE_HASH="none" + +if [ "${L1_RPC_ENDPOINT}" = "" ]; then + echo "L1_RPC_ENDPOINT is not set" + exit +fi + +if [ "$L2_RPC_ENDPOINT" = "" ]; then + echo "L2_RPC_ENDPOINT is not set" + exit +fi + +if [ "${BATCH_SIZE}" = "" ]; then + BATCH_SIZE="100" +fi + +echo "using L1_RPC_ENDPOINT = $L1_RPC_ENDPOINT" +echo "using L2_RPC_ENDPOINT = $L2_RPC_ENDPOINT" + +# simulate L1 +echo "" +echo "simulating on L1" +forge script scripts/deterministic/DeployScroll.s.sol:DeployScroll --rpc-url "$L1_RPC_ENDPOINT" --sig "run(string,string)" "L1" "verify-config" || exit 1 + +# simulate L2 +echo "" +echo "simulating on L2" +forge script scripts/deterministic/DeployScroll.s.sol:DeployScroll --rpc-url "$L2_RPC_ENDPOINT" --sig "run(string,string)" "L2" "verify-config" --legacy || exit 1 + +# deploy L1 +echo "" +echo "deploying on L1" +forge script scripts/deterministic/DeployScroll.s.sol:DeployScroll --rpc-url "$L1_RPC_ENDPOINT" --batch-size "$BATCH_SIZE" --sig "run(string,string)" "L1" "verify-config" --broadcast || exit 1 + +# deploy L2 +echo "" +echo "deploying on L2" +forge script scripts/deterministic/DeployScroll.s.sol:DeployScroll --rpc-url "$L2_RPC_ENDPOINT" --batch-size "$BATCH_SIZE" --sig "run(string,string)" "L2" "verify-config" --broadcast --legacy || exit 1 \ No newline at end of file diff --git a/scripts/deterministic/shell/update-configs.sh b/scripts/deterministic/shell/update-configs.sh new file mode 100755 index 00000000..07ed9c9c --- /dev/null +++ b/scripts/deterministic/shell/update-configs.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +echo "" +echo "generating config-contracts.toml" +forge script scripts/deterministic/DeployScroll.s.sol:DeployScroll --sig "run(string,string)" "none" "write-config" || exit 1 + +echo "" +echo "updating genesis.yaml" +forge script scripts/deterministic/GenerateGenesis.s.sol:GenerateGenesis || exit 1 + +echo "" +echo "updating rollup-config.yaml" +forge script scripts/deterministic/GenerateConfigs.s.sol:GenerateRollupConfig || exit 1 + +echo "" +echo "updating coordinator-config.yaml" +forge script scripts/deterministic/GenerateConfigs.s.sol:GenerateCoordinatorConfig || exit 1 + +# echo "" +# echo "updating chain-monitor-config.yaml" +# forge script scripts/deterministic/GenerateConfigs.s.sol:GenerateChainMonitorConfig || exit 1 + +# echo "" +# echo "updating bridge-history-config.yaml" +# forge script scripts/deterministic/GenerateConfigs.s.sol:GenerateBridgeHistoryConfig || exit 1 + +# echo "" +# echo "updating balance-checker-config.yaml" +# forge script scripts/deterministic/GenerateConfigs.s.sol:GenerateBalanceCheckerConfig || exit 1 \ No newline at end of file