Message service
The message service is responsible for cross-chain messages between Ethereum and Linea, which:
- Allows a contract on the source chain to safely interact with a contract on the target chain (e.g. L1TokenBridge triggering mint on the L2TokenBridge),
 - Is responsible for bridging ETH (native currency on L1 and L2)
 - Supports:
- push: auto-execution on target layer if a fee is paid
 - pull: users / protocols responsible for triggering the transaction
 
 
Message service contractsβ
- Mainnet
 - Linea Sepolia
 
| L1 (Ethereum) Address | L2 (Linea) Address | 
|---|---|
0xd19d4B5d358258f05D7B411E21A1460D11B0876F  | 0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec  | 
| L1 (Sepolia) Address | L2 (Linea Sepolia) Address | 
|---|---|
0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5  | 0x971e727e956690b9957be6d51Ec16E73AcAC83A7  | 
How to useβ
Workflowβ
- dApp calls 
sendMessage(...)on the origin layer usingMessageService.sol- Args:
_to: the destination address on the destination chain_fee: the message service fee on the origin chain- An optional field used to incentivize a Postman to perform 
claimMessage(...)automatically on the destination chain (not available when bridging from L2 to L1) 
- An optional field used to incentivize a Postman to perform 
 _calldata: a flexible field that is generally created usingabi.encode(...)
 
 - Args:
 - dApp uses the Postman SDK (details to come) to pay for the execution of messages on the destination layer by:
- Triggering the delivery
- If messages donβt get delivered by the postman, the message can be manually claimed by calling 
claimMessagewith the parameters detailed in the interface below or by using the SDK. 
 - If messages donβt get delivered by the postman, the message can be manually claimed by calling 
 - Receiving the delivery in the dApp smart-contract
- This triggers 
claimMessage(...)on the destination layer that will call_towith_calldataand a value equal to. - The dApp smart-contract can inherit from 
MessageServiceBase.solto:- Verify that the call comes from the MessageService 
onlyMessagingService - Verify that the sender on the origin chain comes from a trusted contract (usually the dApp sibling contract) using 
onlyAuthorizedRemoteSender() 
 - Verify that the call comes from the MessageService 
 
 - This triggers 
 
 - Triggering the delivery
 
Interface IMessageService.solβ
IMessageService.sol
pragma solidity ^0.8.19;
interface IMessageService {
  /**
   * @dev Emitted when a message is sent.
   * @dev We include the message hash to save hashing costs on the rollup.
   */
  event MessageSent(
    address indexed _from,
    address indexed _to,
    uint256 _fee,
    uint256 _value,
    uint256 _nonce,
    bytes _calldata,
    bytes32 indexed _messageHash
  );
  /**
   * @dev Emitted when a message is claimed.
   */
  event MessageClaimed(bytes32 indexed _messageHash);
  /**
   * @dev Thrown when fees are lower than the minimum fee.
   */
  error FeeTooLow();
  /**
   * @dev Thrown when fees are lower than value.
   */
  error ValueShouldBeGreaterThanFee();
  /**
   * @dev Thrown when the value sent is less than the fee.
   * @dev Value to forward on is msg.value - _fee.
   */
  error ValueSentTooLow();
  /**
   * @dev Thrown when the destination address reverts.
   */
  error MessageSendingFailed(address destination);
  /**
   * @dev Thrown when the destination address reverts.
   */
  error FeePaymentFailed(address recipient);
  /**
   * @notice Sends a message for transporting from the given chain.
   * @dev This function should be called with a msg.value = _value + _fee. The fee will be paid on the destination chain.
   * @param _to The destination address on the destination chain.
   * @param _fee The message service fee on the origin chain.
   * @param _calldata The calldata used by the destination message service to call the destination contract.
   */
  function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable;
  /**
   * @notice Deliver a message to the destination chain.
   * @notice Is called automatically by the Postman, dApp or end user.
   * @param _from The msg.sender calling the origin message service.
   * @param _to The destination address on the destination chain.
   * @param _value The value to be transferred to the destination address.
   * @param _fee The message service fee on the origin chain.
   * @param _feeRecipient Address that will receive the fees.
   * @param _calldata The calldata used by the destination message service to call/forward to the destination contract.
   * @param _nonce Unique message number.
   */
  function claimMessage(
    address _from,
    address _to,
    uint256 _fee,
    uint256 _value,
    address payable _feeRecipient,
    bytes calldata _calldata,
    uint256 _nonce
  ) external;
  /**
   * @notice Returns the original sender of the message on the origin layer.
   * @return The original sender of the message on the origin layer.
   */
  function sender() external view returns (address);
}
Abstract contract MessageServiceBase.solβ
MessageServiceBase.sol
// SPDX-License-Identifier: OWNED BY Consensys Software Inc.
pragma solidity ^0.8.19;
import "./interfaces/IMessageService.sol";
/**
 * @title Base contract to manage cross-chain messaging.
 * @author Consensys Software Inc.
 */
abstract contract MessageServiceBase {
  IMessageService public messageService;
  address public remoteSender;
  uint256[10] private __base_gap;
  /**
   * @dev Thrown when the caller address is not the message service address
   */
  error CallerIsNotMessageService();
  /**
   * @dev Thrown when remote sender address is not authorized.
   */
  error SenderNotAuthorized();
  /**
   * @dev Thrown when an address is the default zero address.
   */
  error ZeroAddressNotAllowed();
  /**
   * @dev Modifier to make sure the caller is the known message service.
   *
   * Requirements:
   *
   * - The msg.sender must be the message service.
   */
  modifier onlyMessagingService() {
    if (msg.sender != address(messageService)) {
      revert CallerIsNotMessageService();
    }
    _;
  }
  /**
   * @dev Modifier to make sure the original sender is allowed.
   *
   * Requirements:
   *
   * - The original message sender via the message service must be a known sender.
   */
  modifier onlyAuthorizedRemoteSender() {
    if (messageService.sender() != remoteSender) {
      revert SenderNotAuthorized();
    }
    _;
  }
  /**
   * @notice Initializes the message service and remote sender address
   * @dev Must be initialized in the initialize function of the main contract or constructor
   * @param _messageService The message service address, cannot be empty.
   * @param _remoteSender The authorized remote sender address, cannot be empty.
   **/
  function _init_MessageServiceBase(address _messageService, address _remoteSender) internal {
    if (_messageService == address(0)) {
      revert ZeroAddressNotAllowed();
    }
    if (_remoteSender == address(0)) {
      revert ZeroAddressNotAllowed();
    }
    messageService = IMessageService(_messageService);
    remoteSender = _remoteSender;
  }
}