diff --git a/docker/config-example.toml b/docker/config-example.toml index 7676c5cd..09df81db 100644 --- a/docker/config-example.toml +++ b/docker/config-example.toml @@ -67,7 +67,7 @@ L1_PLONK_VERIFIER_ADDR = "0x0000000000000000000000000000000000000001" [contracts.overrides] # L1_WETH = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" -# L1_GAS_TOKEN = "0x0000000000000000000000000000000000000000" +# L1_GAS_TOKEN = "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" L2_MESSAGE_QUEUE = "0x5300000000000000000000000000000000000000" L1_GAS_PRICE_ORACLE = "0x5300000000000000000000000000000000000002" diff --git a/docker/scripts/deploy.sh b/docker/scripts/deploy.sh index 6441b2be..286dcd17 100755 --- a/docker/scripts/deploy.sh +++ b/docker/scripts/deploy.sh @@ -13,11 +13,6 @@ if [ "$L2_RPC_ENDPOINT" = "" ]; then L2_RPC_ENDPOINT="http://host.docker.internal:8545" fi -if [ "${L1_RPC_ENDPOINT}" = "" ]; then - echo "L1_RPC_ENDPOINT is not set" - L1_RPC_ENDPOINT="http://host.docker.internal:8543" -fi - if [ "${BATCH_SIZE}" = "" ]; then BATCH_SIZE="100" fi diff --git a/scripts/deterministic/DeployScroll.s.sol b/scripts/deterministic/DeployScroll.s.sol index 076e29d9..fac74df2 100644 --- a/scripts/deterministic/DeployScroll.s.sol +++ b/scripts/deterministic/DeployScroll.s.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.24; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; @@ -241,23 +242,88 @@ contract DeployScroll is DeterminsticDeployment { } } - function checkDeployerBalance() private view { + 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 (", + "[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 && !ALTERNATIVE_GAS_TOKEN_ENABLED) { + uint256 l1MessengerBalance = address(L1_SCROLL_MESSENGER_PROXY_ADDR).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) + ) + ) + ); + } + } + + // check funds for initial deposit (L1, alternative gas token) + // skip it if L1_GAS_TOKEN is not configured in the config file + address gasTokenAddr = tryGetOverride("L1_GAS_TOKEN"); + if (broadcastLayer == Layer.L1 && ALTERNATIVE_GAS_TOKEN_ENABLED && gasTokenAddr != address(0)) { + uint256 l1GasTokenGatewayBalance = IERC20Metadata(L1_GAS_TOKEN_ADDR).balanceOf( + L1_GAS_TOKEN_GATEWAY_PROXY_ADDR + ); + + uint256 scale = 10**(18 - IERC20Metadata(L1_GAS_TOKEN_ADDR).decimals()); + uint256 amountToLock = L2_DEPLOYER_INITIAL_BALANCE / scale; + if (L2_DEPLOYER_INITIAL_BALANCE % scale != 0) { + amountToLock += 1; + } + + uint256 amountToSend = 0; + if (l1GasTokenGatewayBalance < amountToLock) { + amountToSend = amountToLock - l1GasTokenGatewayBalance; + } + + uint256 minBalance = amountToSend; + + if (IERC20Metadata(L1_GAS_TOKEN_ADDR).balanceOf(DEPLOYER_ADDR) < minBalance) { + revert( + string( + abi.encodePacked( + "[ERROR] insufficient funds on deployer account for initial deposit (", + vm.toString(DEPLOYER_ADDR), + ") minimum ", + IERC20Metadata(L1_GAS_TOKEN_ADDR).symbol(), + " balance (in min token unit): ", + vm.toString(minBalance) + ) + ) + ); + } + } } function deployAllContracts() private { @@ -360,6 +426,11 @@ contract DeployScroll is DeterminsticDeployment { // alternative gas token contracts initializeL1GasTokenGateway(); + // lock tokens on L1 to ensure bridge parity, + // we lock ETH in L1ScrollMessenger or GAS_TOKEN in L1GasTokenGateway + // note: this can only be done before transferring ownership + lockTokensOnL1(); + transferL1ContractOwnership(); } @@ -1292,6 +1363,33 @@ contract DeployScroll is DeterminsticDeployment { } } + function lockTokensOnL1() private { + if (!ALTERNATIVE_GAS_TOKEN_ENABLED) { + uint256 l1MessengerBalance = address(L1_SCROLL_MESSENGER_PROXY_ADDR).balance; + uint256 amountToLock = L2_DEPLOYER_INITIAL_BALANCE; + + if (l1MessengerBalance < amountToLock) { + uint256 amountToSend = amountToLock - l1MessengerBalance; + payable(L1_SCROLL_MESSENGER_PROXY_ADDR).transfer(amountToSend); + } + } else { + uint256 l1GasTokenGatewayBalance = IERC20Metadata(L1_GAS_TOKEN_ADDR).balanceOf( + L1_GAS_TOKEN_GATEWAY_PROXY_ADDR + ); + + uint256 scale = 10**(18 - IERC20Metadata(L1_GAS_TOKEN_ADDR).decimals()); + uint256 amountToLock = L2_DEPLOYER_INITIAL_BALANCE / scale; + if (L2_DEPLOYER_INITIAL_BALANCE % scale != 0) { + amountToLock += 1; + } + + if (l1GasTokenGatewayBalance < amountToLock) { + uint256 amountTosend = amountToLock - l1GasTokenGatewayBalance; + IERC20Metadata(L1_GAS_TOKEN_ADDR).transfer(L1_GAS_TOKEN_GATEWAY_PROXY_ADDR, amountTosend); + } + } + } + function transferL1ContractOwnership() private { if (Ownable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR).owner() != OWNER_ADDR) { Ownable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR).transferOwnership(OWNER_ADDR); diff --git a/scripts/deterministic/GenerateConfigs.s.sol b/scripts/deterministic/GenerateConfigs.s.sol index c926fe6a..68d9f4b4 100644 --- a/scripts/deterministic/GenerateConfigs.s.sol +++ b/scripts/deterministic/GenerateConfigs.s.sol @@ -133,6 +133,7 @@ contract GenerateChainMonitorConfig is DeployScroll { vm.writeJson(vm.toString(L1_MESSAGE_QUEUE_PROXY_ADDR), CHAIN_MONITOR_CONFIG_PATH, ".l1_config.l1_contracts.message_queue"); vm.writeJson(vm.toString(L1_SCROLL_CHAIN_PROXY_ADDR), CHAIN_MONITOR_CONFIG_PATH, ".l1_config.l1_contracts.scroll_chain"); vm.writeJson(vm.toString(L1_GAS_TOKEN_ADDR), CHAIN_MONITOR_CONFIG_PATH, ".l1_config.l1_contracts.gas_token"); + vm.writeJson(vm.toString(L2_DEPLOYER_INITIAL_BALANCE), CHAIN_MONITOR_CONFIG_PATH, ".l1_config.start_messenger_balance"); // L2 vm.writeJson(L2_RPC_ENDPOINT, CHAIN_MONITOR_CONFIG_PATH, ".l2_config.l2_url");