L2StandardBridge.sol 9.81 KB
Newer Older
1
// SPDX-License-Identifier: MIT
2
pragma solidity 0.8.15;
3

4
import { Predeploys } from "../libraries/Predeploys.sol";
5
import { StandardBridge } from "../universal/StandardBridge.sol";
6
import { Semver } from "../universal/Semver.sol";
7 8
import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol";

9 10 11 12 13 14 15 16 17
/// @custom:proxied
/// @custom:predeploy 0x4200000000000000000000000000000000000010
/// @title L2StandardBridge
/// @notice The L2StandardBridge is responsible for transfering ETH and ERC20 tokens between L1 and
///         L2. In the case that an ERC20 token is native to L2, it will be escrowed within this
///         contract. If the ERC20 token is native to L1, it will be burnt.
///         NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples
///         of some token types that may not be properly supported by this contract include, but are
///         not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists.
18
contract L2StandardBridge is StandardBridge, Semver {
19 20 21 22 23 24 25 26
    /// @custom:legacy
    /// @notice Emitted whenever a withdrawal from L2 to L1 is initiated.
    /// @param l1Token   Address of the token on L1.
    /// @param l2Token   Address of the corresponding token on L2.
    /// @param from      Address of the withdrawer.
    /// @param to        Address of the recipient on L1.
    /// @param amount    Amount of the ERC20 withdrawn.
    /// @param extraData Extra data attached to the withdrawal.
27
    event WithdrawalInitiated(
28 29 30 31 32 33
        address indexed l1Token,
        address indexed l2Token,
        address indexed from,
        address to,
        uint256 amount,
        bytes extraData
34 35
    );

36 37 38 39 40 41 42 43
    /// @custom:legacy
    /// @notice Emitted whenever an ERC20 deposit is finalized.
    /// @param l1Token   Address of the token on L1.
    /// @param l2Token   Address of the corresponding token on L2.
    /// @param from      Address of the depositor.
    /// @param to        Address of the recipient on L2.
    /// @param amount    Amount of the ERC20 deposited.
    /// @param extraData Extra data attached to the deposit.
44
    event DepositFinalized(
45 46 47 48 49 50
        address indexed l1Token,
        address indexed l2Token,
        address indexed from,
        address to,
        uint256 amount,
        bytes extraData
51 52
    );

53 54 55
    /// @custom:semver 1.1.1
    /// @notice Constructs the L2StandardBridge contract.
    /// @param _otherBridge Address of the L1StandardBridge.
56
    constructor(address payable _otherBridge)
57
        Semver(1, 1, 1)
58 59
        StandardBridge(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _otherBridge)
    {}
60

61
    /// @notice Allows EOAs to bridge ETH by sending directly to the bridge.
62 63 64 65 66 67 68 69 70 71 72
    receive() external payable override onlyEOA {
        _initiateWithdrawal(
            Predeploys.LEGACY_ERC20_ETH,
            msg.sender,
            msg.sender,
            msg.value,
            RECEIVE_DEFAULT_GAS_LIMIT,
            bytes("")
        );
    }

73 74 75 76 77 78 79 80
    /// @custom:legacy
    /// @notice Initiates a withdrawal from L2 to L1.
    ///         This function only works with OptimismMintableERC20 tokens or ether. Use the
    ///         `bridgeERC20` function to bridge native L2 tokens to L1.
    /// @param _l2Token     Address of the L2 token to withdraw.
    /// @param _amount      Amount of the L2 token to withdraw.
    /// @param _minGasLimit Minimum gas limit to use for the transaction.
    /// @param _extraData   Extra data attached to the withdrawal.
81 82 83 84
    function withdraw(
        address _l2Token,
        uint256 _amount,
        uint32 _minGasLimit,
85
        bytes calldata _extraData
86
    ) external payable virtual onlyEOA {
87
        _initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _minGasLimit, _extraData);
88 89
    }

90 91 92 93 94 95 96 97 98 99 100 101 102
    /// @custom:legacy
    /// @notice Initiates a withdrawal from L2 to L1 to a target account on L1.
    ///         Note that if ETH is sent to a contract on L1 and the call fails, then that ETH will
    ///         be locked in the L1StandardBridge. ETH may be recoverable if the call can be
    ///         successfully replayed by increasing the amount of gas supplied to the call. If the
    ///         call will fail for any amount of gas, then the ETH will be locked permanently.
    ///         This function only works with OptimismMintableERC20 tokens or ether. Use the
    ///         `bridgeERC20To` function to bridge native L2 tokens to L1.
    /// @param _l2Token     Address of the L2 token to withdraw.
    /// @param _to          Recipient account on L1.
    /// @param _amount      Amount of the L2 token to withdraw.
    /// @param _minGasLimit Minimum gas limit to use for the transaction.
    /// @param _extraData   Extra data attached to the withdrawal.
103 104 105 106 107
    function withdrawTo(
        address _l2Token,
        address _to,
        uint256 _amount,
        uint32 _minGasLimit,
108
        bytes calldata _extraData
109
    ) external payable virtual {
110
        _initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _minGasLimit, _extraData);
111 112
    }

