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

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { Predeploys } from "src/libraries/Predeploys.sol";
     5  import { StandardBridge } from "src/universal/StandardBridge.sol";
     6  import { ISemver } from "src/universal/ISemver.sol";
     7  import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol";
     8  import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol";
     9  import { Constants } from "src/libraries/Constants.sol";
    10  
    11  /// @custom:proxied
    12  /// @custom:predeploy 0x4200000000000000000000000000000000000010
    13  /// @title L2StandardBridge
    14  /// @notice The L2StandardBridge is responsible for transfering ETH and ERC20 tokens between L1 and
    15  ///         L2. In the case that an ERC20 token is native to L2, it will be escrowed within this
    16  ///         contract. If the ERC20 token is native to L1, it will be burnt.
    17  ///         NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples
    18  ///         of some token types that may not be properly supported by this contract include, but are
    19  ///         not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists.
    20  contract L2StandardBridge is StandardBridge, ISemver {
    21      /// @custom:legacy
    22      /// @notice Emitted whenever a withdrawal from L2 to L1 is initiated.
    23      /// @param l1Token   Address of the token on L1.
    24      /// @param l2Token   Address of the corresponding token on L2.
    25      /// @param from      Address of the withdrawer.
    26      /// @param to        Address of the recipient on L1.
    27      /// @param amount    Amount of the ERC20 withdrawn.
    28      /// @param extraData Extra data attached to the withdrawal.
    29      event WithdrawalInitiated(
    30          address indexed l1Token,
    31          address indexed l2Token,
    32          address indexed from,
    33          address to,
    34          uint256 amount,
    35          bytes extraData
    36      );
    37  
    38      /// @custom:legacy
    39      /// @notice Emitted whenever an ERC20 deposit is finalized.
    40      /// @param l1Token   Address of the token on L1.
    41      /// @param l2Token   Address of the corresponding token on L2.
    42      /// @param from      Address of the depositor.
    43      /// @param to        Address of the recipient on L2.
    44      /// @param amount    Amount of the ERC20 deposited.
    45      /// @param extraData Extra data attached to the deposit.
    46      event DepositFinalized(
    47          address indexed l1Token,
    48          address indexed l2Token,
    49          address indexed from,
    50          address to,
    51          uint256 amount,
    52          bytes extraData
    53      );
    54  
    55      /// @custom:semver 1.8.0
    56      string public constant version = "1.8.0";
    57  
    58      /// @notice Constructs the L2StandardBridge contract.
    59      constructor() StandardBridge() {
    60          initialize({ _otherBridge: StandardBridge(payable(address(0))) });
    61      }
    62  
    63      /// @notice Initializer.
    64      /// @param _otherBridge Contract for the corresponding bridge on the other chain.
    65      function initialize(StandardBridge _otherBridge) public initializer {
    66          __StandardBridge_init({
    67              _messenger: CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER),
    68              _otherBridge: _otherBridge
    69          });
    70      }
    71  
    72      /// @notice Allows EOAs to bridge ETH by sending directly to the bridge.
    73      receive() external payable override onlyEOA {
    74          _initiateWithdrawal(
    75              Predeploys.LEGACY_ERC20_ETH, msg.sender, msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, bytes("")
    76          );
    77      }
    78  
    79      /// @custom:legacy
    80      /// @notice Initiates a withdrawal from L2 to L1.
    81      ///         This function only works with OptimismMintableERC20 tokens or ether. Use the
    82      ///         `bridgeERC20` function to bridge native L2 tokens to L1.
    83      /// @param _l2Token     Address of the L2 token to withdraw.
    84      /// @param _amount      Amount of the L2 token to withdraw.
    85      /// @param _minGasLimit Minimum gas limit to use for the transaction.
    86      /// @param _extraData   Extra data attached to the withdrawal.
    87      function withdraw(
    88          address _l2Token,
    89          uint256 _amount,
    90          uint32 _minGasLimit,
    91          bytes calldata _extraData
    92      )
    93          external
    94          payable
    95          virtual
    96          onlyEOA
    97      {
    98          _initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _minGasLimit, _extraData);
    99      }
   100  
   101      /// @custom:legacy
   102      /// @notice Initiates a withdrawal from L2 to L1 to a target account on L1.
   103      ///         Note that if ETH is sent to a contract on L1 and the call fails, then that ETH will
   104      ///         be locked in the L1StandardBridge. ETH may be recoverable if the call can be
   105      ///         successfully replayed by increasing the amount of gas supplied to the call. If the
   106      ///         call will fail for any amount of gas, then the ETH will be locked permanently.
   107      ///         This function only works with OptimismMintableERC20 tokens or ether. Use the
   108      ///         `bridgeERC20To` function to bridge native L2 tokens to L1.
   109      /// @param _l2Token     Address of the L2 token to withdraw.
   110      /// @param _to          Recipient account on L1.
   111      /// @param _amount      Amount of the L2 token to withdraw.
   112      /// @param _minGasLimit Minimum gas limit to use for the transaction.
   113      /// @param _extraData   Extra data attached to the withdrawal.
   114      function withdrawTo(
   115          address _l2Token,
   116          address _to,
   117          uint256 _amount,
   118          uint32 _minGasLimit,
   119          bytes calldata _extraData
   120      )
   121          external
   122          payable
   123          virtual
   124      {
   125          _initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _minGasLimit, _extraData);
   126      }
   127  
   128      /// @custom:legacy
   129      /// @notice Finalizes a deposit from L1 to L2. To finalize a deposit of ether, use address(0)
   130      ///         and the l1Token and the Legacy ERC20 ether predeploy address as the l2Token.
   131      /// @param _l1Token   Address of the L1 token to deposit.
   132      /// @param _l2Token   Address of the corresponding L2 token.
   133      /// @param _from      Address of the depositor.
   134      /// @param _to        Address of the recipient.
   135      /// @param _amount    Amount of the tokens being deposited.
   136      /// @param _extraData Extra data attached to the deposit.
   137      function finalizeDeposit(
   138          address _l1Token,
   139          address _l2Token,
   140          address _from,
   141          address _to,
   142          uint256 _amount,
   143          bytes calldata _extraData
   144      )
   145          external
   146          payable
   147          virtual
   148      {
   149          if (_l1Token == address(0) && _l2Token == Predeploys.LEGACY_ERC20_ETH) {
   150              finalizeBridgeETH(_from, _to, _amount, _extraData);
   151          } else {
   152              finalizeBridgeERC20(_l2Token, _l1Token, _from, _to, _amount, _extraData);
   153          }
   154      }
   155  
   156      /// @custom:legacy
   157      /// @notice Retrieves the access of the corresponding L1 bridge contract.
   158      /// @return Address of the corresponding L1 bridge contract.
   159      function l1TokenBridge() external view returns (address) {
   160          return address(otherBridge);
   161      }
   162  
   163      /// @custom:legacy
   164      /// @notice Internal function to initiate a withdrawal from L2 to L1 to a target account on L1.
   165      /// @param _l2Token     Address of the L2 token to withdraw.
   166      /// @param _from        Address of the withdrawer.
   167      /// @param _to          Recipient account on L1.
   168      /// @param _amount      Amount of the L2 token to withdraw.
   169      /// @param _minGasLimit Minimum gas limit to use for the transaction.
   170      /// @param _extraData   Extra data attached to the withdrawal.
   171      function _initiateWithdrawal(
   172          address _l2Token,
   173          address _from,
   174          address _to,
   175          uint256 _amount,
   176          uint32 _minGasLimit,
   177          bytes memory _extraData
   178      )
   179          internal
   180      {
   181          if (_l2Token == Predeploys.LEGACY_ERC20_ETH) {
   182              _initiateBridgeETH(_from, _to, _amount, _minGasLimit, _extraData);
   183          } else {
   184              address l1Token = OptimismMintableERC20(_l2Token).l1Token();
   185              _initiateBridgeERC20(_l2Token, l1Token, _from, _to, _amount, _minGasLimit, _extraData);
   186          }
   187      }
   188  
   189      /// @notice Emits the legacy WithdrawalInitiated event followed by the ETHBridgeInitiated event.
   190      ///         This is necessary for backwards compatibility with the legacy bridge.
   191      /// @inheritdoc StandardBridge
   192      function _emitETHBridgeInitiated(
   193          address _from,
   194          address _to,
   195          uint256 _amount,
   196          bytes memory _extraData
   197      )
   198          internal
   199          override
   200      {
   201          emit WithdrawalInitiated(address(0), Predeploys.LEGACY_ERC20_ETH, _from, _to, _amount, _extraData);
   202          super._emitETHBridgeInitiated(_from, _to, _amount, _extraData);
   203      }
   204  
   205      /// @notice Emits the legacy DepositFinalized event followed by the ETHBridgeFinalized event.
   206      ///         This is necessary for backwards compatibility with the legacy bridge.
   207      /// @inheritdoc StandardBridge
   208      function _emitETHBridgeFinalized(
   209          address _from,
   210          address _to,
   211          uint256 _amount,
   212          bytes memory _extraData
   213      )
   214          internal
   215          override
   216      {
   217          emit DepositFinalized(address(0), Predeploys.LEGACY_ERC20_ETH, _from, _to, _amount, _extraData);
   218          super._emitETHBridgeFinalized(_from, _to, _amount, _extraData);
   219      }
   220  
   221      /// @notice Emits the legacy WithdrawalInitiated event followed by the ERC20BridgeInitiated
   222      ///         event. This is necessary for backwards compatibility with the legacy bridge.
   223      /// @inheritdoc StandardBridge
   224      function _emitERC20BridgeInitiated(
   225          address _localToken,
   226          address _remoteToken,
   227          address _from,
   228          address _to,
   229          uint256 _amount,
   230          bytes memory _extraData
   231      )
   232          internal
   233          override
   234      {
   235          emit WithdrawalInitiated(_remoteToken, _localToken, _from, _to, _amount, _extraData);
   236          super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
   237      }
   238  
   239      /// @notice Emits the legacy DepositFinalized event followed by the ERC20BridgeFinalized event.
   240      ///         This is necessary for backwards compatibility with the legacy bridge.
   241      /// @inheritdoc StandardBridge
   242      function _emitERC20BridgeFinalized(
   243          address _localToken,
   244          address _remoteToken,
   245          address _from,
   246          address _to,
   247          uint256 _amount,
   248          bytes memory _extraData
   249      )
   250          internal
   251          override
   252      {
   253          emit DepositFinalized(_remoteToken, _localToken, _from, _to, _amount, _extraData);
   254          super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
   255      }
   256  }