github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  // Testing utilities
     5  import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
     6  
     7  // Target contract is imported by the `Bridge_Initializer`
     8  import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol";
     9  import { stdStorage, StdStorage } from "forge-std/Test.sol";
    10  import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol";
    11  import { L2ToL1MessagePasser } from "src/L2/L2ToL1MessagePasser.sol";
    12  import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    13  
    14  // Libraries
    15  import { Hashing } from "src/libraries/Hashing.sol";
    16  import { Types } from "src/libraries/Types.sol";
    17  
    18  // Target contract dependencies
    19  import { L2StandardBridge } from "src/L2/L2StandardBridge.sol";
    20  import { Predeploys } from "src/libraries/Predeploys.sol";
    21  import { StandardBridge } from "src/universal/StandardBridge.sol";
    22  import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol";
    23  
    24  contract L2StandardBridge_Test is Bridge_Initializer {
    25      using stdStorage for StdStorage;
    26  
    27      /// @dev Test that the bridge's constructor sets the correct values.
    28      function test_constructor_succeeds() external {
    29          L2StandardBridge impl =
    30              L2StandardBridge(payable(EIP1967Helper.getImplementation(deploy.mustGetAddress("L2StandardBridge"))));
    31          assertEq(address(impl.MESSENGER()), address(0));
    32          assertEq(address(impl.messenger()), address(0));
    33          assertEq(address(impl.OTHER_BRIDGE()), address(0));
    34          assertEq(address(impl.otherBridge()), address(0));
    35      }
    36  
    37      /// @dev Tests that the bridge is initialized correctly.
    38      function test_initialize_succeeds() external {
    39          assertEq(address(l2StandardBridge.MESSENGER()), address(l2CrossDomainMessenger));
    40          assertEq(address(l2StandardBridge.messenger()), address(l2CrossDomainMessenger));
    41          assertEq(l1StandardBridge.l2TokenBridge(), address(l2StandardBridge));
    42          assertEq(address(l2StandardBridge.OTHER_BRIDGE()), address(l1StandardBridge));
    43          assertEq(address(l2StandardBridge.otherBridge()), address(l1StandardBridge));
    44      }
    45  
    46      /// @dev Ensures that the L2StandardBridge is always not paused. The pausability
    47      ///      happens on L1 and not L2.
    48      function test_paused_succeeds() external {
    49          assertFalse(l2StandardBridge.paused());
    50      }
    51  
    52      /// @dev Tests that the bridge receives ETH and successfully initiates a withdrawal.
    53      function test_receive_succeeds() external {
    54          assertEq(address(l2ToL1MessagePasser).balance, 0);
    55          uint256 nonce = l2CrossDomainMessenger.messageNonce();
    56  
    57          bytes memory message =
    58              abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, alice, 100, hex"");
    59          uint64 baseGas = l2CrossDomainMessenger.baseGas(message, 200_000);
    60          bytes memory withdrawalData = abi.encodeWithSelector(
    61              CrossDomainMessenger.relayMessage.selector,
    62              nonce,
    63              address(l2StandardBridge),
    64              address(l1StandardBridge),
    65              100,
    66              200_000,
    67              message
    68          );
    69          bytes32 withdrawalHash = Hashing.hashWithdrawal(
    70              Types.WithdrawalTransaction({
    71                  nonce: nonce,
    72                  sender: address(l2CrossDomainMessenger),
    73                  target: address(l1CrossDomainMessenger),
    74                  value: 100,
    75                  gasLimit: baseGas,
    76                  data: withdrawalData
    77              })
    78          );
    79  
    80          vm.expectEmit(true, true, true, true);
    81          emit WithdrawalInitiated(address(0), Predeploys.LEGACY_ERC20_ETH, alice, alice, 100, hex"");
    82  
    83          vm.expectEmit(true, true, true, true);
    84          emit ETHBridgeInitiated(alice, alice, 100, hex"");
    85  
    86          // L2ToL1MessagePasser will emit a MessagePassed event
    87          vm.expectEmit(true, true, true, true, address(l2ToL1MessagePasser));
    88          emit MessagePassed(
    89              nonce,
    90              address(l2CrossDomainMessenger),
    91              address(l1CrossDomainMessenger),
    92              100,
    93              baseGas,
    94              withdrawalData,
    95              withdrawalHash
    96          );
    97  
    98          // SentMessage event emitted by the CrossDomainMessenger
    99          vm.expectEmit(true, true, true, true, address(l2CrossDomainMessenger));
   100          emit SentMessage(address(l1StandardBridge), address(l2StandardBridge), message, nonce, 200_000);
   101  
   102          // SentMessageExtension1 event emitted by the CrossDomainMessenger
   103          vm.expectEmit(true, true, true, true, address(l2CrossDomainMessenger));
   104          emit SentMessageExtension1(address(l2StandardBridge), 100);
   105  
   106          vm.expectCall(
   107              address(l2CrossDomainMessenger),
   108              abi.encodeWithSelector(
   109                  CrossDomainMessenger.sendMessage.selector,
   110                  address(l1StandardBridge),
   111                  message,
   112                  200_000 // StandardBridge's RECEIVE_DEFAULT_GAS_LIMIT
   113              )
   114          );
   115  
   116          vm.expectCall(
   117              Predeploys.L2_TO_L1_MESSAGE_PASSER,
   118              abi.encodeWithSelector(
   119                  L2ToL1MessagePasser.initiateWithdrawal.selector,
   120                  address(l1CrossDomainMessenger),
   121                  baseGas,
   122                  withdrawalData
   123              )
   124          );
   125  
   126          vm.prank(alice, alice);
   127          (bool success,) = address(l2StandardBridge).call{ value: 100 }(hex"");
   128          assertEq(success, true);
   129          assertEq(address(l2ToL1MessagePasser).balance, 100);
   130      }
   131  
   132      /// @dev Tests that `withdraw` reverts if the amount is not equal to the value sent.
   133      function test_withdraw_insufficientValue_reverts() external {
   134          assertEq(address(l2ToL1MessagePasser).balance, 0);
   135  
   136          vm.expectRevert("StandardBridge: bridging ETH must include sufficient ETH value");
   137          vm.prank(alice, alice);
   138          l2StandardBridge.withdraw(address(Predeploys.LEGACY_ERC20_ETH), 100, 1000, hex"");
   139      }
   140  
   141      /// @dev Tests that the legacy `withdraw` interface on the L2StandardBridge
   142      ///      successfully initiates a withdrawal.
   143      function test_withdraw_ether_succeeds() external {
   144          assertTrue(alice.balance >= 100);
   145          assertEq(Predeploys.L2_TO_L1_MESSAGE_PASSER.balance, 0);
   146  
   147          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   148          emit WithdrawalInitiated({
   149              l1Token: address(0),
   150              l2Token: Predeploys.LEGACY_ERC20_ETH,
   151              from: alice,
   152              to: alice,
   153              amount: 100,
   154              data: hex""
   155          });
   156  
   157          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   158          emit ETHBridgeInitiated({ from: alice, to: alice, amount: 100, data: hex"" });
   159  
   160          vm.prank(alice, alice);
   161          l2StandardBridge.withdraw{ value: 100 }({
   162              _l2Token: Predeploys.LEGACY_ERC20_ETH,
   163              _amount: 100,
   164              _minGasLimit: 1000,
   165              _extraData: hex""
   166          });
   167  
   168          assertEq(Predeploys.L2_TO_L1_MESSAGE_PASSER.balance, 100);
   169      }
   170  }
   171  
   172  contract PreBridgeERC20 is Bridge_Initializer {
   173      /// @dev Sets up expected calls and emits for a successful ERC20 withdrawal.
   174      function _preBridgeERC20(bool _isLegacy, address _l2Token) internal {
   175          // Alice has 100 L2Token
   176          deal(_l2Token, alice, 100, true);
   177          assertEq(ERC20(_l2Token).balanceOf(alice), 100);
   178          uint256 nonce = l2CrossDomainMessenger.messageNonce();
   179          bytes memory message = abi.encodeWithSelector(
   180              StandardBridge.finalizeBridgeERC20.selector, address(L1Token), _l2Token, alice, alice, 100, hex""
   181          );
   182          uint64 baseGas = l2CrossDomainMessenger.baseGas(message, 1000);
   183          bytes memory withdrawalData = abi.encodeWithSelector(
   184              CrossDomainMessenger.relayMessage.selector,
   185              nonce,
   186              address(l2StandardBridge),
   187              address(l1StandardBridge),
   188              0,
   189              1000,
   190              message
   191          );
   192          bytes32 withdrawalHash = Hashing.hashWithdrawal(
   193              Types.WithdrawalTransaction({
   194                  nonce: nonce,
   195                  sender: address(l2CrossDomainMessenger),
   196                  target: address(l1CrossDomainMessenger),
   197                  value: 0,
   198                  gasLimit: baseGas,
   199                  data: withdrawalData
   200              })
   201          );
   202  
   203          if (_isLegacy) {
   204              vm.expectCall(
   205                  address(l2StandardBridge),
   206                  abi.encodeWithSelector(l2StandardBridge.withdraw.selector, _l2Token, 100, 1000, hex"")
   207              );
   208          } else {
   209              vm.expectCall(
   210                  address(l2StandardBridge),
   211                  abi.encodeWithSelector(
   212                      l2StandardBridge.bridgeERC20.selector, _l2Token, address(L1Token), 100, 1000, hex""
   213                  )
   214              );
   215          }
   216  
   217          vm.expectCall(
   218              address(l2CrossDomainMessenger),
   219              abi.encodeWithSelector(CrossDomainMessenger.sendMessage.selector, address(l1StandardBridge), message, 1000)
   220          );
   221  
   222          vm.expectCall(
   223              Predeploys.L2_TO_L1_MESSAGE_PASSER,
   224              abi.encodeWithSelector(
   225                  L2ToL1MessagePasser.initiateWithdrawal.selector,
   226                  address(l1CrossDomainMessenger),
   227                  baseGas,
   228                  withdrawalData
   229              )
   230          );
   231  
   232          // The l2StandardBridge should burn the tokens
   233          vm.expectCall(_l2Token, abi.encodeWithSelector(OptimismMintableERC20.burn.selector, alice, 100));
   234  
   235          vm.expectEmit(true, true, true, true);
   236          emit WithdrawalInitiated(address(L1Token), _l2Token, alice, alice, 100, hex"");
   237  
   238          vm.expectEmit(true, true, true, true);
   239          emit ERC20BridgeInitiated(_l2Token, address(L1Token), alice, alice, 100, hex"");
   240  
   241          vm.expectEmit(true, true, true, true);
   242          emit MessagePassed(
   243              nonce,
   244              address(l2CrossDomainMessenger),
   245              address(l1CrossDomainMessenger),
   246              0,
   247              baseGas,
   248              withdrawalData,
   249              withdrawalHash
   250          );
   251  
   252          // SentMessage event emitted by the CrossDomainMessenger
   253          vm.expectEmit(true, true, true, true);
   254          emit SentMessage(address(l1StandardBridge), address(l2StandardBridge), message, nonce, 1000);
   255  
   256          // SentMessageExtension1 event emitted by the CrossDomainMessenger
   257          vm.expectEmit(true, true, true, true);
   258          emit SentMessageExtension1(address(l2StandardBridge), 0);
   259  
   260          vm.prank(alice, alice);
   261      }
   262  }
   263  
   264  contract L2StandardBridge_BridgeERC20_Test is PreBridgeERC20 {
   265      // withdraw
   266      // - token is burned
   267      // - emits WithdrawalInitiated
   268      // - calls Withdrawer.initiateWithdrawal
   269      function test_withdraw_withdrawingERC20_succeeds() external {
   270          _preBridgeERC20({ _isLegacy: true, _l2Token: address(L2Token) });
   271          l2StandardBridge.withdraw(address(L2Token), 100, 1000, hex"");
   272  
   273          assertEq(L2Token.balanceOf(alice), 0);
   274      }
   275  
   276      // BridgeERC20
   277      // - token is burned
   278      // - emits WithdrawalInitiated
   279      // - calls Withdrawer.initiateWithdrawal
   280      function test_bridgeERC20_succeeds() external {
   281          _preBridgeERC20({ _isLegacy: false, _l2Token: address(L2Token) });
   282          l2StandardBridge.bridgeERC20(address(L2Token), address(L1Token), 100, 1000, hex"");
   283  
   284          assertEq(L2Token.balanceOf(alice), 0);
   285      }
   286  
   287      function test_withdrawLegacyERC20_succeeds() external {
   288          _preBridgeERC20({ _isLegacy: true, _l2Token: address(LegacyL2Token) });
   289          l2StandardBridge.withdraw(address(LegacyL2Token), 100, 1000, hex"");
   290  
   291          assertEq(L2Token.balanceOf(alice), 0);
   292      }
   293  
   294      function test_bridgeLegacyERC20_succeeds() external {
   295          _preBridgeERC20({ _isLegacy: false, _l2Token: address(LegacyL2Token) });
   296          l2StandardBridge.bridgeERC20(address(LegacyL2Token), address(L1Token), 100, 1000, hex"");
   297  
   298          assertEq(L2Token.balanceOf(alice), 0);
   299      }
   300  
   301      function test_withdraw_notEOA_reverts() external {
   302          // This contract has 100 L2Token
   303          deal(address(L2Token), address(this), 100, true);
   304  
   305          vm.expectRevert("StandardBridge: function can only be called from an EOA");
   306          l2StandardBridge.withdraw(address(L2Token), 100, 1000, hex"");
   307      }
   308  }
   309  
   310  contract PreBridgeERC20To is Bridge_Initializer {
   311      // withdrawTo and BridgeERC20To should behave the same when transferring ERC20 tokens
   312      // so they should share the same setup and expectEmit calls
   313      function _preBridgeERC20To(bool _isLegacy, address _l2Token) internal {
   314          deal(_l2Token, alice, 100, true);
   315          assertEq(ERC20(L2Token).balanceOf(alice), 100);
   316          uint256 nonce = l2CrossDomainMessenger.messageNonce();
   317          bytes memory message = abi.encodeWithSelector(
   318              StandardBridge.finalizeBridgeERC20.selector, address(L1Token), _l2Token, alice, bob, 100, hex""
   319          );
   320          uint64 baseGas = l2CrossDomainMessenger.baseGas(message, 1000);
   321          bytes memory withdrawalData = abi.encodeWithSelector(
   322              CrossDomainMessenger.relayMessage.selector,
   323              nonce,
   324              address(l2StandardBridge),
   325              address(l1StandardBridge),
   326              0,
   327              1000,
   328              message
   329          );
   330          bytes32 withdrawalHash = Hashing.hashWithdrawal(
   331              Types.WithdrawalTransaction({
   332                  nonce: nonce,
   333                  sender: address(l2CrossDomainMessenger),
   334                  target: address(l1CrossDomainMessenger),
   335                  value: 0,
   336                  gasLimit: baseGas,
   337                  data: withdrawalData
   338              })
   339          );
   340  
   341          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   342          emit WithdrawalInitiated(address(L1Token), _l2Token, alice, bob, 100, hex"");
   343  
   344          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   345          emit ERC20BridgeInitiated(_l2Token, address(L1Token), alice, bob, 100, hex"");
   346  
   347          vm.expectEmit(true, true, true, true, address(l2ToL1MessagePasser));
   348          emit MessagePassed(
   349              nonce,
   350              address(l2CrossDomainMessenger),
   351              address(l1CrossDomainMessenger),
   352              0,
   353              baseGas,
   354              withdrawalData,
   355              withdrawalHash
   356          );
   357  
   358          // SentMessage event emitted by the CrossDomainMessenger
   359          vm.expectEmit(true, true, true, true, address(l2CrossDomainMessenger));
   360          emit SentMessage(address(l1StandardBridge), address(l2StandardBridge), message, nonce, 1000);
   361  
   362          // SentMessageExtension1 event emitted by the CrossDomainMessenger
   363          vm.expectEmit(true, true, true, true, address(l2CrossDomainMessenger));
   364          emit SentMessageExtension1(address(l2StandardBridge), 0);
   365  
   366          if (_isLegacy) {
   367              vm.expectCall(
   368                  address(l2StandardBridge),
   369                  abi.encodeWithSelector(l2StandardBridge.withdrawTo.selector, _l2Token, bob, 100, 1000, hex"")
   370              );
   371          } else {
   372              vm.expectCall(
   373                  address(l2StandardBridge),
   374                  abi.encodeWithSelector(
   375                      l2StandardBridge.bridgeERC20To.selector, _l2Token, address(L1Token), bob, 100, 1000, hex""
   376                  )
   377              );
   378          }
   379  
   380          vm.expectCall(
   381              address(l2CrossDomainMessenger),
   382              abi.encodeWithSelector(CrossDomainMessenger.sendMessage.selector, address(l1StandardBridge), message, 1000)
   383          );
   384  
   385          vm.expectCall(
   386              Predeploys.L2_TO_L1_MESSAGE_PASSER,
   387              abi.encodeWithSelector(
   388                  L2ToL1MessagePasser.initiateWithdrawal.selector,
   389                  address(l1CrossDomainMessenger),
   390                  baseGas,
   391                  withdrawalData
   392              )
   393          );
   394  
   395          // The l2StandardBridge should burn the tokens
   396          vm.expectCall(address(L2Token), abi.encodeWithSelector(OptimismMintableERC20.burn.selector, alice, 100));
   397  
   398          vm.prank(alice, alice);
   399      }
   400  }
   401  
   402  contract L2StandardBridge_BridgeERC20To_Test is PreBridgeERC20To {
   403      /// @dev Tests that `withdrawTo` burns the tokens, emits `WithdrawalInitiated`,
   404      ///      and initiates a withdrawal with `Withdrawer.initiateWithdrawal`.
   405      function test_withdrawTo_withdrawingERC20_succeeds() external {
   406          _preBridgeERC20To({ _isLegacy: true, _l2Token: address(L2Token) });
   407          l2StandardBridge.withdrawTo(address(L2Token), bob, 100, 1000, hex"");
   408  
   409          assertEq(L2Token.balanceOf(alice), 0);
   410      }
   411  
   412      /// @dev Tests that `bridgeERC20To` burns the tokens, emits `WithdrawalInitiated`,
   413      ///      and initiates a withdrawal with `Withdrawer.initiateWithdrawal`.
   414      function test_bridgeERC20To_succeeds() external {
   415          _preBridgeERC20To({ _isLegacy: false, _l2Token: address(L2Token) });
   416          l2StandardBridge.bridgeERC20To(address(L2Token), address(L1Token), bob, 100, 1000, hex"");
   417          assertEq(L2Token.balanceOf(alice), 0);
   418      }
   419  }
   420  
   421  contract L2StandardBridge_Bridge_Test is Bridge_Initializer {
   422      /// @dev Tests that `finalizeDeposit` succeeds. It should:
   423      ///      - only be callable by the l1TokenBridge
   424      ///      - emit `DepositFinalized` if the token pair is supported
   425      ///      - call `Withdrawer.initiateWithdrawal` if the token pair is not supported
   426      function test_finalizeDeposit_depositingERC20_succeeds() external {
   427          vm.mockCall(
   428              address(l2StandardBridge.messenger()),
   429              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   430              abi.encode(address(l2StandardBridge.OTHER_BRIDGE()))
   431          );
   432  
   433          vm.expectCall(address(L2Token), abi.encodeWithSelector(OptimismMintableERC20.mint.selector, alice, 100));
   434  
   435          // Should emit both the bedrock and legacy events
   436          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   437          emit DepositFinalized(address(L1Token), address(L2Token), alice, alice, 100, hex"");
   438  
   439          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   440          emit ERC20BridgeFinalized(address(L2Token), address(L1Token), alice, alice, 100, hex"");
   441  
   442          vm.prank(address(l2CrossDomainMessenger));
   443          l2StandardBridge.finalizeDeposit(address(L1Token), address(L2Token), alice, alice, 100, hex"");
   444      }
   445  
   446      /// @dev Tests that `finalizeDeposit` succeeds when depositing ETH.
   447      function test_finalizeDeposit_depositingETH_succeeds() external {
   448          vm.mockCall(
   449              address(l2StandardBridge.messenger()),
   450              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   451              abi.encode(address(l2StandardBridge.OTHER_BRIDGE()))
   452          );
   453  
   454          // Should emit both the bedrock and legacy events
   455          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   456          emit DepositFinalized(address(L1Token), address(L2Token), alice, alice, 100, hex"");
   457  
   458          vm.expectEmit(true, true, true, true, address(l2StandardBridge));
   459          emit ERC20BridgeFinalized(
   460              address(L2Token), // localToken
   461              address(L1Token), // remoteToken
   462              alice,
   463              alice,
   464              100,
   465              hex""
   466          );
   467  
   468          vm.prank(address(l2CrossDomainMessenger));
   469          l2StandardBridge.finalizeDeposit(address(L1Token), address(L2Token), alice, alice, 100, hex"");
   470      }
   471  
   472      /// @dev Tests that `finalizeDeposit` reverts if the amounts do not match.
   473      function test_finalizeBridgeETH_incorrectValue_reverts() external {
   474          vm.mockCall(
   475              address(l2StandardBridge.messenger()),
   476              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   477              abi.encode(address(l2StandardBridge.OTHER_BRIDGE()))
   478          );
   479          vm.deal(address(l2CrossDomainMessenger), 100);
   480          vm.prank(address(l2CrossDomainMessenger));
   481          vm.expectRevert("StandardBridge: amount sent does not match amount required");
   482          l2StandardBridge.finalizeBridgeETH{ value: 50 }(alice, alice, 100, hex"");
   483      }
   484  
   485      /// @dev Tests that `finalizeDeposit` reverts if the receipient is the other bridge.
   486      function test_finalizeBridgeETH_sendToSelf_reverts() external {
   487          vm.mockCall(
   488              address(l2StandardBridge.messenger()),
   489              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   490              abi.encode(address(l2StandardBridge.OTHER_BRIDGE()))
   491          );
   492          vm.deal(address(l2CrossDomainMessenger), 100);
   493          vm.prank(address(l2CrossDomainMessenger));
   494          vm.expectRevert("StandardBridge: cannot send to self");
   495          l2StandardBridge.finalizeBridgeETH{ value: 100 }(alice, address(l2StandardBridge), 100, hex"");
   496      }
   497  
   498      /// @dev Tests that `finalizeDeposit` reverts if the receipient is the messenger.
   499      function test_finalizeBridgeETH_sendToMessenger_reverts() external {
   500          vm.mockCall(
   501              address(l2StandardBridge.messenger()),
   502              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   503              abi.encode(address(l2StandardBridge.OTHER_BRIDGE()))
   504          );
   505          vm.deal(address(l2CrossDomainMessenger), 100);
   506          vm.prank(address(l2CrossDomainMessenger));
   507          vm.expectRevert("StandardBridge: cannot send to messenger");
   508          l2StandardBridge.finalizeBridgeETH{ value: 100 }(alice, address(l2CrossDomainMessenger), 100, hex"");
   509      }
   510  }
   511  
   512  contract L2StandardBridge_FinalizeBridgeETH_Test is Bridge_Initializer {
   513      /// @dev Tests that `finalizeBridgeETH` succeeds.
   514      function test_finalizeBridgeETH_succeeds() external {
   515          address messenger = address(l2StandardBridge.messenger());
   516          vm.mockCall(
   517              messenger,
   518              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   519              abi.encode(address(l2StandardBridge.OTHER_BRIDGE()))
   520          );
   521          vm.deal(messenger, 100);
   522          vm.prank(messenger);
   523  
   524          vm.expectEmit(true, true, true, true);
   525          emit DepositFinalized(address(0), Predeploys.LEGACY_ERC20_ETH, alice, alice, 100, hex"");
   526  
   527          vm.expectEmit(true, true, true, true);
   528          emit ETHBridgeFinalized(alice, alice, 100, hex"");
   529  
   530          l2StandardBridge.finalizeBridgeETH{ value: 100 }(alice, alice, 100, hex"");
   531      }
   532  }