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 }