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

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
     5  import { SafeCall } from "src/libraries/SafeCall.sol";
     6  import { Hashing } from "src/libraries/Hashing.sol";
     7  import { Encoding } from "src/libraries/Encoding.sol";
     8  import { Constants } from "src/libraries/Constants.sol";
     9  
    10  /// @custom:legacy
    11  /// @title CrossDomainMessengerLegacySpacer0
    12  /// @notice Contract only exists to add a spacer to the CrossDomainMessenger where the
    13  ///         libAddressManager variable used to exist. Must be the first contract in the inheritance
    14  ///         tree of the CrossDomainMessenger.
    15  contract CrossDomainMessengerLegacySpacer0 {
    16      /// @custom:legacy
    17      /// @custom:spacer libAddressManager
    18      /// @notice Spacer for backwards compatibility.
    19      address private spacer_0_0_20;
    20  }
    21  
    22  /// @custom:legacy
    23  /// @title CrossDomainMessengerLegacySpacer1
    24  /// @notice Contract only exists to add a spacer to the CrossDomainMessenger where the
    25  ///         PausableUpgradable and OwnableUpgradeable variables used to exist. Must be
    26  ///         the third contract in the inheritance tree of the CrossDomainMessenger.
    27  contract CrossDomainMessengerLegacySpacer1 {
    28      /// @custom:legacy
    29      /// @custom:spacer ContextUpgradable's __gap
    30      /// @notice Spacer for backwards compatibility. Comes from OpenZeppelin
    31      ///         ContextUpgradable.
    32      uint256[50] private spacer_1_0_1600;
    33  
    34      /// @custom:legacy
    35      /// @custom:spacer OwnableUpgradeable's _owner
    36      /// @notice Spacer for backwards compatibility.
    37      ///         Come from OpenZeppelin OwnableUpgradeable.
    38      address private spacer_51_0_20;
    39  
    40      /// @custom:legacy
    41      /// @custom:spacer OwnableUpgradeable's __gap
    42      /// @notice Spacer for backwards compatibility. Comes from OpenZeppelin
    43      ///         OwnableUpgradeable.
    44      uint256[49] private spacer_52_0_1568;
    45  
    46      /// @custom:legacy
    47      /// @custom:spacer PausableUpgradable's _paused
    48      /// @notice Spacer for backwards compatibility. Comes from OpenZeppelin
    49      ///         PausableUpgradable.
    50      bool private spacer_101_0_1;
    51  
    52      /// @custom:legacy
    53      /// @custom:spacer PausableUpgradable's __gap
    54      /// @notice Spacer for backwards compatibility. Comes from OpenZeppelin
    55      ///         PausableUpgradable.
    56      uint256[49] private spacer_102_0_1568;
    57  
    58      /// @custom:legacy
    59      /// @custom:spacer ReentrancyGuardUpgradeable's `_status` field.
    60      /// @notice Spacer for backwards compatibility.
    61      uint256 private spacer_151_0_32;
    62  
    63      /// @custom:legacy
    64      /// @custom:spacer ReentrancyGuardUpgradeable's __gap
    65      /// @notice Spacer for backwards compatibility.
    66      uint256[49] private spacer_152_0_1568;
    67  
    68      /// @custom:legacy
    69      /// @custom:spacer blockedMessages
    70      /// @notice Spacer for backwards compatibility.
    71      mapping(bytes32 => bool) private spacer_201_0_32;
    72  
    73      /// @custom:legacy
    74      /// @custom:spacer relayedMessages
    75      /// @notice Spacer for backwards compatibility.
    76      mapping(bytes32 => bool) private spacer_202_0_32;
    77  }
    78  
    79  /// @custom:upgradeable
    80  /// @title CrossDomainMessenger
    81  /// @notice CrossDomainMessenger is a base contract that provides the core logic for the L1 and L2
    82  ///         cross-chain messenger contracts. It's designed to be a universal interface that only
    83  ///         needs to be extended slightly to provide low-level message passing functionality on each
    84  ///         chain it's deployed on. Currently only designed for message passing between two paired
    85  ///         chains and does not support one-to-many interactions.
    86  ///         Any changes to this contract MUST result in a semver bump for contracts that inherit it.
    87  abstract contract CrossDomainMessenger is
    88      CrossDomainMessengerLegacySpacer0,
    89      Initializable,
    90      CrossDomainMessengerLegacySpacer1
    91  {
    92      /// @notice Current message version identifier.
    93      uint16 public constant MESSAGE_VERSION = 1;
    94  
    95      /// @notice Constant overhead added to the base gas for a message.
    96      uint64 public constant RELAY_CONSTANT_OVERHEAD = 200_000;
    97  
    98      /// @notice Numerator for dynamic overhead added to the base gas for a message.
    99      uint64 public constant MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR = 64;
   100  
   101      /// @notice Denominator for dynamic overhead added to the base gas for a message.
   102      uint64 public constant MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR = 63;
   103  
   104      /// @notice Extra gas added to base gas for each byte of calldata in a message.
   105      uint64 public constant MIN_GAS_CALLDATA_OVERHEAD = 16;
   106  
   107      /// @notice Gas reserved for performing the external call in `relayMessage`.
   108      uint64 public constant RELAY_CALL_OVERHEAD = 40_000;
   109  
   110      /// @notice Gas reserved for finalizing the execution of `relayMessage` after the safe call.
   111      uint64 public constant RELAY_RESERVED_GAS = 40_000;
   112  
   113      /// @notice Gas reserved for the execution between the `hasMinGas` check and the external
   114      ///         call in `relayMessage`.
   115      uint64 public constant RELAY_GAS_CHECK_BUFFER = 5_000;
   116  
   117      /// @notice Mapping of message hashes to boolean receipt values. Note that a message will only
   118      ///         be present in this mapping if it has successfully been relayed on this chain, and
   119      ///         can therefore not be relayed again.
   120      mapping(bytes32 => bool) public successfulMessages;
   121  
   122      /// @notice Address of the sender of the currently executing message on the other chain. If the
   123      ///         value of this variable is the default value (0x00000000...dead) then no message is
   124      ///         currently being executed. Use the xDomainMessageSender getter which will throw an
   125      ///         error if this is the case.
   126      address internal xDomainMsgSender;
   127  
   128      /// @notice Nonce for the next message to be sent, without the message version applied. Use the
   129      ///         messageNonce getter which will insert the message version into the nonce to give you
   130      ///         the actual nonce to be used for the message.
   131      uint240 internal msgNonce;
   132  
   133      /// @notice Mapping of message hashes to a boolean if and only if the message has failed to be
   134      ///         executed at least once. A message will not be present in this mapping if it
   135      ///         successfully executed on the first attempt.
   136      mapping(bytes32 => bool) public failedMessages;
   137  
   138      /// @notice CrossDomainMessenger contract on the other chain.
   139      /// @custom:network-specific
   140      CrossDomainMessenger public otherMessenger;
   141  
   142      /// @notice Reserve extra slots in the storage layout for future upgrades.
   143      ///         A gap size of 43 was chosen here, so that the first slot used in a child contract
   144      ///         would be 1 plus a multiple of 50.
   145      uint256[43] private __gap;
   146  
   147      /// @notice Emitted whenever a message is sent to the other chain.
   148      /// @param target       Address of the recipient of the message.
   149      /// @param sender       Address of the sender of the message.
   150      /// @param message      Message to trigger the recipient address with.
   151      /// @param messageNonce Unique nonce attached to the message.
   152      /// @param gasLimit     Minimum gas limit that the message can be executed with.
   153      event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit);
   154  
   155      /// @notice Additional event data to emit, required as of Bedrock. Cannot be merged with the
   156      ///         SentMessage event without breaking the ABI of this contract, this is good enough.
   157      /// @param sender Address of the sender of the message.
   158      /// @param value  ETH value sent along with the message to the recipient.
   159      event SentMessageExtension1(address indexed sender, uint256 value);
   160  
   161      /// @notice Emitted whenever a message is successfully relayed on this chain.
   162      /// @param msgHash Hash of the message that was relayed.
   163      event RelayedMessage(bytes32 indexed msgHash);
   164  
   165      /// @notice Emitted whenever a message fails to be relayed on this chain.
   166      /// @param msgHash Hash of the message that failed to be relayed.
   167      event FailedRelayedMessage(bytes32 indexed msgHash);
   168  
   169      /// @notice Sends a message to some target address on the other chain. Note that if the call
   170      ///         always reverts, then the message will be unrelayable, and any ETH sent will be
   171      ///         permanently locked. The same will occur if the target on the other chain is
   172      ///         considered unsafe (see the _isUnsafeTarget() function).
   173      /// @param _target      Target contract or wallet address.
   174      /// @param _message     Message to trigger the target address with.
   175      /// @param _minGasLimit Minimum gas limit that the message can be executed with.
   176      function sendMessage(address _target, bytes calldata _message, uint32 _minGasLimit) external payable {
   177          // Triggers a message to the other messenger. Note that the amount of gas provided to the
   178          // message is the amount of gas requested by the user PLUS the base gas value. We want to
   179          // guarantee the property that the call to the target contract will always have at least
   180          // the minimum gas limit specified by the user.
   181          _sendMessage({
   182              _to: address(otherMessenger),
   183              _gasLimit: baseGas(_message, _minGasLimit),
   184              _value: msg.value,
   185              _data: abi.encodeWithSelector(
   186                  this.relayMessage.selector, messageNonce(), msg.sender, _target, msg.value, _minGasLimit, _message
   187                  )
   188          });
   189  
   190          emit SentMessage(_target, msg.sender, _message, messageNonce(), _minGasLimit);
   191          emit SentMessageExtension1(msg.sender, msg.value);
   192  
   193          unchecked {
   194              ++msgNonce;
   195          }
   196      }
   197  
   198      /// @notice Relays a message that was sent by the other CrossDomainMessenger contract. Can only
   199      ///         be executed via cross-chain call from the other messenger OR if the message was
   200      ///         already received once and is currently being replayed.
   201      /// @param _nonce       Nonce of the message being relayed.
   202      /// @param _sender      Address of the user who sent the message.
   203      /// @param _target      Address that the message is targeted at.
   204      /// @param _value       ETH value to send with the message.
   205      /// @param _minGasLimit Minimum amount of gas that the message can be executed with.
   206      /// @param _message     Message to send to the target.
   207      function relayMessage(
   208          uint256 _nonce,
   209          address _sender,
   210          address _target,
   211          uint256 _value,
   212          uint256 _minGasLimit,
   213          bytes calldata _message
   214      )
   215          external
   216          payable
   217      {
   218          // On L1 this function will check the Portal for its paused status.
   219          // On L2 this function should be a no-op, because paused will always return false.
   220          require(paused() == false, "CrossDomainMessenger: paused");
   221  
   222          (, uint16 version) = Encoding.decodeVersionedNonce(_nonce);
   223          require(version < 2, "CrossDomainMessenger: only version 0 or 1 messages are supported at this time");
   224  
   225          // If the message is version 0, then it's a migrated legacy withdrawal. We therefore need
   226          // to check that the legacy version of the message has not already been relayed.
   227          if (version == 0) {
   228              bytes32 oldHash = Hashing.hashCrossDomainMessageV0(_target, _sender, _message, _nonce);
   229              require(successfulMessages[oldHash] == false, "CrossDomainMessenger: legacy withdrawal already relayed");
   230          }
   231  
   232          // We use the v1 message hash as the unique identifier for the message because it commits
   233          // to the value and minimum gas limit of the message.
   234          bytes32 versionedHash =
   235              Hashing.hashCrossDomainMessageV1(_nonce, _sender, _target, _value, _minGasLimit, _message);
   236  
   237          if (_isOtherMessenger()) {
   238              // These properties should always hold when the message is first submitted (as
   239              // opposed to being replayed).
   240              assert(msg.value == _value);
   241              assert(!failedMessages[versionedHash]);
   242          } else {
   243              require(msg.value == 0, "CrossDomainMessenger: value must be zero unless message is from a system address");
   244  
   245              require(failedMessages[versionedHash], "CrossDomainMessenger: message cannot be replayed");
   246          }
   247  
   248          require(
   249              _isUnsafeTarget(_target) == false, "CrossDomainMessenger: cannot send message to blocked system address"
   250          );
   251  
   252          require(successfulMessages[versionedHash] == false, "CrossDomainMessenger: message has already been relayed");
   253  
   254          // If there is not enough gas left to perform the external call and finish the execution,
   255          // return early and assign the message to the failedMessages mapping.
   256          // We are asserting that we have enough gas to:
   257          // 1. Call the target contract (_minGasLimit + RELAY_CALL_OVERHEAD + RELAY_GAS_CHECK_BUFFER)
   258          //   1.a. The RELAY_CALL_OVERHEAD is included in `hasMinGas`.
   259          // 2. Finish the execution after the external call (RELAY_RESERVED_GAS).
   260          //
   261          // If `xDomainMsgSender` is not the default L2 sender, this function
   262          // is being re-entered. This marks the message as failed to allow it to be replayed.
   263          if (
   264              !SafeCall.hasMinGas(_minGasLimit, RELAY_RESERVED_GAS + RELAY_GAS_CHECK_BUFFER)
   265                  || xDomainMsgSender != Constants.DEFAULT_L2_SENDER
   266          ) {
   267              failedMessages[versionedHash] = true;
   268              emit FailedRelayedMessage(versionedHash);
   269  
   270              // Revert in this case if the transaction was triggered by the estimation address. This
   271              // should only be possible during gas estimation or we have bigger problems. Reverting
   272              // here will make the behavior of gas estimation change such that the gas limit
   273              // computed will be the amount required to relay the message, even if that amount is
   274              // greater than the minimum gas limit specified by the user.
   275              if (tx.origin == Constants.ESTIMATION_ADDRESS) {
   276                  revert("CrossDomainMessenger: failed to relay message");
   277              }
   278  
   279              return;
   280          }
   281  
   282          xDomainMsgSender = _sender;
   283          bool success = SafeCall.call(_target, gasleft() - RELAY_RESERVED_GAS, _value, _message);
   284          xDomainMsgSender = Constants.DEFAULT_L2_SENDER;
   285  
   286          if (success) {
   287              // This check is identical to one above, but it ensures that the same message cannot be relayed
   288              // twice, and adds a layer of protection against rentrancy.
   289              assert(successfulMessages[versionedHash] == false);
   290              successfulMessages[versionedHash] = true;
   291              emit RelayedMessage(versionedHash);
   292          } else {
   293              failedMessages[versionedHash] = true;
   294              emit FailedRelayedMessage(versionedHash);
   295  
   296              // Revert in this case if the transaction was triggered by the estimation address. This
   297              // should only be possible during gas estimation or we have bigger problems. Reverting
   298              // here will make the behavior of gas estimation change such that the gas limit
   299              // computed will be the amount required to relay the message, even if that amount is
   300              // greater than the minimum gas limit specified by the user.
   301              if (tx.origin == Constants.ESTIMATION_ADDRESS) {
   302                  revert("CrossDomainMessenger: failed to relay message");
   303              }
   304          }
   305      }
   306  
   307      /// @notice Retrieves the address of the contract or wallet that initiated the currently
   308      ///         executing message on the other chain. Will throw an error if there is no message
   309      ///         currently being executed. Allows the recipient of a call to see who triggered it.
   310      /// @return Address of the sender of the currently executing message on the other chain.
   311      function xDomainMessageSender() external view returns (address) {
   312          require(
   313              xDomainMsgSender != Constants.DEFAULT_L2_SENDER, "CrossDomainMessenger: xDomainMessageSender is not set"
   314          );
   315  
   316          return xDomainMsgSender;
   317      }
   318  
   319      /// @notice Retrieves the address of the paired CrossDomainMessenger contract on the other chain
   320      ///         Public getter is legacy and will be removed in the future. Use `otherMessenger()` instead.
   321      /// @return CrossDomainMessenger contract on the other chain.
   322      /// @custom:legacy
   323      function OTHER_MESSENGER() public view returns (CrossDomainMessenger) {
   324          return otherMessenger;
   325      }
   326  
   327      /// @notice Retrieves the next message nonce. Message version will be added to the upper two
   328      ///         bytes of the message nonce. Message version allows us to treat messages as having
   329      ///         different structures.
   330      /// @return Nonce of the next message to be sent, with added message version.
   331      function messageNonce() public view returns (uint256) {
   332          return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION);
   333      }
   334  
   335      /// @notice Computes the amount of gas required to guarantee that a given message will be
   336      ///         received on the other chain without running out of gas. Guaranteeing that a message
   337      ///         will not run out of gas is important because this ensures that a message can always
   338      ///         be replayed on the other chain if it fails to execute completely.
   339      /// @param _message     Message to compute the amount of required gas for.
   340      /// @param _minGasLimit Minimum desired gas limit when message goes to target.
   341      /// @return Amount of gas required to guarantee message receipt.
   342      function baseGas(bytes calldata _message, uint32 _minGasLimit) public pure returns (uint64) {
   343          return
   344          // Constant overhead
   345          RELAY_CONSTANT_OVERHEAD
   346          // Calldata overhead
   347          + (uint64(_message.length) * MIN_GAS_CALLDATA_OVERHEAD)
   348          // Dynamic overhead (EIP-150)
   349          + ((_minGasLimit * MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR) / MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR)
   350          // Gas reserved for the worst-case cost of 3/5 of the `CALL` opcode's dynamic gas
   351          // factors. (Conservative)
   352          + RELAY_CALL_OVERHEAD
   353          // Relay reserved gas (to ensure execution of `relayMessage` completes after the
   354          // subcontext finishes executing) (Conservative)
   355          + RELAY_RESERVED_GAS
   356          // Gas reserved for the execution between the `hasMinGas` check and the `CALL`
   357          // opcode. (Conservative)
   358          + RELAY_GAS_CHECK_BUFFER;
   359      }
   360  
   361      /// @notice Initializer.
   362      /// @param _otherMessenger CrossDomainMessenger contract on the other chain.
   363      function __CrossDomainMessenger_init(CrossDomainMessenger _otherMessenger) internal onlyInitializing {
   364          // We only want to set the xDomainMsgSender to the default value if it hasn't been initialized yet,
   365          // meaning that this is a fresh contract deployment.
   366          // This prevents resetting the xDomainMsgSender to the default value during an upgrade, which would enable
   367          // a reentrant withdrawal to sandwhich the upgrade replay a withdrawal twice.
   368          if (xDomainMsgSender == address(0)) {
   369              xDomainMsgSender = Constants.DEFAULT_L2_SENDER;
   370          }
   371          otherMessenger = _otherMessenger;
   372      }
   373  
   374      /// @notice Sends a low-level message to the other messenger. Needs to be implemented by child
   375      ///         contracts because the logic for this depends on the network where the messenger is
   376      ///         being deployed.
   377      /// @param _to       Recipient of the message on the other chain.
   378      /// @param _gasLimit Minimum gas limit the message can be executed with.
   379      /// @param _value    Amount of ETH to send with the message.
   380      /// @param _data     Message data.
   381      function _sendMessage(address _to, uint64 _gasLimit, uint256 _value, bytes memory _data) internal virtual;
   382  
   383      /// @notice Checks whether the message is coming from the other messenger. Implemented by child
   384      ///         contracts because the logic for this depends on the network where the messenger is
   385      ///         being deployed.
   386      /// @return Whether the message is coming from the other messenger.
   387      function _isOtherMessenger() internal view virtual returns (bool);
   388  
   389      /// @notice Checks whether a given call target is a system address that could cause the
   390      ///         messenger to peform an unsafe action. This is NOT a mechanism for blocking user
   391      ///         addresses. This is ONLY used to prevent the execution of messages to specific
   392      ///         system addresses that could cause security issues, e.g., having the
   393      ///         CrossDomainMessenger send messages to itself.
   394      /// @param _target Address of the contract to check.
   395      /// @return Whether or not the address is an unsafe system address.
   396      function _isUnsafeTarget(address _target) internal view virtual returns (bool);
   397  
   398      /// @notice This function should return true if the contract is paused.
   399      ///         On L1 this function will check the SuperchainConfig for its paused status.
   400      ///         On L2 this function should be a no-op.
   401      /// @return Whether or not the contract is paused.
   402      function paused() public view virtual returns (bool) {
   403          return false;
   404      }
   405  }