Skip to main content

MailboxClient

继承自MailboxClient是一种简单的方法,可以确保您的合约知道在何处发送或从何处接收链间消息。

该mix-in合约维护着指向 Hyperlane 开发人员可能需要与之交互的三个合约的指针:

  1. Mailbox (required)
  2. IPostDispatchHook (optional)
  3. IInterchainSecurityModule (optional)

MailboxClient公开了允许子类通过mailbox储变量轻松发送消息到Mailbox的函数,并通过onlyMailbox修饰符允许消息传递。

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;

// ============ Internal Imports ============
import {IMailbox} from "../interfaces/IMailbox.sol";
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol";
import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule.sol";
import {Message} from "../libs/Message.sol";

// ============ External Imports ============
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

abstract contract MailboxClient is OwnableUpgradeable {
using Message for bytes;

IMailbox public immutable mailbox;

uint32 public immutable localDomain;

IPostDispatchHook public hook;

IInterchainSecurityModule public interchainSecurityModule;

// ============ Modifiers ============
modifier onlyContract(address _contract) {
require(
Address.isContract(_contract),
"MailboxClient: invalid mailbox"
);
_;
}

modifier onlyContractOrNull(address _contract) {
require(
Address.isContract(_contract) || _contract == address(0),
"MailboxClient: invalid contract setting"
);
_;
}

/**
* @notice Only accept messages from an Hyperlane Mailbox contract
*/
modifier onlyMailbox() {
require(
msg.sender == address(mailbox),
"MailboxClient: sender not mailbox"
);
_;
}

constructor(address _mailbox) onlyContract(_mailbox) {
mailbox = IMailbox(_mailbox);
localDomain = mailbox.localDomain();
_transferOwnership(msg.sender);
}

/**
* @notice Sets the address of the application's custom hook.
* @param _hook The address of the hook contract.
*/
function setHook(address _hook) public onlyContractOrNull(_hook) onlyOwner {
hook = IPostDispatchHook(_hook);
}

/**
* @notice Sets the address of the application's custom interchain security module.
* @param _module The address of the interchain security module contract.
*/
function setInterchainSecurityModule(
address _module
) public onlyContractOrNull(_module) onlyOwner {
interchainSecurityModule = IInterchainSecurityModule(_module);
}

// ======== Initializer =========
function _MailboxClient_initialize(
address _hook,
address _interchainSecurityModule,
address _owner
) internal onlyInitializing {
__Ownable_init();
setHook(_hook);
setInterchainSecurityModule(_interchainSecurityModule);
_transferOwnership(_owner);
}

function _isLatestDispatched(bytes32 id) internal view returns (bool) {
return mailbox.latestDispatchedId() == id;
}

function _metadata(
uint32 /*_destinationDomain*/
) internal view virtual returns (bytes memory) {
return "";
}

function _dispatch(
uint32 _destinationDomain,
bytes32 _recipient,
bytes memory _messageBody
) internal virtual returns (bytes32) {
return
_dispatch(_destinationDomain, _recipient, msg.value, _messageBody);
}

function _dispatch(
uint32 _destinationDomain,
bytes32 _recipient,
uint256 _value,
bytes memory _messageBody
) internal virtual returns (bytes32) {
return
mailbox.dispatch{value: _value}(
_destinationDomain,
_recipient,
_messageBody,
_metadata(_destinationDomain),
hook
);
}

function _quoteDispatch(
uint32 _destinationDomain,
bytes32 _recipient,
bytes memory _messageBody
) internal view virtual returns (uint256) {
return
mailbox.quoteDispatch(
_destinationDomain,
_recipient,
_messageBody,
_metadata(_destinationDomain),
hook
);
}
}