113 114 115 116 117 118 119 120 121
    /// @custom:legacy
    /// @notice Finalizes a deposit from L1 to L2. To finalize a deposit of ether, use address(0)
    ///         and the l1Token and the Legacy ERC20 ether predeploy address as the l2Token.
    /// @param _l1Token   Address of the L1 token to deposit.
    /// @param _l2Token   Address of the corresponding L2 token.
    /// @param _from      Address of the depositor.
    /// @param _to        Address of the recipient.
    /// @param _amount    Amount of the tokens being deposited.
    /// @param _extraData Extra data attached to the deposit.
122 123 124 125 126 127
    function finalizeDeposit(
        address _l1Token,
        address _l2Token,
        address _from,
        address _to,
        uint256 _amount,
128
        bytes calldata _extraData
129
    ) external payable virtual {
130
        if (_l1Token == address(0) && _l2Token == Predeploys.LEGACY_ERC20_ETH) {
131
            finalizeBridgeETH(_from, _to, _amount, _extraData);
132
        } else {
133
            finalizeBridgeERC20(_l2Token, _l1Token, _from, _to, _amount, _extraData);
134 135 136
        }
    }

137 138 139
    /// @custom:legacy
    /// @notice Retrieves the access of the corresponding L1 bridge contract.
    /// @return Address of the corresponding L1 bridge contract.
140 141 142 143
    function l1TokenBridge() external view returns (address) {
        return address(OTHER_BRIDGE);
    }

144 145 146 147 148 149 150 151
    /// @custom:legacy
    /// @notice Internal function to initiate a withdrawal from L2 to L1 to a target account on L1.
    /// @param _l2Token     Address of the L2 token to withdraw.
    /// @param _from        Address of the withdrawer.
    /// @param _to          Recipient account on L1.
    /// @param _amount      Amount of the L2 token to withdraw.
    /// @param _minGasLimit Minimum gas limit to use for the transaction.
    /// @param _extraData   Extra data attached to the withdrawal.
152 153 154 155 156 157
    function _initiateWithdrawal(
        address _l2Token,
        address _from,
        address _to,
        uint256 _amount,
        uint32 _minGasLimit,
158
        bytes memory _extraData
159
    ) internal {
160
        if (_l2Token == Predeploys.LEGACY_ERC20_ETH) {
161
            _initiateBridgeETH(_from, _to, _amount, _minGasLimit, _extraData);
162
        } else {
163
            address l1Token = OptimismMintableERC20(_l2Token).l1Token();
164
            _initiateBridgeERC20(_l2Token, l1Token, _from, _to, _amount, _minGasLimit, _extraData);
165
        }
166 167
    }

168 169 170
    /// @notice Emits the legacy WithdrawalInitiated event followed by the ETHBridgeInitiated event.
    ///         This is necessary for backwards compatibility with the legacy bridge.
    /// @inheritdoc StandardBridge
171 172 173 174 175 176 177 178 179 180 181 182 183 184
    function _emitETHBridgeInitiated(
        address _from,
        address _to,
        uint256 _amount,
        bytes memory _extraData
    ) internal override {
        emit WithdrawalInitiated(
            address(0),
            Predeploys.LEGACY_ERC20_ETH,
            _from,
            _to,
            _amount,
            _extraData
        );
185
        super._emitETHBridgeInitiated(_from, _to, _amount, _extraData);
186 187
    }

188 189 190
    /// @notice Emits the legacy DepositFinalized event followed by the ETHBridgeFinalized event.
    ///         This is necessary for backwards compatibility with the legacy bridge.
    /// @inheritdoc StandardBridge
191 192 193 194 195 196 197 198 199 200 201 202 203 204
    function _emitETHBridgeFinalized(
        address _from,
        address _to,
        uint256 _amount,
        bytes memory _extraData
    ) internal override {
        emit DepositFinalized(
            address(0),
            Predeploys.LEGACY_ERC20_ETH,
            _from,
            _to,
            _amount,
            _extraData
        );
205
        super._emitETHBridgeFinalized(_from, _to, _amount, _extraData);
206 207
    }

208 209 210
    /// @notice Emits the legacy WithdrawalInitiated event followed by the ERC20BridgeInitiated
    ///         event. This is necessary for backwards compatibility with the legacy bridge.
    /// @inheritdoc StandardBridge
211 212 213 214 215 216 217 218 219
    function _emitERC20BridgeInitiated(
        address _localToken,
        address _remoteToken,
        address _from,
        address _to,
        uint256 _amount,
        bytes memory _extraData
    ) internal override {
        emit WithdrawalInitiated(_remoteToken, _localToken, _from, _to, _amount, _extraData);
220
        super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
221
    }
222

223 224 225
    /// @notice Emits the legacy DepositFinalized event followed by the ERC20BridgeFinalized event.
    ///         This is necessary for backwards compatibility with the legacy bridge.
    /// @inheritdoc StandardBridge
226 227 228 229 230 231 232 233 234
    function _emitERC20BridgeFinalized(
        address _localToken,
        address _remoteToken,
        address _from,
        address _to,
        uint256 _amount,
        bytes memory _extraData
    ) internal override {
        emit DepositFinalized(_remoteToken, _localToken, _from, _to, _amount, _extraData);
235
        super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
236 237
    }
}