Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added hyperlane adapter #17

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import { IMailbox } from "./interfaces/IMailbox.sol";
import { IMessageRecipient } from "./interfaces/IMessageRecipient.sol";
import { IInterchainSecurityModule, ISpecifiesInterchainSecurityModule } from "./interfaces/IInterchainSecurityModule.sol";
import { TypeCasts } from "./libraries/TypeCasts.sol";
import { EncodeDecodeUtil } from "./libraries/EncodeDecodeUtil.sol";
import { Errors } from "./libraries/Errors.sol";
import { IMessageDispatcher } from "./interfaces/IMessageDispatcher.sol";
import { IMessageExecutor } from "./interfaces/IMessageExecutor.sol";
import "./libraries/MessageLib.sol";
import { IMessageDispatcher } from "../interfaces/IMessageDispatcher.sol";
import { IMessageExecutor } from "../interfaces/IMessageExecutor.sol";
import "../libraries/MessageLib.sol";

/**
* @title HyperlaneReceiverAdapter implementation.
* @notice `IBridgeReceiverAdapter` implementation that uses Hyperlane as the bridge.
*/
contract HyperlaneReceiverAdapter is
contract HyperlaneReceiverAdapterV2 is
Copy link
Author

@degencodebeast degencodebeast Nov 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to V2

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be v3?

Copy link
Author

@degencodebeast degencodebeast Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the adapter to use hyperlane V3 and added some unit tests as well

IMessageRecipient,
ISpecifiesInterchainSecurityModule,
Ownable
Expand Down Expand Up @@ -130,8 +131,7 @@ contract HyperlaneReceiverAdapter is
* @param _body Body of the message.
*/
function handle(
uint32,
/* _origin*/
uint32 _origin,
bytes32 _sender,
bytes memory _body
) external onlyMailbox {
Expand All @@ -142,20 +142,27 @@ contract HyperlaneReceiverAdapter is
bytes32 msgId,
uint256 srcChainId,
address srcSender
) = abi.decode(_body, (MessageLib.Message[], bytes32, uint256, address));
) = EncodeDecodeUtil.decode(_body);

if (_origin != srcChainId) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparing the origin and sender chain

revert Errors.UnauthorizedOrigin(_origin);
}

if (IMessageDispatcher(adapter) != senderAdapters[srcChainId]) {
revert Errors.UnauthorizedAdapter(srcChainId, adapter);
}

if (_messages.length < 1) {
revert Errors.NoMessagesSent(srcChainId);
}

if (executedMessages[msgId]) {
revert MessageIdAlreadyExecuted(msgId);
} else {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did all my revert conditions up front and did state changes after

_executedMessageId = executedMessages[msgId];
executedMessages[msgId] = true;
}
if (_messages.length < 1) {
revert Errors.NoMessagesSent(srcChainId);
}

if (_messages.length == 1) {
MessageLib.Message memory _message = _messages[0];
executeMessage(_message.to, _message.data, msgId, srcChainId, srcSender, _executedMessageId);
Expand All @@ -177,9 +184,11 @@ contract HyperlaneReceiverAdapter is
}
}

