diff --git a/contracts/package.json b/contracts/package.json index eddea1983f..a5300e6a87 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -56,7 +56,7 @@ }, "dependencies": { "@openzeppelin/contracts": "^v4.9.3", - "@openzeppelin/contracts-upgradeable": "^v4.9.2" + "@openzeppelin/contracts-upgradeable": "^v4.9.3" }, "lint-staged": { "*.{js,ts}": "npx eslint --cache --fix", diff --git a/contracts/scripts/foundry/DeployL2BridgeContracts.s.sol b/contracts/scripts/foundry/DeployL2BridgeContracts.s.sol index 52353e1e15..c47086a7fd 100644 --- a/contracts/scripts/foundry/DeployL2BridgeContracts.s.sol +++ b/contracts/scripts/foundry/DeployL2BridgeContracts.s.sol @@ -98,7 +98,7 @@ contract DeployL2BridgeContracts is Script { } address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY); - L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR); + L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR, 10 ether); logAddress("L2_TX_FEE_VAULT_ADDR", address(feeVault)); } diff --git a/contracts/src/L2/predeploys/L2TxFeeVault.sol b/contracts/src/L2/predeploys/L2TxFeeVault.sol index 168d64c00c..245bc3d7d6 100644 --- a/contracts/src/L2/predeploys/L2TxFeeVault.sol +++ b/contracts/src/L2/predeploys/L2TxFeeVault.sol @@ -1,14 +1,164 @@ // SPDX-License-Identifier: MIT +// MIT License + +// Copyright (c) 2022 Optimism +// Copyright (c) 2022 Scroll + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + pragma solidity =0.8.16; -import {FeeVault} from "../../libraries/FeeVault.sol"; +import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol"; +import {OwnableBase} from "../../libraries/common/OwnableBase.sol"; + +// solhint-disable no-empty-blocks +// solhint-disable reason-string /// @title L2TxFeeVault -/// @notice The `L2TxFeeVault` contract collects all L2 transaction fees and allows withdrawing these fees to a predefined L1 address. -/// The minimum withdrawal amount is 10 ether. -contract L2TxFeeVault is FeeVault { - /// @param _owner The owner of the contract. - /// @param _recipient The fee recipient address on L1. - constructor(address _owner, address _recipient) FeeVault(_owner, _recipient, 10 ether) {} +/// @notice The L2TxFeeVault contract contains the basic logic for the various different vault contracts +/// used to hold fee revenue generated by the L2 system. +contract L2TxFeeVault is OwnableBase { + /********** + * Events * + **********/ + + /// @notice Emits each time that a withdrawal occurs. + /// + /// @param value Amount that was withdrawn (in wei). + /// @param to Address that the funds were sent to. + /// @param from Address that triggered the withdrawal. + event Withdrawal(uint256 value, address to, address from); + + /// @notice Emits each time the owner updates the address of `messenger`. + /// @param oldMessenger The address of old messenger. + /// @param newMessenger The address of new messenger. + event UpdateMessenger(address indexed oldMessenger, address indexed newMessenger); + + /// @notice Emits each time the owner updates the address of `recipient`. + /// @param oldRecipient The address of old recipient. + /// @param newRecipient The address of new recipient. + event UpdateRecipient(address indexed oldRecipient, address indexed newRecipient); + + /// @notice Emits each time the owner updates the value of `minWithdrawAmount`. + /// @param oldMinWithdrawAmount The value of old `minWithdrawAmount`. + /// @param newMinWithdrawAmount The value of new `minWithdrawAmount`. + event UpdateMinWithdrawAmount(uint256 oldMinWithdrawAmount, uint256 newMinWithdrawAmount); + + /************* + * Variables * + *************/ + + /// @notice Minimum balance before a withdrawal can be triggered. + uint256 public minWithdrawAmount; + + /// @notice Scroll L2 messenger address. + address public messenger; + + /// @notice Wallet that will receive the fees on L1. + address public recipient; + + /// @notice Total amount of wei processed by the contract. + uint256 public totalProcessed; + + /*************** + * Constructor * + ***************/ + + /// @param _owner The owner of the contract. + /// @param _recipient Wallet that will receive the fees on L1. + /// @param _minWithdrawalAmount Minimum balance before a withdrawal can be triggered. + constructor( + address _owner, + address _recipient, + uint256 _minWithdrawalAmount + ) { + _transferOwnership(_owner); + + minWithdrawAmount = _minWithdrawalAmount; + recipient = _recipient; + } + + /***************************** + * Public Mutating Functions * + *****************************/ + + /// @notice Allow the contract to receive ETH. + receive() external payable {} + + /// @notice Triggers a withdrawal of funds to the L1 fee wallet. + /// @param _value The amount of ETH to withdraw. + function withdraw(uint256 _value) public { + require( + _value >= minWithdrawAmount, + "FeeVault: withdrawal amount must be greater than minimum withdrawal amount" + ); + + unchecked { + totalProcessed += _value; + } + + emit Withdrawal(_value, recipient, msg.sender); + + // no fee provided + IL2ScrollMessenger(messenger).sendMessage{value: _value}( + recipient, + _value, + bytes(""), // no message (simple eth transfer) + 0 // _gasLimit can be zero for fee vault. + ); + } + + /// @notice Triggers a withdrawal of all available funds to the L1 fee wallet. + function withdraw() external { + uint256 value = address(this).balance; + withdraw(value); + } + + /************************ + * Restricted Functions * + ************************/ + + /// @notice Update the address of messenger. + /// @param _newMessenger The address of messenger to update. + function updateMessenger(address _newMessenger) external onlyOwner { + address _oldMessenger = messenger; + messenger = _newMessenger; + + emit UpdateMessenger(_oldMessenger, _newMessenger); + } + + /// @notice Update the address of recipient. + /// @param _newRecipient The address of recipient to update. + function updateRecipient(address _newRecipient) external onlyOwner { + address _oldRecipient = recipient; + recipient = _newRecipient; + + emit UpdateRecipient(_oldRecipient, _newRecipient); + } + + /// @notice Update the minimum withdraw amount. + /// @param _newMinWithdrawAmount The minimum withdraw amount to update. + function updateMinWithdrawAmount(uint256 _newMinWithdrawAmount) external onlyOwner { + uint256 _oldMinWithdrawAmount = minWithdrawAmount; + minWithdrawAmount = _newMinWithdrawAmount; + + emit UpdateMinWithdrawAmount(_oldMinWithdrawAmount, _newMinWithdrawAmount); + } } diff --git a/contracts/src/libraries/FeeVault.sol b/contracts/src/libraries/FeeVault.sol deleted file mode 100644 index 71e59c4d85..0000000000 --- a/contracts/src/libraries/FeeVault.sol +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-License-Identifier: MIT - -// MIT License - -// Copyright (c) 2022 Optimism -// Copyright (c) 2022 Scroll - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -pragma solidity ^0.8.16; - -import {IL2ScrollMessenger} from "../L2/IL2ScrollMessenger.sol"; -import {OwnableBase} from "./common/OwnableBase.sol"; - -// solhint-disable no-empty-blocks -// solhint-disable reason-string - -/// @title FeeVault -/// @notice The FeeVault contract contains the basic logic for the various different vault contracts -/// used to hold fee revenue generated by the L2 system. -abstract contract FeeVault is OwnableBase { - /********** - * Events * - **********/ - - /// @notice Emits each time that a withdrawal occurs. - /// - /// @param value Amount that was withdrawn (in wei). - /// @param to Address that the funds were sent to. - /// @param from Address that triggered the withdrawal. - event Withdrawal(uint256 value, address to, address from); - - /// @notice Emits each time the owner updates the address of `messenger`. - /// @param oldMessenger The address of old messenger. - /// @param newMessenger The address of new messenger. - event UpdateMessenger(address indexed oldMessenger, address indexed newMessenger); - - /// @notice Emits each time the owner updates the address of `recipient`. - /// @param oldRecipient The address of old recipient. - /// @param newRecipient The address of new recipient. - event UpdateRecipient(address indexed oldRecipient, address indexed newRecipient); - - /// @notice Emits each time the owner updates the value of `minWithdrawAmount`. - /// @param oldMinWithdrawAmount The value of old `minWithdrawAmount`. - /// @param newMinWithdrawAmount The value of new `minWithdrawAmount`. - event UpdateMinWithdrawAmount(uint256 oldMinWithdrawAmount, uint256 newMinWithdrawAmount); - - /************* - * Variables * - *************/ - - /// @notice Minimum balance before a withdrawal can be triggered. - uint256 public minWithdrawAmount; - - /// @notice Scroll L2 messenger address. - address public messenger; - - /// @notice Wallet that will receive the fees on L1. - address public recipient; - - /// @notice Total amount of wei processed by the contract. - uint256 public totalProcessed; - - /*************** - * Constructor * - ***************/ - - /// @param _owner The owner of the contract. - /// @param _recipient Wallet that will receive the fees on L1. - /// @param _minWithdrawalAmount Minimum balance before a withdrawal can be triggered. - constructor( - address _owner, - address _recipient, - uint256 _minWithdrawalAmount - ) { - _transferOwnership(_owner); - - minWithdrawAmount = _minWithdrawalAmount; - recipient = _recipient; - } - - /***************************** - * Public Mutating Functions * - *****************************/ - - /// @notice Allow the contract to receive ETH. - receive() external payable {} - - /// @notice Triggers a withdrawal of funds to the L1 fee wallet. - /// @param _value The amount of ETH to withdraw. - function withdraw(uint256 _value) public { - require( - _value >= minWithdrawAmount, - "FeeVault: withdrawal amount must be greater than minimum withdrawal amount" - ); - - unchecked { - totalProcessed += _value; - } - - emit Withdrawal(_value, recipient, msg.sender); - - // no fee provided - IL2ScrollMessenger(messenger).sendMessage{value: _value}( - recipient, - _value, - bytes(""), // no message (simple eth transfer) - 0 // _gasLimit can be zero for fee vault. - ); - } - - /// @notice Triggers a withdrawal of all available funds to the L1 fee wallet. - function withdraw() external { - uint256 value = address(this).balance; - withdraw(value); - } - - /************************ - * Restricted Functions * - ************************/ - - /// @notice Update the address of messenger. - /// @param _newMessenger The address of messenger to update. - function updateMessenger(address _newMessenger) external onlyOwner { - address _oldMessenger = messenger; - messenger = _newMessenger; - - emit UpdateMessenger(_oldMessenger, _newMessenger); - } - - /// @notice Update the address of recipient. - /// @param _newRecipient The address of recipient to update. - function updateRecipient(address _newRecipient) external onlyOwner { - address _oldRecipient = recipient; - recipient = _newRecipient; - - emit UpdateRecipient(_oldRecipient, _newRecipient); - } - - /// @notice Update the minimum withdraw amount. - /// @param _newMinWithdrawAmount The minimum withdraw amount to update. - function updateMinWithdrawAmount(uint256 _newMinWithdrawAmount) external onlyOwner { - uint256 _oldMinWithdrawAmount = minWithdrawAmount; - minWithdrawAmount = _newMinWithdrawAmount; - - emit UpdateMinWithdrawAmount(_oldMinWithdrawAmount, _newMinWithdrawAmount); - } -} diff --git a/contracts/src/test/L2TxFeeVault.t.sol b/contracts/src/test/L2TxFeeVault.t.sol index cfeca78dda..614fd85134 100644 --- a/contracts/src/test/L2TxFeeVault.t.sol +++ b/contracts/src/test/L2TxFeeVault.t.sol @@ -13,7 +13,7 @@ contract L2TxFeeVaultTest is DSTestPlus { function setUp() public { messenger = new MockScrollMessenger(); - vault = new L2TxFeeVault(address(this), address(1)); + vault = new L2TxFeeVault(address(this), address(1), 10 ether); vault.updateMessenger(address(messenger)); } diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 84c27deeaf..bd6521578e 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -652,10 +652,10 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" -"@openzeppelin/contracts-upgradeable@^v4.9.2": - version "4.9.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.2.tgz#a817c75688f8daede420052fbcb34e52482e769e" - integrity sha512-siviV3PZV/fHfPaoIC51rf1Jb6iElkYWnNYZ0leO23/ukXuvOyoC/ahy8jqiV7g+++9Nuo3n/rk5ajSN/+d/Sg== +"@openzeppelin/contracts-upgradeable@^v4.9.3": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.3.tgz#ff17a80fb945f5102571f8efecb5ce5915cc4811" + integrity sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A== "@openzeppelin/contracts@^v4.9.3": version "4.9.3"