diff --git a/.circleci/config.yml b/.circleci/config.yml index 119e7399770..0f74b7e3b48 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -420,7 +420,7 @@ jobs: contracts-bedrock-build: docker: - image: <> - resource_class: xlarge + resource_class: 2xlarge parameters: build_args: description: Forge build arguments @@ -720,7 +720,7 @@ jobs: circleci_ip_ranges: true docker: - image: <> - resource_class: xlarge + resource_class: 2xlarge parameters: test_list: description: List of test files to run diff --git a/.gitignore b/.gitignore index bf22c3755f5..4031cb1d276 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,4 @@ __pycache__ crytic-export # ignore local asdf config -.tool-versions +.tool-versions \ No newline at end of file diff --git a/packages/contracts-bedrock/interfaces/L1/IFeesDepositor.sol b/packages/contracts-bedrock/interfaces/L1/IFeesDepositor.sol index 30c76e962e0..09c4ed009e5 100644 --- a/packages/contracts-bedrock/interfaces/L1/IFeesDepositor.sol +++ b/packages/contracts-bedrock/interfaces/L1/IFeesDepositor.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { ISemver } from "interfaces/universal/ISemver.sol"; import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol"; import { IReinitializableBase } from "interfaces/universal/IReinitializableBase.sol"; -import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; +import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; interface IFeesDepositor is ISemver, IProxyAdminOwnedBase, IReinitializableBase { event Initialized(uint8 version); @@ -12,23 +12,23 @@ interface IFeesDepositor is ISemver, IProxyAdminOwnedBase, IReinitializableBase event FeesDeposited(address indexed l2Recipient, uint256 amount); event MinDepositAmountUpdated(uint96 oldMinDepositAmount, uint96 newMinDepositAmount); event L2RecipientUpdated(address oldL2Recipient, address newL2Recipient); - event GasLimitUpdated(uint64 oldGasLimit, uint64 newGasLimit); + event GasLimitUpdated(uint32 oldGasLimit, uint32 newGasLimit); function minDepositAmount() external view returns (uint96); - function portal() external view returns (IOptimismPortal); + function messenger() external view returns (IL1CrossDomainMessenger); function l2Recipient() external view returns (address); - function gasLimit() external view returns (uint64); + function gasLimit() external view returns (uint32); function initialize( uint96 _minDepositAmount, address _l2Recipient, - IOptimismPortal _portal, - uint64 _gasLimit + IL1CrossDomainMessenger _messenger, + uint32 _gasLimit ) external; function setMinDepositAmount(uint96 _newMinDepositAmount) external; function setL2Recipient(address _newL2Recipient) external; - function setGasLimit(uint64 _newGasLimit) external; + function setGasLimit(uint32 _newGasLimit) external; receive() external payable; diff --git a/packages/contracts-bedrock/interfaces/L2/IL1Withdrawer.sol b/packages/contracts-bedrock/interfaces/L2/IL1Withdrawer.sol index 59bae92afe1..b1d2b58dea3 100644 --- a/packages/contracts-bedrock/interfaces/L2/IL1Withdrawer.sol +++ b/packages/contracts-bedrock/interfaces/L2/IL1Withdrawer.sol @@ -5,23 +5,22 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; interface IL1Withdrawer is ISemver { error L1Withdrawer_OnlyProxyAdminOwner(); - error L1Withdrawer_WithdrawalGasLimitTooLow(); event WithdrawalInitiated(address indexed recipient, uint256 amount); event FundsReceived(address indexed sender, uint256 amount, uint256 newBalance); event MinWithdrawalAmountUpdated(uint256 oldMinWithdrawalAmount, uint256 newMinWithdrawalAmount); event RecipientUpdated(address oldRecipient, address newRecipient); - event WithdrawalGasLimitUpdated(uint96 oldWithdrawalGasLimit, uint96 newWithdrawalGasLimit); + event WithdrawalGasLimitUpdated(uint32 oldWithdrawalGasLimit, uint32 newWithdrawalGasLimit); function minWithdrawalAmount() external view returns (uint256); function recipient() external view returns (address); - function withdrawalGasLimit() external view returns (uint96); + function withdrawalGasLimit() external view returns (uint32); function setMinWithdrawalAmount(uint256 _newMinWithdrawalAmount) external; function setRecipient(address _newRecipient) external; - function setWithdrawalGasLimit(uint96 _newWithdrawalGasLimit) external; + function setWithdrawalGasLimit(uint32 _newWithdrawalGasLimit) external; receive() external payable; - function __constructor__(uint256 _minWithdrawalAmount, address _recipient, uint96 _withdrawalGasLimit) external; + function __constructor__(uint256 _minWithdrawalAmount, address _recipient, uint32 _withdrawalGasLimit) external; } diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 9132b9677fb..af6d0b699ce 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -86,7 +86,7 @@ contract L2Genesis is Script { uint256 internal constant PRECOMPILE_COUNT = 256; uint80 internal constant DEV_ACCOUNT_FUND_AMT = 10_000 ether; - uint96 internal constant WITHDRAWAL_MIN_GAS_LIMIT = 300_000; + uint32 internal constant WITHDRAWAL_MIN_GAS_LIMIT = 1_000_000; uint256 internal constant MIN_WITHDRAWAL_AMOUNT_THRESHOLD = 10 ether; /// @notice Default Anvil dev accounts. Only funded if `cfg.fundDevAccounts == true`. diff --git a/packages/contracts-bedrock/snapshots/abi/FeesDepositor.json b/packages/contracts-bedrock/snapshots/abi/FeesDepositor.json index 9f255b0dc37..1a9c2cc2522 100644 --- a/packages/contracts-bedrock/snapshots/abi/FeesDepositor.json +++ b/packages/contracts-bedrock/snapshots/abi/FeesDepositor.json @@ -13,9 +13,9 @@ "name": "gasLimit", "outputs": [ { - "internalType": "uint64", + "internalType": "uint32", "name": "", - "type": "uint64" + "type": "uint32" } ], "stateMutability": "view", @@ -47,14 +47,14 @@ "type": "address" }, { - "internalType": "contract IOptimismPortal2", - "name": "_portal", + "internalType": "contract IL1CrossDomainMessenger", + "name": "_messenger", "type": "address" }, { - "internalType": "uint64", + "internalType": "uint32", "name": "_gasLimit", - "type": "uint64" + "type": "uint32" } ], "name": "initialize", @@ -77,12 +77,12 @@ }, { "inputs": [], - "name": "minDepositAmount", + "name": "messenger", "outputs": [ { - "internalType": "uint96", + "internalType": "contract IL1CrossDomainMessenger", "name": "", - "type": "uint96" + "type": "address" } ], "stateMutability": "view", @@ -90,12 +90,12 @@ }, { "inputs": [], - "name": "portal", + "name": "minDepositAmount", "outputs": [ { - "internalType": "contract IOptimismPortal2", + "internalType": "uint96", "name": "", - "type": "address" + "type": "uint96" } ], "stateMutability": "view", @@ -130,9 +130,9 @@ { "inputs": [ { - "internalType": "uint64", + "internalType": "uint32", "name": "_newGasLimit", - "type": "uint64" + "type": "uint32" } ], "name": "setGasLimit", @@ -228,15 +228,15 @@ "inputs": [ { "indexed": false, - "internalType": "uint64", + "internalType": "uint32", "name": "oldGasLimit", - "type": "uint64" + "type": "uint32" }, { "indexed": false, - "internalType": "uint64", + "internalType": "uint32", "name": "newGasLimit", - "type": "uint64" + "type": "uint32" } ], "name": "GasLimitUpdated", diff --git a/packages/contracts-bedrock/snapshots/abi/L1Withdrawer.json b/packages/contracts-bedrock/snapshots/abi/L1Withdrawer.json index 933b67ef8a5..3ead4d7a5c3 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1Withdrawer.json +++ b/packages/contracts-bedrock/snapshots/abi/L1Withdrawer.json @@ -12,9 +12,9 @@ "type": "address" }, { - "internalType": "uint96", + "internalType": "uint32", "name": "_withdrawalGasLimit", - "type": "uint96" + "type": "uint32" } ], "stateMutability": "nonpayable", @@ -79,9 +79,9 @@ { "inputs": [ { - "internalType": "uint96", + "internalType": "uint32", "name": "_newWithdrawalGasLimit", - "type": "uint96" + "type": "uint32" } ], "name": "setWithdrawalGasLimit", @@ -107,9 +107,9 @@ "name": "withdrawalGasLimit", "outputs": [ { - "internalType": "uint96", + "internalType": "uint32", "name": "", - "type": "uint96" + "type": "uint32" } ], "stateMutability": "view", @@ -183,15 +183,15 @@ "inputs": [ { "indexed": false, - "internalType": "uint96", + "internalType": "uint32", "name": "oldWithdrawalGasLimit", - "type": "uint96" + "type": "uint32" }, { "indexed": false, - "internalType": "uint96", + "internalType": "uint32", "name": "newWithdrawalGasLimit", - "type": "uint96" + "type": "uint32" } ], "name": "WithdrawalGasLimitUpdated", @@ -220,10 +220,5 @@ "inputs": [], "name": "L1Withdrawer_OnlyProxyAdminOwner", "type": "error" - }, - { - "inputs": [], - "name": "L1Withdrawer_WithdrawalGasLimitTooLow", - "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index b3bcaa7e6ff..29ede899423 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -8,8 +8,8 @@ "sourceCodeHash": "0x6c9d3e2dee44c234d59ab93b6564536dfd807f1c4a02a82d5393bc53cb15b8b7" }, "src/L1/FeesDepositor.sol:FeesDepositor": { - "initCodeHash": "0x3b1acae6460e04be9a855a24de87524f19827239da08f05934c3dd6183a8b5c5", - "sourceCodeHash": "0x613dc957e3bb409d1c7fb767971308b9cb1ed3c953407c8c641a6ec2bbf42fe8" + "initCodeHash": "0xe52c51805cfd55967d037173159f18aaf4344e32e5c8ad41f8d5d0025b1d36a8", + "sourceCodeHash": "0xe5f2b1915a201c0b8a107f168f5b9bc8aec8e8e95f938082e42ba5b5c8ebbd11" }, "src/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger": { "initCodeHash": "0x3dc659aafb03bd357f92abfc6794af89ee0ddd5212364551637422bf8d0b00f9", @@ -84,8 +84,8 @@ "sourceCodeHash": "0x2e85139090b9072e368a5ff36e5fcf2a90b219c6024e06a7998904cd75412395" }, "src/L2/L1Withdrawer.sol:L1Withdrawer": { - "initCodeHash": "0xb25010651e421d159204b9c9d3ae3d3569e57de82eabcff6a1d2560a21b88a82", - "sourceCodeHash": "0xde60d5d9f89f6c1195b11e21b2c3287afaa756a749c052530b76f26b4cdf6c0a" + "initCodeHash": "0x91e0be0d49636212678191c06b9b6840c399f08ad946bc7b52f24231691be28b", + "sourceCodeHash": "0x25422bdaf51d611c1688a835737368c0ff2ab639dac852af8a20ebb4e16fc103" }, "src/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger": { "initCodeHash": "0xe160be403df12709c371c33195d1b9c3b5e9499e902e86bdabc8eed749c3fd61", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/FeesDepositor.json b/packages/contracts-bedrock/snapshots/storageLayout/FeesDepositor.json index 3dd22ca68e1..f19c8e649a8 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/FeesDepositor.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/FeesDepositor.json @@ -15,10 +15,10 @@ }, { "bytes": "20", - "label": "portal", + "label": "messenger", "offset": 2, "slot": "0", - "type": "contract IOptimismPortal2" + "type": "contract IL1CrossDomainMessenger" }, { "bytes": "12", @@ -35,10 +35,10 @@ "type": "address" }, { - "bytes": "8", + "bytes": "4", "label": "gasLimit", "offset": 0, "slot": "2", - "type": "uint64" + "type": "uint32" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1Withdrawer.json b/packages/contracts-bedrock/snapshots/storageLayout/L1Withdrawer.json index c6cbaf7da89..cbc72ddb62e 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1Withdrawer.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1Withdrawer.json @@ -14,10 +14,10 @@ "type": "address" }, { - "bytes": "12", + "bytes": "4", "label": "withdrawalGasLimit", "offset": 20, "slot": "1", - "type": "uint96" + "type": "uint32" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/src/L1/FeesDepositor.sol b/packages/contracts-bedrock/src/L1/FeesDepositor.sol index 8a748085879..3c7185eb289 100644 --- a/packages/contracts-bedrock/src/L1/FeesDepositor.sol +++ b/packages/contracts-bedrock/src/L1/FeesDepositor.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; +import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; import { ProxyAdminOwnedBase } from "src/L1/ProxyAdminOwnedBase.sol"; import { ReinitializableBase } from "src/universal/ReinitializableBase.sol"; import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -11,8 +11,8 @@ import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable /// @title FeesDepositor /// @notice A contract that deposits fees to the L2 recipient when the deposit threshold is reached. contract FeesDepositor is ProxyAdminOwnedBase, Initializable, ReinitializableBase, ISemver { - /// @notice The portal contract. - IOptimismPortal public portal; + /// @notice The L1CrossDomainMessenger contract. + IL1CrossDomainMessenger public messenger; /// @notice The threshold at which fees are deposited. uint96 public minDepositAmount; @@ -21,7 +21,7 @@ contract FeesDepositor is ProxyAdminOwnedBase, Initializable, ReinitializableBas address public l2Recipient; /// @notice The gas limit for the deposit transaction. - uint64 public gasLimit; + uint32 public gasLimit; /// @notice Emitted when fees are received. /// @param sender The sender of the fees. @@ -47,7 +47,7 @@ contract FeesDepositor is ProxyAdminOwnedBase, Initializable, ReinitializableBas /// @notice Emitted when the gas limit is updated. /// @param oldGasLimit The old gas limit. /// @param newGasLimit The new gas limit. - event GasLimitUpdated(uint64 oldGasLimit, uint64 newGasLimit); + event GasLimitUpdated(uint32 oldGasLimit, uint32 newGasLimit); /// @notice Semantic version. /// @custom:semver 1.0.0 @@ -61,13 +61,13 @@ contract FeesDepositor is ProxyAdminOwnedBase, Initializable, ReinitializableBas /// @notice Initializes the FeesDepositor contract. /// @param _minDepositAmount The threshold at which fees are deposited. /// @param _l2Recipient The L2 recipient of the fees. - /// @param _portal The portal contract. + /// @param _messenger The L1CrossDomainMessenger contract. /// @param _gasLimit The gas limit for the deposit transaction. function initialize( uint96 _minDepositAmount, address _l2Recipient, - IOptimismPortal _portal, - uint64 _gasLimit + IL1CrossDomainMessenger _messenger, + uint32 _gasLimit ) external reinitializer(initVersion()) @@ -75,22 +75,20 @@ contract FeesDepositor is ProxyAdminOwnedBase, Initializable, ReinitializableBas // Initialization transactions must come from the ProxyAdmin or its owner. _assertOnlyProxyAdminOrProxyAdminOwner(); - portal = _portal; + messenger = _messenger; minDepositAmount = _minDepositAmount; l2Recipient = _l2Recipient; gasLimit = _gasLimit; } - /// @notice Receives ETH and deposits it to the L2 recipient through the portal when the threshold is reached. - /// @dev Be aware that when the DepositTransaction is sent, the `from` address will be the alias of this contract - /// address. + /// @notice Receives ETH and sends it to the L2 recipient via CrossDomainMessenger when the threshold is reached. receive() external payable { uint256 balance = address(this).balance; emit FundsReceived(msg.sender, msg.value, balance); if (balance >= minDepositAmount) { address recipient = l2Recipient; - portal.depositTransaction{ value: balance }(recipient, balance, gasLimit, false, ""); + messenger.sendMessage{ value: balance }(recipient, hex"", gasLimit); emit FeesDeposited(recipient, balance); } } @@ -116,9 +114,9 @@ contract FeesDepositor is ProxyAdminOwnedBase, Initializable, ReinitializableBas /// @notice Updates the gas limit for the deposit transaction. /// @param _newGasLimit The new gas limit. - function setGasLimit(uint64 _newGasLimit) external { + function setGasLimit(uint32 _newGasLimit) external { _assertOnlyProxyAdminOwner(); - uint64 oldGasLimit = gasLimit; + uint32 oldGasLimit = gasLimit; gasLimit = _newGasLimit; emit GasLimitUpdated(oldGasLimit, _newGasLimit); } diff --git a/packages/contracts-bedrock/src/L2/L1Withdrawer.sol b/packages/contracts-bedrock/src/L2/L1Withdrawer.sol index 69b2b19ce09..bbaf18e4638 100644 --- a/packages/contracts-bedrock/src/L2/L1Withdrawer.sol +++ b/packages/contracts-bedrock/src/L2/L1Withdrawer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.25; import { ISemver } from "interfaces/universal/ISemver.sol"; -import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; +import { IL2CrossDomainMessenger } from "interfaces/L2/IL2CrossDomainMessenger.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -14,11 +14,6 @@ contract L1Withdrawer is ISemver { /// @notice Thrown when the caller is not the ProxyAdmin owner. error L1Withdrawer_OnlyProxyAdminOwner(); - /// @notice Thrown when the withdrawal gas limit is too low. - error L1Withdrawer_WithdrawalGasLimitTooLow(); - - uint256 internal constant MIN_WITHDRAWAL_GAS = 250_000; - /// @notice The minimum amount of ETH that must be accumulated before a withdrawal is initiated. uint256 public minWithdrawalAmount; @@ -27,7 +22,7 @@ contract L1Withdrawer is ISemver { /// @notice The L1 gas limit set when initiating withdrawals. /// @dev withdrawalGasLimit should be overestimated to account for expensive receive() - uint96 public withdrawalGasLimit; + uint32 public withdrawalGasLimit; /// @notice Emitted when a withdrawal to L1 is initiated. /// @param recipient The L1 address receiving the withdrawal. @@ -53,7 +48,7 @@ contract L1Withdrawer is ISemver { /// @notice Emitted when the withdrawal gas limit is updated. /// @param oldWithdrawalGasLimit The previous withdrawal gas limit. /// @param newWithdrawalGasLimit The new withdrawal gas limit. - event WithdrawalGasLimitUpdated(uint96 oldWithdrawalGasLimit, uint96 newWithdrawalGasLimit); + event WithdrawalGasLimitUpdated(uint32 oldWithdrawalGasLimit, uint32 newWithdrawalGasLimit); /// @notice Semantic version. /// @custom:semver 1.0.0 @@ -63,10 +58,8 @@ contract L1Withdrawer is ISemver { /// @param _minWithdrawalAmount The minimum amount of ETH required to trigger a withdrawal. /// @param _recipient The L1 address that will receive withdrawals. /// @param _withdrawalGasLimit The gas limit for the L1 withdrawal transaction. - constructor(uint256 _minWithdrawalAmount, address _recipient, uint96 _withdrawalGasLimit) { - if (_withdrawalGasLimit < MIN_WITHDRAWAL_GAS) { - revert L1Withdrawer_WithdrawalGasLimitTooLow(); - } + /// @dev If target on L1 is `FeesDepositor`, the gas limit should be above 800k gas. + constructor(uint256 _minWithdrawalAmount, address _recipient, uint32 _withdrawalGasLimit) { minWithdrawalAmount = _minWithdrawalAmount; recipient = _recipient; withdrawalGasLimit = _withdrawalGasLimit; @@ -78,8 +71,8 @@ contract L1Withdrawer is ISemver { emit FundsReceived(msg.sender, msg.value, balance); if (balance >= minWithdrawalAmount) { - IL2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal{ value: balance }( - recipient, withdrawalGasLimit, hex"" + IL2CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER).sendMessage{ value: balance }( + recipient, hex"", withdrawalGasLimit ); emit WithdrawalInitiated(recipient, balance); @@ -112,14 +105,12 @@ contract L1Withdrawer is ISemver { /// @notice Updates the withdrawal gas limit. Only callable by the ProxyAdmin owner. /// @param _newWithdrawalGasLimit The new withdrawal gas limit. - function setWithdrawalGasLimit(uint96 _newWithdrawalGasLimit) external { + /// @dev If target on L1 is `FeesDepositor`, the gas limit should be above 800k gas. + function setWithdrawalGasLimit(uint32 _newWithdrawalGasLimit) external { if (msg.sender != IProxyAdmin(Predeploys.PROXY_ADMIN).owner()) { revert L1Withdrawer_OnlyProxyAdminOwner(); } - if (_newWithdrawalGasLimit < MIN_WITHDRAWAL_GAS) { - revert L1Withdrawer_WithdrawalGasLimitTooLow(); - } - uint96 oldWithdrawalGasLimit = withdrawalGasLimit; + uint32 oldWithdrawalGasLimit = withdrawalGasLimit; withdrawalGasLimit = _newWithdrawalGasLimit; emit WithdrawalGasLimitUpdated(oldWithdrawalGasLimit, _newWithdrawalGasLimit); } diff --git a/packages/contracts-bedrock/test/L1/FeesDepositor.t.sol b/packages/contracts-bedrock/test/L1/FeesDepositor.t.sol index 6322c9f9418..5c253b4a7cd 100644 --- a/packages/contracts-bedrock/test/L1/FeesDepositor.t.sol +++ b/packages/contracts-bedrock/test/L1/FeesDepositor.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; import { CommonTest } from "test/setup/CommonTest.sol"; -import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; +import { ICrossDomainMessenger } from "interfaces/universal/ICrossDomainMessenger.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { IFeesDepositor } from "interfaces/L1/IFeesDepositor.sol"; import { FeesDepositor } from "src/L1/FeesDepositor.sol"; @@ -18,13 +18,13 @@ contract FeesDepositor_TestInit is CommonTest { event FundsReceived(address indexed sender, uint256 amount, uint256 newBalance); event MinDepositAmountUpdated(uint96 oldMinDepositAmount, uint96 newMinDepositAmount); event L2RecipientUpdated(address oldL2Recipient, address newL2Recipient); - event GasLimitUpdated(uint64 oldGasLimit, uint64 newGasLimit); + event GasLimitUpdated(uint32 oldGasLimit, uint32 newGasLimit); // Test state FeesDepositor feesDepositor; address l2Recipient = makeAddr("l2Recipient"); uint96 minDepositAmount = 1 ether; - uint64 gasLimit = 150_000; + uint32 gasLimit = 150_000; address depositFeesRecipient; /// @notice Test setup. @@ -49,7 +49,7 @@ contract FeesDepositor_TestInit is CommonTest { // Initialize through proxy vm.prank(proxyAdminOwner); - feesDepositor.initialize(minDepositAmount, l2Recipient, optimismPortal2, gasLimit); + feesDepositor.initialize(minDepositAmount, l2Recipient, l1CrossDomainMessenger, gasLimit); // Set depositFeesRecipient depositFeesRecipient = @@ -64,7 +64,7 @@ contract FeesDepositor_Initialize_Test is FeesDepositor_TestInit { /// standard deployment script and instead is deployed manually, that's why we have this test. function test_cannotReinitialize_succeeds() public { vm.expectRevert("Initializable: contract is already initialized"); - feesDepositor.initialize(minDepositAmount, l2Recipient, optimismPortal2, gasLimit); + feesDepositor.initialize(minDepositAmount, l2Recipient, l1CrossDomainMessenger, gasLimit); } } @@ -81,11 +81,11 @@ contract FeesDepositor_Receive_Test is FeesDepositor_TestInit { vm.expectEmit(address(feesDepositor)); emit FundsReceived(address(this), _amount, _amount); - // Expect call to the portal not to be done + // Expect call to the messenger not to be done vm.expectCall( - address(optimismPortal2), + address(l1CrossDomainMessenger), _amount, - abi.encodeCall(IOptimismPortal.depositTransaction, (l2Recipient, _amount, gasLimit, false, "")), + abi.encodeCall(ICrossDomainMessenger.sendMessage, (l2Recipient, hex"", gasLimit)), 0 ); @@ -110,9 +110,9 @@ contract FeesDepositor_Receive_Test is FeesDepositor_TestInit { emit FeesDeposited(l2Recipient, _sendAmount); vm.expectCall( - address(optimismPortal2), + address(l1CrossDomainMessenger), _sendAmount, - abi.encodeCall(IOptimismPortal.depositTransaction, (l2Recipient, _sendAmount, gasLimit, false, "")) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (l2Recipient, hex"", gasLimit)) ); (bool success,) = address(feesDepositor).call{ value: _sendAmount }(""); @@ -128,7 +128,7 @@ contract FeesDepositor_Receive_Test is FeesDepositor_TestInit { // First amount should not exceed minDepositAmount (so it doesn't trigger deposit) _firstAmount = bound(_firstAmount, 0, minDepositAmount - 1); - // First deposit (should not trigger portal deposit) + // First deposit (should not trigger deposit) vm.deal(address(this), _firstAmount); vm.expectEmit(address(feesDepositor)); @@ -150,7 +150,7 @@ contract FeesDepositor_Receive_Test is FeesDepositor_TestInit { uint256 totalAmount = _firstAmount + _secondAmount; - // Second deposit (will trigger portal deposit since total >= minDepositAmount) + // Second deposit (will trigger deposit since total >= minDepositAmount) vm.deal(address(this), _secondAmount); vm.expectEmit(address(feesDepositor)); @@ -160,9 +160,9 @@ contract FeesDepositor_Receive_Test is FeesDepositor_TestInit { emit FeesDeposited(l2Recipient, totalAmount); vm.expectCall( - address(optimismPortal2), + address(l1CrossDomainMessenger), totalAmount, - abi.encodeCall(IOptimismPortal.depositTransaction, (l2Recipient, totalAmount, gasLimit, false, "")) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (l2Recipient, hex"", gasLimit)) ); (bool success2,) = address(feesDepositor).call{ value: _secondAmount }(""); @@ -176,23 +176,6 @@ contract FeesDepositor_Receive_Test is FeesDepositor_TestInit { "depositFeesRecipient balance 2" ); } - - /// @notice Fuzz test to ensure receive function gas usage never exceeds 200,000 gas. - /// @dev This test verifies the security requirement that receive() doesn't consume excessive gas, - /// preventing potential issues with withdrawal gas limits. The limit includes buffer for - /// measurement overhead and future contract changes. - function testFuzz_receive_gasUsageWithinLimit_succeeds(uint256 _amount) external { - _amount = bound(_amount, 0, type(uint256).max - depositFeesRecipient.balance); - - vm.deal(address(this), _amount); - - uint256 gasBefore = gasleft(); - (bool success,) = address(feesDepositor).call{ value: _amount }(""); - uint256 gasUsed = gasBefore - gasleft(); - - assertTrue(success, "Receive call should succeed"); - assertLe(gasUsed, 200_000, "Receive function gas usage should not exceed 200,000 gas"); - } } /// @title FeesDepositor_SetMinDepositAmount_Test @@ -256,7 +239,7 @@ contract FeesDepositor_SetL2Recipient_Test is FeesDepositor_TestInit { /// @title FeesDepositor_SetGasLimit_Test /// @notice Tests the setGasLimit function of the `FeesDepositor` contract. contract FeesDepositor_SetGasLimit_Test is FeesDepositor_TestInit { - function testFuzz_setGasLimit_asOwner_succeeds(uint64 _newGasLimit) external { + function testFuzz_setGasLimit_asOwner_succeeds(uint32 _newGasLimit) external { address owner = proxyAdmin.owner(); vm.expectEmit(address(feesDepositor)); @@ -272,7 +255,7 @@ contract FeesDepositor_SetGasLimit_Test is FeesDepositor_TestInit { address owner = proxyAdmin.owner(); vm.assume(_caller != owner); - uint64 newGasLimit = 200_000; + uint32 newGasLimit = 200_000; vm.expectRevert(IProxyAdminOwnedBase.ProxyAdminOwnedBase_NotProxyAdminOwner.selector); vm.prank(_caller); diff --git a/packages/contracts-bedrock/test/L2/L1Withdrawer.t.sol b/packages/contracts-bedrock/test/L2/L1Withdrawer.t.sol index 4239e35621e..865e7177f23 100644 --- a/packages/contracts-bedrock/test/L2/L1Withdrawer.t.sol +++ b/packages/contracts-bedrock/test/L2/L1Withdrawer.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; import { CommonTest } from "test/setup/CommonTest.sol"; -import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; +import { ICrossDomainMessenger } from "interfaces/universal/ICrossDomainMessenger.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { IL1Withdrawer } from "interfaces/L2/IL1Withdrawer.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; @@ -15,13 +15,13 @@ contract L1Withdrawer_TestInit is CommonTest { event FundsReceived(address indexed sender, uint256 amount, uint256 newBalance); event MinWithdrawalAmountUpdated(uint256 oldMinWithdrawalAmount, uint256 newMinWithdrawalAmount); event RecipientUpdated(address oldRecipient, address newRecipient); - event WithdrawalGasLimitUpdated(uint96 oldWithdrawalGasLimit, uint96 newWithdrawalGasLimit); + event WithdrawalGasLimitUpdated(uint32 oldWithdrawalGasLimit, uint32 newWithdrawalGasLimit); // Test state uint256 minWithdrawalAmount = 10 ether; - uint96 withdrawalGasLimit = 300_000; + uint32 withdrawalGasLimit = 1_000_000; - uint256 internal constant MIN_WITHDRAWAL_GAS_LIMIT = 250_000; + uint32 internal constant MIN_WITHDRAWAL_GAS_LIMIT = 800_000; /// @notice Test setup. function setUp() public virtual override { @@ -35,11 +35,11 @@ contract L1Withdrawer_Constructor_Test is L1Withdrawer_TestInit { function testFuzz_constructor_succeeds( uint256 _minWithdrawalAmount, address _recipient, - uint96 _withdrawalGasLimit + uint32 _withdrawalGasLimit ) external { - _withdrawalGasLimit = uint96(bound(uint256(_withdrawalGasLimit), MIN_WITHDRAWAL_GAS_LIMIT, type(uint96).max)); + _withdrawalGasLimit = uint32(bound(uint256(_withdrawalGasLimit), MIN_WITHDRAWAL_GAS_LIMIT, type(uint32).max)); IL1Withdrawer withdrawer = IL1Withdrawer( DeployUtils.create1({ @@ -54,26 +54,6 @@ contract L1Withdrawer_Constructor_Test is L1Withdrawer_TestInit { assertEq(withdrawer.recipient(), _recipient); assertEq(withdrawer.withdrawalGasLimit(), _withdrawalGasLimit); } - - function testFuzz_constructor_lowGasLimit_reverts( - uint256 _minWithdrawalAmount, - address _recipient, - uint96 _withdrawalGasLimit - ) - external - { - _withdrawalGasLimit = uint96(bound(uint256(_withdrawalGasLimit), 0, MIN_WITHDRAWAL_GAS_LIMIT - 1)); - - vm.expectRevert(IL1Withdrawer.L1Withdrawer_WithdrawalGasLimitTooLow.selector); - IL1Withdrawer( - DeployUtils.create1({ - _name: "L1Withdrawer", - _args: DeployUtils.encodeConstructor( - abi.encodeCall(IL1Withdrawer.__constructor__, (_minWithdrawalAmount, _recipient, _withdrawalGasLimit)) - ) - }) - ); - } } /// @title L1Withdrawer_Receive_Test @@ -91,7 +71,7 @@ contract L1Withdrawer_Receive_Test is L1Withdrawer_TestInit { assertTrue(success); assertEq(address(l1Withdrawer).balance, _amount); - assertEq(address(Predeploys.L2_TO_L1_MESSAGE_PASSER).balance, 0); + assertEq(address(Predeploys.L2_CROSS_DOMAIN_MESSENGER).balance, 0); } function testFuzz_receive_atOrAboveThreshold_succeeds(uint256 _sendAmount) external { @@ -106,15 +86,18 @@ contract L1Withdrawer_Receive_Test is L1Withdrawer_TestInit { emit WithdrawalInitiated(l1FeesDepositor, _sendAmount); vm.expectCall( - Predeploys.L2_TO_L1_MESSAGE_PASSER, + Predeploys.L2_CROSS_DOMAIN_MESSENGER, _sendAmount, - abi.encodeCall(IL2ToL1MessagePasser.initiateWithdrawal, (l1FeesDepositor, withdrawalGasLimit, hex"")) + abi.encodeCall( + ICrossDomainMessenger.sendMessage, (l1FeesDepositor, hex"", l1Withdrawer.withdrawalGasLimit()) + ) ); (bool success,) = address(l1Withdrawer).call{ value: _sendAmount }(""); assertTrue(success); assertEq(address(l1Withdrawer).balance, 0); + // Note: CrossDomainMessenger forwards to L2ToL1MessagePasser, so balance goes there assertEq(address(Predeploys.L2_TO_L1_MESSAGE_PASSER).balance, _sendAmount); } @@ -136,7 +119,7 @@ contract L1Withdrawer_Receive_Test is L1Withdrawer_TestInit { (bool success1,) = address(l1Withdrawer).call{ value: _firstAmount }(""); assertTrue(success1); assertEq(address(l1Withdrawer).balance, _firstAmount); - assertEq(address(Predeploys.L2_TO_L1_MESSAGE_PASSER).balance, 0); + assertEq(address(Predeploys.L2_CROSS_DOMAIN_MESSENGER).balance, 0); // Second deposit (will trigger withdrawal since total >= minWithdrawalAmount) vm.deal(address(this), _secondAmount); @@ -148,9 +131,11 @@ contract L1Withdrawer_Receive_Test is L1Withdrawer_TestInit { emit WithdrawalInitiated(l1FeesDepositor, totalAmount); vm.expectCall( - Predeploys.L2_TO_L1_MESSAGE_PASSER, + Predeploys.L2_CROSS_DOMAIN_MESSENGER, totalAmount, - abi.encodeCall(IL2ToL1MessagePasser.initiateWithdrawal, (l1FeesDepositor, withdrawalGasLimit, hex"")) + abi.encodeCall( + ICrossDomainMessenger.sendMessage, (l1FeesDepositor, hex"", l1Withdrawer.withdrawalGasLimit()) + ) ); (bool success2,) = address(l1Withdrawer).call{ value: _secondAmount }(""); @@ -223,14 +208,14 @@ contract L1Withdrawer_SetRecipient_Test is L1Withdrawer_TestInit { /// @title L1Withdrawer_SetWithdrawalGasLimit_Test /// @notice Tests the setWithdrawalGasLimit function of the `L1Withdrawer` contract. contract L1Withdrawer_SetWithdrawalGasLimit_Test is L1Withdrawer_TestInit { - function testFuzz_setWithdrawalGasLimit_asOwner_succeeds(uint96 _newWithdrawalGasLimit) external { + function testFuzz_setWithdrawalGasLimit_asOwner_succeeds(uint32 _newWithdrawalGasLimit) external { address owner = proxyAdmin.owner(); _newWithdrawalGasLimit = - uint96(bound(uint256(_newWithdrawalGasLimit), MIN_WITHDRAWAL_GAS_LIMIT, type(uint96).max)); + uint32(bound(uint256(_newWithdrawalGasLimit), MIN_WITHDRAWAL_GAS_LIMIT, type(uint32).max)); vm.expectEmit(address(l1Withdrawer)); - emit WithdrawalGasLimitUpdated(withdrawalGasLimit, _newWithdrawalGasLimit); + emit WithdrawalGasLimitUpdated(l1Withdrawer.withdrawalGasLimit(), _newWithdrawalGasLimit); vm.prank(owner); l1Withdrawer.setWithdrawalGasLimit(_newWithdrawalGasLimit); @@ -242,20 +227,12 @@ contract L1Withdrawer_SetWithdrawalGasLimit_Test is L1Withdrawer_TestInit { address owner = proxyAdmin.owner(); vm.assume(_caller != owner); - uint96 newWithdrawalGasLimit = 250_000; + uint32 newWithdrawalGasLimit = 250_000; vm.expectRevert(IL1Withdrawer.L1Withdrawer_OnlyProxyAdminOwner.selector); vm.prank(_caller); l1Withdrawer.setWithdrawalGasLimit(newWithdrawalGasLimit); - assertEq(l1Withdrawer.withdrawalGasLimit(), withdrawalGasLimit); - } - - function testFuzz_setWithdrawalGasLimit_lowGasLimit_reverts(uint96 _newWithdrawalGasLimit) external { - _newWithdrawalGasLimit = uint96(bound(uint256(_newWithdrawalGasLimit), 0, MIN_WITHDRAWAL_GAS_LIMIT - 1)); - - vm.prank(proxyAdmin.owner()); - vm.expectRevert(IL1Withdrawer.L1Withdrawer_WithdrawalGasLimitTooLow.selector); - l1Withdrawer.setWithdrawalGasLimit(_newWithdrawalGasLimit); + assertEq(l1Withdrawer.withdrawalGasLimit(), l1Withdrawer.withdrawalGasLimit()); } } diff --git a/packages/contracts-bedrock/test/L2/RevenueSharingIntegration.t.sol b/packages/contracts-bedrock/test/L2/RevenueSharingIntegration.t.sol index be1db50ab4d..777b0ffa942 100644 --- a/packages/contracts-bedrock/test/L2/RevenueSharingIntegration.t.sol +++ b/packages/contracts-bedrock/test/L2/RevenueSharingIntegration.t.sol @@ -5,9 +5,9 @@ import { CommonTest } from "test/setup/CommonTest.sol"; import { ISharesCalculator } from "interfaces/L2/ISharesCalculator.sol"; import { ISuperchainRevSharesCalculator } from "interfaces/L2/ISuperchainRevSharesCalculator.sol"; import { IFeeVault } from "interfaces/L2/IFeeVault.sol"; -import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Types } from "src/libraries/Types.sol"; +import { ICrossDomainMessenger } from "interfaces/universal/ICrossDomainMessenger.sol"; /// @title RevenueSharingIntegration_Test /// @notice Integration tests for the complete revenue sharing system including @@ -183,11 +183,10 @@ contract RevenueSharingIntegration_Test is CommonTest { // Expect L2→L1 withdrawal since 16.95 ETH > 10 ETH threshold vm.expectCall( - Predeploys.L2_TO_L1_MESSAGE_PASSER, + Predeploys.L2_CROSS_DOMAIN_MESSENGER, expectedTotalWithdrawal, abi.encodeCall( - IL2ToL1MessagePasser.initiateWithdrawal, - (l1Withdrawer.recipient(), l1Withdrawer.withdrawalGasLimit(), hex"") + ICrossDomainMessenger.sendMessage, (l1Withdrawer.recipient(), hex"", l1Withdrawer.withdrawalGasLimit()) ) );