github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/universal/StandardBridge.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; 6 import { Address } from "@openzeppelin/contracts/utils/Address.sol"; 7 import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 8 import { SafeCall } from "src/libraries/SafeCall.sol"; 9 import { IOptimismMintableERC20, ILegacyMintableERC20 } from "src/universal/IOptimismMintableERC20.sol"; 10 import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol"; 11 import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; 12 import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; 13 14 /// @custom:upgradeable 15 /// @title StandardBridge 16 /// @notice StandardBridge is a base contract for the L1 and L2 standard ERC20 bridges. It handles 17 /// the core bridging logic, including escrowing tokens that are native to the local chain 18 /// and minting/burning tokens that are native to the remote chain. 19 abstract contract StandardBridge is Initializable { 20 using SafeERC20 for IERC20; 21 22 /// @notice The L2 gas limit set when eth is depoisited using the receive() function. 23 uint32 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 200_000; 24 25 /// @custom:legacy 26 /// @custom:spacer messenger 27 /// @notice Spacer for backwards compatibility. 28 bytes30 private spacer_0_2_30; 29 30 /// @custom:legacy 31 /// @custom:spacer l2TokenBridge 32 /// @notice Spacer for backwards compatibility. 33 address private spacer_1_0_20; 34 35 /// @notice Mapping that stores deposits for a given pair of local and remote tokens. 36 mapping(address => mapping(address => uint256)) public deposits; 37 38 /// @notice Messenger contract on this domain. 39 /// @custom:network-specific 40 CrossDomainMessenger public messenger; 41 42 /// @notice Corresponding bridge on the other domain. 43 /// @custom:network-specific 44 StandardBridge public otherBridge; 45 46 /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. 47 /// A gap size of 45 was chosen here, so that the first slot used in a child contract 48 /// would be a multiple of 50. 49 uint256[45] private __gap; 50 51 /// @notice Emitted when an ETH bridge is initiated to the other chain. 52 /// @param from Address of the sender. 53 /// @param to Address of the receiver. 54 /// @param amount Amount of ETH sent. 55 /// @param extraData Extra data sent with the transaction. 56 event ETHBridgeInitiated(address indexed from, address indexed to, uint256 amount, bytes extraData); 57 58 /// @notice Emitted when an ETH bridge is finalized on this chain. 59 /// @param from Address of the sender. 60 /// @param to Address of the receiver. 61 /// @param amount Amount of ETH sent. 62 /// @param extraData Extra data sent with the transaction. 63 event ETHBridgeFinalized(address indexed from, address indexed to, uint256 amount, bytes extraData); 64 65 /// @notice Emitted when an ERC20 bridge is initiated to the other chain. 66 /// @param localToken Address of the ERC20 on this chain. 67 /// @param remoteToken Address of the ERC20 on the remote chain. 68 /// @param from Address of the sender. 69 /// @param to Address of the receiver. 70 /// @param amount Amount of the ERC20 sent. 71 /// @param extraData Extra data sent with the transaction. 72 event ERC20BridgeInitiated( 73 address indexed localToken, 74 address indexed remoteToken, 75 address indexed from, 76 address to, 77 uint256 amount, 78 bytes extraData 79 ); 80 81 /// @notice Emitted when an ERC20 bridge is finalized on this chain. 82 /// @param localToken Address of the ERC20 on this chain. 83 /// @param remoteToken Address of the ERC20 on the remote chain. 84 /// @param from Address of the sender. 85 /// @param to Address of the receiver. 86 /// @param amount Amount of the ERC20 sent. 87 /// @param extraData Extra data sent with the transaction. 88 event ERC20BridgeFinalized( 89 address indexed localToken, 90 address indexed remoteToken, 91 address indexed from, 92 address to, 93 uint256 amount, 94 bytes extraData 95 ); 96 97 /// @notice Only allow EOAs to call the functions. Note that this is not safe against contracts 98 /// calling code within their constructors, but also doesn't really matter since we're 99 /// just trying to prevent users accidentally depositing with smart contract wallets. 100 modifier onlyEOA() { 101 require(!Address.isContract(msg.sender), "StandardBridge: function can only be called from an EOA"); 102 _; 103 } 104 105 /// @notice Ensures that the caller is a cross-chain message from the other bridge. 106 modifier onlyOtherBridge() { 107 require( 108 msg.sender == address(messenger) && messenger.xDomainMessageSender() == address(otherBridge), 109 "StandardBridge: function can only be called from the other bridge" 110 ); 111 _; 112 } 113 114 /// @notice Initializer. 115 /// @param _messenger Contract for CrossDomainMessenger on this network. 116 /// @param _otherBridge Contract for the other StandardBridge contract. 117 function __StandardBridge_init( 118 CrossDomainMessenger _messenger, 119 StandardBridge _otherBridge 120 ) 121 internal 122 onlyInitializing 123 { 124 messenger = _messenger; 125 otherBridge = _otherBridge; 126 } 127 128 /// @notice Allows EOAs to bridge ETH by sending directly to the bridge. 129 /// Must be implemented by contracts that inherit. 130 receive() external payable virtual; 131 132 /// @notice Getter for messenger contract. 133 /// Public getter is legacy and will be removed in the future. Use `messenger` instead. 134 /// @return Contract of the messenger on this domain. 135 /// @custom:legacy 136 function MESSENGER() external view returns (CrossDomainMessenger) { 137 return messenger; 138 } 139 140 /// @notice Getter for the other bridge contract. 141 /// Public getter is legacy and will be removed in the future. Use `otherBridge` instead. 142 /// @return Contract of the bridge on the other network. 143 /// @custom:legacy 144 function OTHER_BRIDGE() external view returns (StandardBridge) { 145 return otherBridge; 146 } 147 148 /// @notice This function should return true if the contract is paused. 149 /// On L1 this function will check the SuperchainConfig for its paused status. 150 /// On L2 this function should be a no-op. 151 /// @return Whether or not the contract is paused. 152 function paused() public view virtual returns (bool) { 153 return false; 154 } 155 156 /// @notice Sends ETH to the sender's address on the other chain. 157 /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. 158 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 159 /// not be triggered with this data, but it will be emitted and can be used 160 /// to identify the transaction. 161 function bridgeETH(uint32 _minGasLimit, bytes calldata _extraData) public payable onlyEOA { 162 _initiateBridgeETH(msg.sender, msg.sender, msg.value, _minGasLimit, _extraData); 163 } 164 165 /// @notice Sends ETH to a receiver's address on the other chain. Note that if ETH is sent to a 166 /// smart contract and the call fails, the ETH will be temporarily locked in the 167 /// StandardBridge on the other chain until the call is replayed. If the call cannot be 168 /// replayed with any amount of gas (call always reverts), then the ETH will be 169 /// permanently locked in the StandardBridge on the other chain. ETH will also 170 /// be locked if the receiver is the other bridge, because finalizeBridgeETH will revert 171 /// in that case. 172 /// @param _to Address of the receiver. 173 /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. 174 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 175 /// not be triggered with this data, but it will be emitted and can be used 176 /// to identify the transaction. 177 function bridgeETHTo(address _to, uint32 _minGasLimit, bytes calldata _extraData) public payable { 178 _initiateBridgeETH(msg.sender, _to, msg.value, _minGasLimit, _extraData); 179 } 180 181 /// @notice Sends ERC20 tokens to the sender's address on the other chain. Note that if the 182 /// ERC20 token on the other chain does not recognize the local token as the correct 183 /// pair token, the ERC20 bridge will fail and the tokens will be returned to sender on 184 /// this chain. 185 /// @param _localToken Address of the ERC20 on this chain. 186 /// @param _remoteToken Address of the corresponding token on the remote chain. 187 /// @param _amount Amount of local tokens to deposit. 188 /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. 189 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 190 /// not be triggered with this data, but it will be emitted and can be used 191 /// to identify the transaction. 192 function bridgeERC20( 193 address _localToken, 194 address _remoteToken, 195 uint256 _amount, 196 uint32 _minGasLimit, 197 bytes calldata _extraData 198 ) 199 public 200 virtual 201 onlyEOA 202 { 203 _initiateBridgeERC20(_localToken, _remoteToken, msg.sender, msg.sender, _amount, _minGasLimit, _extraData); 204 } 205 206 /// @notice Sends ERC20 tokens to a receiver's address on the other chain. Note that if the 207 /// ERC20 token on the other chain does not recognize the local token as the correct 208 /// pair token, the ERC20 bridge will fail and the tokens will be returned to sender on 209 /// this chain. 210 /// @param _localToken Address of the ERC20 on this chain. 211 /// @param _remoteToken Address of the corresponding token on the remote chain. 212 /// @param _to Address of the receiver. 213 /// @param _amount Amount of local tokens to deposit. 214 /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. 215 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 216 /// not be triggered with this data, but it will be emitted and can be used 217 /// to identify the transaction. 218 function bridgeERC20To( 219 address _localToken, 220 address _remoteToken, 221 address _to, 222 uint256 _amount, 223 uint32 _minGasLimit, 224 bytes calldata _extraData 225 ) 226 public 227 virtual 228 { 229 _initiateBridgeERC20(_localToken, _remoteToken, msg.sender, _to, _amount, _minGasLimit, _extraData); 230 } 231 232 /// @notice Finalizes an ETH bridge on this chain. Can only be triggered by the other 233 /// StandardBridge contract on the remote chain. 234 /// @param _from Address of the sender. 235 /// @param _to Address of the receiver. 236 /// @param _amount Amount of ETH being bridged. 237 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 238 /// not be triggered with this data, but it will be emitted and can be used 239 /// to identify the transaction. 240 function finalizeBridgeETH( 241 address _from, 242 address _to, 243 uint256 _amount, 244 bytes calldata _extraData 245 ) 246 public 247 payable 248 onlyOtherBridge 249 { 250 require(paused() == false, "StandardBridge: paused"); 251 require(msg.value == _amount, "StandardBridge: amount sent does not match amount required"); 252 require(_to != address(this), "StandardBridge: cannot send to self"); 253 require(_to != address(messenger), "StandardBridge: cannot send to messenger"); 254 255 // Emit the correct events. By default this will be _amount, but child 256 // contracts may override this function in order to emit legacy events as well. 257 _emitETHBridgeFinalized(_from, _to, _amount, _extraData); 258 259 bool success = SafeCall.call(_to, gasleft(), _amount, hex""); 260 require(success, "StandardBridge: ETH transfer failed"); 261 } 262 263 /// @notice Finalizes an ERC20 bridge on this chain. Can only be triggered by the other 264 /// StandardBridge contract on the remote chain. 265 /// @param _localToken Address of the ERC20 on this chain. 266 /// @param _remoteToken Address of the corresponding token on the remote chain. 267 /// @param _from Address of the sender. 268 /// @param _to Address of the receiver. 269 /// @param _amount Amount of the ERC20 being bridged. 270 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 271 /// not be triggered with this data, but it will be emitted and can be used 272 /// to identify the transaction. 273 function finalizeBridgeERC20( 274 address _localToken, 275 address _remoteToken, 276 address _from, 277 address _to, 278 uint256 _amount, 279 bytes calldata _extraData 280 ) 281 public 282 onlyOtherBridge 283 { 284 require(paused() == false, "StandardBridge: paused"); 285 if (_isOptimismMintableERC20(_localToken)) { 286 require( 287 _isCorrectTokenPair(_localToken, _remoteToken), 288 "StandardBridge: wrong remote token for Optimism Mintable ERC20 local token" 289 ); 290 291 OptimismMintableERC20(_localToken).mint(_to, _amount); 292 } else { 293 deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] - _amount; 294 IERC20(_localToken).safeTransfer(_to, _amount); 295 } 296 297 // Emit the correct events. By default this will be ERC20BridgeFinalized, but child 298 // contracts may override this function in order to emit legacy events as well. 299 _emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData); 300 } 301 302 /// @notice Initiates a bridge of ETH through the CrossDomainMessenger. 303 /// @param _from Address of the sender. 304 /// @param _to Address of the receiver. 305 /// @param _amount Amount of ETH being bridged. 306 /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. 307 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 308 /// not be triggered with this data, but it will be emitted and can be used 309 /// to identify the transaction. 310 function _initiateBridgeETH( 311 address _from, 312 address _to, 313 uint256 _amount, 314 uint32 _minGasLimit, 315 bytes memory _extraData 316 ) 317 internal 318 { 319 require(msg.value == _amount, "StandardBridge: bridging ETH must include sufficient ETH value"); 320 321 // Emit the correct events. By default this will be _amount, but child 322 // contracts may override this function in order to emit legacy events as well. 323 _emitETHBridgeInitiated(_from, _to, _amount, _extraData); 324 325 messenger.sendMessage{ value: _amount }({ 326 _target: address(otherBridge), 327 _message: abi.encodeWithSelector(this.finalizeBridgeETH.selector, _from, _to, _amount, _extraData), 328 _minGasLimit: _minGasLimit 329 }); 330 } 331 332 /// @notice Sends ERC20 tokens to a receiver's address on the other chain. 333 /// @param _localToken Address of the ERC20 on this chain. 334 /// @param _remoteToken Address of the corresponding token on the remote chain. 335 /// @param _to Address of the receiver. 336 /// @param _amount Amount of local tokens to deposit. 337 /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. 338 /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will 339 /// not be triggered with this data, but it will be emitted and can be used 340 /// to identify the transaction. 341 function _initiateBridgeERC20( 342 address _localToken, 343 address _remoteToken, 344 address _from, 345 address _to, 346 uint256 _amount, 347 uint32 _minGasLimit, 348 bytes memory _extraData 349 ) 350 internal 351 { 352 if (_isOptimismMintableERC20(_localToken)) { 353 require( 354 _isCorrectTokenPair(_localToken, _remoteToken), 355 "StandardBridge: wrong remote token for Optimism Mintable ERC20 local token" 356 ); 357 358 OptimismMintableERC20(_localToken).burn(_from, _amount); 359 } else { 360 IERC20(_localToken).safeTransferFrom(_from, address(this), _amount); 361 deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] + _amount; 362 } 363 364 // Emit the correct events. By default this will be ERC20BridgeInitiated, but child 365 // contracts may override this function in order to emit legacy events as well. 366 _emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData); 367 368 messenger.sendMessage({ 369 _target: address(otherBridge), 370 _message: abi.encodeWithSelector( 371 this.finalizeBridgeERC20.selector, 372 // Because this call will be executed on the remote chain, we reverse the order of 373 // the remote and local token addresses relative to their order in the 374 // finalizeBridgeERC20 function. 375 _remoteToken, 376 _localToken, 377 _from, 378 _to, 379 _amount, 380 _extraData 381 ), 382 _minGasLimit: _minGasLimit 383 }); 384 } 385 386 /// @notice Checks if a given address is an OptimismMintableERC20. Not perfect, but good enough. 387 /// Just the way we like it. 388 /// @param _token Address of the token to check. 389 /// @return True if the token is an OptimismMintableERC20. 390 function _isOptimismMintableERC20(address _token) internal view returns (bool) { 391 return ERC165Checker.supportsInterface(_token, type(ILegacyMintableERC20).interfaceId) 392 || ERC165Checker.supportsInterface(_token, type(IOptimismMintableERC20).interfaceId); 393 } 394 395 /// @notice Checks if the "other token" is the correct pair token for the OptimismMintableERC20. 396 /// Calls can be saved in the future by combining this logic with 397 /// `_isOptimismMintableERC20`. 398 /// @param _mintableToken OptimismMintableERC20 to check against. 399 /// @param _otherToken Pair token to check. 400 /// @return True if the other token is the correct pair token for the OptimismMintableERC20. 401 function _isCorrectTokenPair(address _mintableToken, address _otherToken) internal view returns (bool) { 402 if (ERC165Checker.supportsInterface(_mintableToken, type(ILegacyMintableERC20).interfaceId)) { 403 return _otherToken == ILegacyMintableERC20(_mintableToken).l1Token(); 404 } else { 405 return _otherToken == IOptimismMintableERC20(_mintableToken).remoteToken(); 406 } 407 } 408 409 /// @notice Emits the ETHBridgeInitiated event and if necessary the appropriate legacy event 410 /// when an ETH bridge is finalized on this chain. 411 /// @param _from Address of the sender. 412 /// @param _to Address of the receiver. 413 /// @param _amount Amount of ETH sent. 414 /// @param _extraData Extra data sent with the transaction. 415 function _emitETHBridgeInitiated( 416 address _from, 417 address _to, 418 uint256 _amount, 419 bytes memory _extraData 420 ) 421 internal 422 virtual 423 { 424 emit ETHBridgeInitiated(_from, _to, _amount, _extraData); 425 } 426 427 /// @notice Emits the ETHBridgeFinalized and if necessary the appropriate legacy event when an 428 /// ETH bridge is finalized on this chain. 429 /// @param _from Address of the sender. 430 /// @param _to Address of the receiver. 431 /// @param _amount Amount of ETH sent. 432 /// @param _extraData Extra data sent with the transaction. 433 function _emitETHBridgeFinalized( 434 address _from, 435 address _to, 436 uint256 _amount, 437 bytes memory _extraData 438 ) 439 internal 440 virtual 441 { 442 emit ETHBridgeFinalized(_from, _to, _amount, _extraData); 443 } 444 445 /// @notice Emits the ERC20BridgeInitiated event and if necessary the appropriate legacy 446 /// event when an ERC20 bridge is initiated to the other chain. 447 /// @param _localToken Address of the ERC20 on this chain. 448 /// @param _remoteToken Address of the ERC20 on the remote chain. 449 /// @param _from Address of the sender. 450 /// @param _to Address of the receiver. 451 /// @param _amount Amount of the ERC20 sent. 452 /// @param _extraData Extra data sent with the transaction. 453 function _emitERC20BridgeInitiated( 454 address _localToken, 455 address _remoteToken, 456 address _from, 457 address _to, 458 uint256 _amount, 459 bytes memory _extraData 460 ) 461 internal 462 virtual 463 { 464 emit ERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData); 465 } 466 467 /// @notice Emits the ERC20BridgeFinalized event and if necessary the appropriate legacy 468 /// event when an ERC20 bridge is initiated to the other chain. 469 /// @param _localToken Address of the ERC20 on this chain. 470 /// @param _remoteToken Address of the ERC20 on the remote chain. 471 /// @param _from Address of the sender. 472 /// @param _to Address of the receiver. 473 /// @param _amount Amount of the ERC20 sent. 474 /// @param _extraData Extra data sent with the transaction. 475 function _emitERC20BridgeFinalized( 476 address _localToken, 477 address _remoteToken, 478 address _from, 479 address _to, 480 uint256 _amount, 481 bytes memory _extraData 482 ) 483 internal 484 virtual 485 { 486 emit ERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData); 487 } 488 }