github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 // Testing utilities 5 import { CommonTest } from "test/setup/CommonTest.sol"; 6 import { Reverter } from "test/mocks/Callers.sol"; 7 import { StandardBridge } from "src/universal/StandardBridge.sol"; 8 import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; 9 10 // Libraries 11 import { Predeploys } from "src/libraries/Predeploys.sol"; 12 13 // Target contract dependencies 14 import { FeeVault } from "src/universal/FeeVault.sol"; 15 16 // Target contract 17 import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol"; 18 19 contract SequencerFeeVault_Test is CommonTest { 20 address recipient; 21 22 /// @dev Sets up the test suite. 23 function setUp() public override { 24 super.setUp(); 25 recipient = deploy.cfg().sequencerFeeVaultRecipient(); 26 } 27 28 /// @dev Tests that the minimum withdrawal amount is correct. 29 function test_minWithdrawalAmount_succeeds() external { 30 assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount()); 31 } 32 33 /// @dev Tests that the l1 fee wallet is correct. 34 function test_constructor_succeeds() external { 35 assertEq(sequencerFeeVault.l1FeeWallet(), recipient); 36 } 37 38 /// @dev Tests that the fee vault is able to receive ETH. 39 function test_receive_succeeds() external { 40 uint256 balance = address(sequencerFeeVault).balance; 41 42 vm.prank(alice); 43 (bool success,) = address(sequencerFeeVault).call{ value: 100 }(hex""); 44 45 assertEq(success, true); 46 assertEq(address(sequencerFeeVault).balance, balance + 100); 47 } 48 49 /// @dev Tests that `withdraw` reverts if the balance is less than the minimum 50 /// withdrawal amount. 51 function test_withdraw_notEnough_reverts() external { 52 assert(address(sequencerFeeVault).balance < sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT()); 53 54 vm.expectRevert("FeeVault: withdrawal amount must be greater than minimum withdrawal amount"); 55 sequencerFeeVault.withdraw(); 56 } 57 58 /// @dev Tests that `withdraw` successfully initiates a withdrawal to L1. 59 function test_withdraw_toL1_succeeds() external { 60 uint256 amount = sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT() + 1; 61 vm.deal(address(sequencerFeeVault), amount); 62 63 // No ether has been withdrawn yet 64 assertEq(sequencerFeeVault.totalProcessed(), 0); 65 66 vm.expectEmit(address(Predeploys.SEQUENCER_FEE_WALLET)); 67 emit Withdrawal(address(sequencerFeeVault).balance, sequencerFeeVault.RECIPIENT(), address(this)); 68 vm.expectEmit(address(Predeploys.SEQUENCER_FEE_WALLET)); 69 emit Withdrawal( 70 address(sequencerFeeVault).balance, 71 sequencerFeeVault.RECIPIENT(), 72 address(this), 73 FeeVault.WithdrawalNetwork.L1 74 ); 75 76 // The entire vault's balance is withdrawn 77 vm.expectCall( 78 Predeploys.L2_STANDARD_BRIDGE, 79 address(sequencerFeeVault).balance, 80 abi.encodeWithSelector( 81 StandardBridge.bridgeETHTo.selector, sequencerFeeVault.l1FeeWallet(), 35_000, bytes("") 82 ) 83 ); 84 85 sequencerFeeVault.withdraw(); 86 87 // The withdrawal was successful 88 assertEq(sequencerFeeVault.totalProcessed(), amount); 89 assertEq(address(sequencerFeeVault).balance, 0); 90 assertEq(Predeploys.L2_TO_L1_MESSAGE_PASSER.balance, amount); 91 } 92 } 93 94 contract SequencerFeeVault_L2Withdrawal_Test is CommonTest { 95 /// @dev a cache for the config fee recipient 96 address recipient; 97 98 /// @dev Sets up the test suite. 99 function setUp() public override { 100 super.setUp(); 101 102 // Alter the deployment to use WithdrawalNetwork.L2 103 vm.etch( 104 EIP1967Helper.getImplementation(Predeploys.SEQUENCER_FEE_WALLET), 105 address( 106 new SequencerFeeVault( 107 deploy.cfg().sequencerFeeVaultRecipient(), 108 deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(), 109 FeeVault.WithdrawalNetwork.L2 110 ) 111 ).code 112 ); 113 114 recipient = deploy.cfg().sequencerFeeVaultRecipient(); 115 } 116 117 /// @dev Tests that `withdraw` successfully initiates a withdrawal to L2. 118 function test_withdraw_toL2_succeeds() external { 119 uint256 amount = sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT() + 1; 120 vm.deal(address(sequencerFeeVault), amount); 121 122 // No ether has been withdrawn yet 123 assertEq(sequencerFeeVault.totalProcessed(), 0); 124 125 vm.expectEmit(address(Predeploys.SEQUENCER_FEE_WALLET)); 126 emit Withdrawal(address(sequencerFeeVault).balance, sequencerFeeVault.RECIPIENT(), address(this)); 127 vm.expectEmit(address(Predeploys.SEQUENCER_FEE_WALLET)); 128 emit Withdrawal( 129 address(sequencerFeeVault).balance, 130 sequencerFeeVault.RECIPIENT(), 131 address(this), 132 FeeVault.WithdrawalNetwork.L2 133 ); 134 135 // The entire vault's balance is withdrawn 136 vm.expectCall(recipient, address(sequencerFeeVault).balance, bytes("")); 137 138 sequencerFeeVault.withdraw(); 139 140 // The withdrawal was successful 141 assertEq(sequencerFeeVault.totalProcessed(), amount); 142 assertEq(address(sequencerFeeVault).balance, 0); 143 assertEq(recipient.balance, amount); 144 } 145 146 /// @dev Tests that `withdraw` fails if the Recipient reverts. This also serves to simulate 147 /// a situation where insufficient gas is provided to the RECIPIENT. 148 function test_withdraw_toL2recipientReverts_fails() external { 149 uint256 amount = sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(); 150 151 vm.deal(address(sequencerFeeVault), amount); 152 // No ether has been withdrawn yet 153 assertEq(sequencerFeeVault.totalProcessed(), 0); 154 155 // Ensure the RECIPIENT reverts 156 vm.etch(sequencerFeeVault.RECIPIENT(), type(Reverter).runtimeCode); 157 158 // The entire vault's balance is withdrawn 159 vm.expectCall(recipient, address(sequencerFeeVault).balance, bytes("")); 160 vm.expectRevert("FeeVault: failed to send ETH to L2 fee recipient"); 161 sequencerFeeVault.withdraw(); 162 assertEq(sequencerFeeVault.totalProcessed(), 0); 163 } 164 }