function getSenderAdapter(
uint256 _srcChainId
) public view returns (IMessageDispatcher _senderAdapter) {
function getSenderAdapter(uint256 _srcChainId)
public
view
returns (IMessageDispatcher _senderAdapter)
{
_senderAdapter = senderAdapters[_srcChainId];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { IInterchainGasPaymaster } from "./interfaces/IInterchainGasPaymaster.so
import { TypeCasts } from "./libraries/TypeCasts.sol";
import { Errors } from "./libraries/Errors.sol";
import { IMessageDispatcher, ISingleMessageDispatcher } from "./interfaces/ISingleMessageDispatcher.sol";
import { EncodeDecodeUtil } from "./libraries/EncodeDecodeUtil.sol";
import { IBatchedMessageDispatcher } from "./interfaces/IBatchedMessageDispatcher.sol";
import { IMessageExecutor } from "./interfaces/IMessageExecutor.sol";
import "./libraries/MessageLib.sol";
import { IMessageExecutor } from "../interfaces/IMessageExecutor.sol";
import "../libraries/MessageLib.sol";

contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDispatcher, Ownable {
contract HyperlaneSenderAdapterV2 is ISingleMessageDispatcher, IBatchedMessageDispatcher, Ownable {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to V2

/// @notice `Mailbox` contract reference.
IMailbox public immutable mailbox;

Expand All @@ -20,6 +21,8 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp

uint256 public nonce;

uint256 public immutable gasAmount;

/**
* @notice Receiver adapter address for each destination chain.
* @dev dstChainId => receiverAdapter address.
Expand Down Expand Up @@ -58,10 +61,18 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
* @notice HyperlaneSenderAdapter constructor.
* @param _mailbox Address of the Hyperlane `Mailbox` contract.
*/
constructor(address _mailbox, address _igp) {
constructor(
address _mailbox,
address _igp,
uint256 _gasAmount
) {
if (_mailbox == address(0)) {
revert Errors.InvalidMailboxZeroAddress();
}

// See https://docs.hyperlane.xyz/docs/build-with-hyperlane/guides/paying-for-interchain-gas
// Set gasAmount to the default (500,000) if _gasAmount is 0
gasAmount = (_gasAmount == 0) ? 500000 : _gasAmount;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made gasAmount a configurable option in the constructor, it it isn't set (set to zero), it defaults to 500k

mailbox = IMailbox(_mailbox);
_setIgp(_igp);
}
Expand All @@ -75,12 +86,10 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
bytes calldata /* data*/
) external view returns (uint256) {
uint32 dstDomainId = _getDestinationDomain(toChainId);
// destination gasAmount is hardcoded to 500k similar to Wormhole implementation
// See https://docs.hyperlane.xyz/docs/build-with-hyperlane/guides/paying-for-interchain-gas
try igp.quoteGasPayment(dstDomainId, 500000) returns (uint256 gasQuote) {
try igp.quoteGasPayment(dstDomainId, gasAmount) returns (uint256 gasQuote) {
return gasQuote;
} catch {
// Default to zero, MultiMessageSender.estimateTotalMessageFee doesn't expect this function to revert
return 0;
}
}
Expand Down Expand Up @@ -112,7 +121,7 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
MessageLib.Message[] memory _messages = new MessageLib.Message[](1);
_messages[0] = MessageLib.Message({ to: _to, data: _data });

bytes memory payload = abi.encode(_messages, msgId, block.chainid, msg.sender);
bytes memory payload = EncodeDecodeUtil.encode(_messages, msgId, block.chainid, msg.sender);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used the library I created for encoding/decoding to encode the messages with extra relevant data to generate a payload


bytes32 hyperlaneMsgId = IMailbox(mailbox).dispatch(
dstDomainId,
Expand All @@ -122,26 +131,20 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
);

// try to make gas payment, ignore failures
// destination gasAmount is hardcoded to 500k similar to Wormhole implementation
// refundAddress is set from MMS caller state variable
try
igp.payForGas{ value: msg.value }(
hyperlaneMsgId,
dstDomainId,
500000,
//address(this)
msg.sender
)
igp.payForGas{ value: msg.value }(hyperlaneMsgId, dstDomainId, gasAmount, msg.sender)
{} catch {}

emit MessageDispatched(msgId, msg.sender, _toChainId, _to, _data);
return msgId;
}

function dispatchMessageBatch(
uint256 _toChainId,
MessageLib.Message[] calldata _messages
) external payable override returns (bytes32) {
function dispatchMessageBatch(uint256 _toChainId, MessageLib.Message[] calldata _messages)
external
payable
override
returns (bytes32)
{
IMessageExecutor adapter = _getMessageExecutorAddress(_toChainId);
_checkAdapter(_toChainId, adapter);
uint32 dstDomainId = _getDestinationDomain(_toChainId);
Expand All @@ -152,7 +155,7 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp

uint256 _nonce = _incrementNonce();
bytes32 msgId = MessageLib.computeMessageBatchId(_nonce, msg.sender, _messages);
bytes memory payload = abi.encode(_messages, msgId, block.chainid, msg.sender);
bytes memory payload = EncodeDecodeUtil.encode(_messages, msgId, block.chainid, msg.sender);

bytes32 hyperlaneMsgId = IMailbox(mailbox).dispatch(
dstDomainId,
Expand All @@ -162,16 +165,8 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
);

// try to make gas payment, ignore failures
// destination gasAmount is hardcoded to 500k similar to Wormhole implementation
// refundAddress is set from MMS caller state variable
try
igp.payForGas{ value: msg.value }(
hyperlaneMsgId,
dstDomainId,
500000,
//address(this)
msg.sender
)
igp.payForGas{ value: msg.value }(hyperlaneMsgId, dstDomainId, gasAmount, msg.sender)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved gas amount to storage as gas amount is now a state variable set in the constructor

{} catch {}

emit MessageBatchDispatched(msgId, msg.sender, _toChainId, _messages);
Expand Down Expand Up @@ -201,9 +196,11 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
require(_executor == executor, "Dispatcher/executor-mis-match");
}

function getMessageExecutorAddress(
uint256 _toChainId
) external view returns (address _executorAddress) {
function getMessageExecutorAddress(uint256 _toChainId)
external
view
returns (address _executorAddress)
{
_executorAddress = address(_getMessageExecutorAddress(_toChainId));
}

Expand Down Expand Up @@ -261,9 +258,11 @@ contract HyperlaneSenderAdapter is ISingleMessageDispatcher, IBatchedMessageDisp
* @param _toChainId ID of the chain with which MessageDispatcher is communicating
* @return receiverAdapter MessageExecutor contract address
*/
function _getMessageExecutorAddress(
uint256 _toChainId
) internal view returns (IMessageExecutor receiverAdapter) {
function _getMessageExecutorAddress(uint256 _toChainId)
internal
view
returns (IMessageExecutor receiverAdapter)
{
_checkToChainId(_toChainId);
receiverAdapter = receiverAdapters[_toChainId];
}
Expand Down
10 changes: 5 additions & 5 deletions src/hyperlane-adapter/interfaces/IBatchedMessageDispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity 0.8.16;

import "./IMessageDispatcher.sol";
import "../../interfaces/IMessageDispatcher.sol";

/**
* @title ERC-5164: Cross-Chain Execution Standard, optional BatchMessageDispatcher extension
Expand All @@ -17,8 +17,8 @@ interface IBatchedMessageDispatcher is IMessageDispatcher {
* @param messages Array of Message dispatched
* @return bytes32 ID uniquely identifying the `messages`
*/
function dispatchMessageBatch(
uint256 toChainId,
MessageLib.Message[] calldata messages
) external payable returns (bytes32);
function dispatchMessageBatch(uint256 toChainId, MessageLib.Message[] calldata messages)
external
payable
returns (bytes32);
}
8 changes: 4 additions & 4 deletions src/hyperlane-adapter/interfaces/IInterchainGasPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ interface IInterchainGasPaymaster {
address _refundAddress
) external payable;

function quoteGasPayment(
uint32 _destinationDomain,
uint256 _gasAmount
) external view returns (uint256);
function quoteGasPayment(uint32 _destinationDomain, uint256 _gasAmount)
external
view
returns (uint256);
}
49 changes: 0 additions & 49 deletions src/hyperlane-adapter/interfaces/IMessageDispatcher.sol

This file was deleted.

56 changes: 0 additions & 56 deletions src/hyperlane-adapter/interfaces/IMessageExecutor.sol

This file was deleted.

6 changes: 5 additions & 1 deletion src/hyperlane-adapter/interfaces/IMessageRecipient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
pragma solidity 0.8.16;

interface IMessageRecipient {
function handle(uint32 _origin, bytes32 _sender, bytes calldata _message) external;
function handle(
uint32 _origin,
bytes32 _sender,
bytes calldata _message
) external;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity 0.8.16;

import "./IMessageDispatcher.sol";
import "../../interfaces/IMessageDispatcher.sol";

/**
* @title ERC-5164: Cross-Chain Execution Standard, optional SingleMessageDispatcher extension
Expand Down
Loading