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

Modifying IGP to be a hook #2638

Merged
merged 13 commits into from
Aug 15, 2023
26 changes: 17 additions & 9 deletions solidity/contracts/Mailbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ contract Mailbox is IMailbox, Versioned, Ownable {

// A monotonically increasing nonce for outbound unique message IDs.
uint32 public nonce;
bytes32 public latestDispatchedId;

// The default ISM, used if the recipient fails to specify one.
IInterchainSecurityModule public defaultIsm;

// The default post dispatch hook, used for post processing of dispatched messages.
IPostDispatchHook public defaultHook;

// Mapping of message ID to sender of the call that processed the message.
// Mapping of message ID to delivery context that processed the message.
struct Delivery {
address sender;
// uint48 value?
Expand Down Expand Up @@ -101,7 +102,8 @@ contract Mailbox is IMailbox, Versioned, Ownable {
_destinationDomain,
_recipientAddress,
_messageBody,
bytes("")
defaultHook,
_messageBody[0:0]
);
}

Expand Down Expand Up @@ -135,7 +137,7 @@ contract Mailbox is IMailbox, Versioned, Ownable {
bytes calldata messageBody,
IPostDispatchHook hook,
bytes calldata metadata
) public returns (bytes32) {
) public payable returns (bytes32) {
// Format the message into packed bytes.
bytes memory message = Message.formatMessage(
VERSION,
Expand All @@ -150,6 +152,7 @@ contract Mailbox is IMailbox, Versioned, Ownable {
// effects
nonce += 1;
bytes32 id = message.id();
latestDispatchedId = id;
emit DispatchId(id);
emit Dispatch(message);

Expand Down Expand Up @@ -186,18 +189,23 @@ contract Mailbox is IMailbox, Versioned, Ownable {

address recipient = _message.recipientAddress();

// effects
deliveries[_id] = Delivery({
sender: msg.sender
// value: uint48(msg.value),
// timestamp: uint48(block.number)
});
emit Process(_message);
emit ProcessId(_id);

// interactions
// Verify the message via the ISM.
IInterchainSecurityModule _ism = IInterchainSecurityModule(
recipientIsm(recipient)
);
require(_ism.verify(_metadata, _message), "verification failed");

// effects
deliveries[_id] = Delivery({sender: msg.sender});
emit Process(_message);
emit ProcessId(_id);

// Deliver the message to the recipient. (interactions)
// Deliver the message to the recipient.
IMessageRecipient(recipient).handle{value: msg.value}(
_message.origin(),
_message.sender(),
Expand Down
14 changes: 12 additions & 2 deletions solidity/contracts/client/MailboxClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ pragma solidity >=0.6.11;

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

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

abstract contract MailboxClient {
using Message for bytes;

IMailbox immutable mailbox;

constructor(address _mailbox) {
require(Address.isContract(_mailbox), "!contract");
require(Address.isContract(_mailbox), "MailboxClient: invalid mailbox");
mailbox = IMailbox(_mailbox);
}

Expand All @@ -21,7 +24,14 @@ abstract contract MailboxClient {
* @notice Only accept messages from an Hyperlane Mailbox contract
*/
modifier onlyMailbox() {
require(msg.sender == address(mailbox), "!mailbox");
require(
msg.sender == address(mailbox),
"MailboxClient: sender not mailbox"
);
_;
}

function isLatestDispatched(bytes32 id) internal view returns (bool) {
return mailbox.latestDispatchedId() == id;
}
}
101 changes: 0 additions & 101 deletions solidity/contracts/hooks/AbstractBridgeHook.sol

This file was deleted.

24 changes: 0 additions & 24 deletions solidity/contracts/hooks/AbstractHook.sol

This file was deleted.

40 changes: 19 additions & 21 deletions solidity/contracts/hooks/AbstractMessageIdAuthHook.sol
aroralanuk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,23 @@ pragma solidity >=0.8.0;
@@@@@@@@@ @@@@@@@@*/

// ============ Internal Imports ============
import {AbstractHook} from "./AbstractHook.sol";
import {AbstractMessageIdAuthorizedIsm} from "../isms/hook/AbstractMessageIdAuthorizedIsm.sol";
import {TypeCasts} from "../libs/TypeCasts.sol";
import {Message} from "../libs/Message.sol";
import {OPStackHookMetadata} from "../libs/hooks/OPStackHookMetadata.sol";
import {MailboxClient} from "../client/MailboxClient.sol";
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol";

// ============ External Imports ============
import {ICrossDomainMessenger} from "../interfaces/optimism/ICrossDomainMessenger.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

/**
* @title AbstractMessageIdAuthHook
* @notice Message hook to inform an Abstract Message ID ISM of messages published through
* the native OPStack bridge.
* a third-party bridge.
* @dev V3 WIP
*/
abstract contract AbstractMessageIdAuthHook is AbstractHook {
abstract contract AbstractMessageIdAuthHook is
IPostDispatchHook,
MailboxClient
{
using Message for bytes;

// ============ Constants ============
Expand All @@ -44,43 +43,42 @@ abstract contract AbstractMessageIdAuthHook is AbstractHook {
// ============ Constructor ============

constructor(
address _mailbox,
address mailbox,
uint32 _destinationDomain,
address _ism
) AbstractHook(_mailbox) {
) MailboxClient(mailbox) {
require(_ism != address(0), "invalid ISM");
require(_destinationDomain != 0, "invalid destination domain");
ism = _ism;
destinationDomain = _destinationDomain;
}

function _sendMessageId(bytes calldata metadata, bytes memory payload)
internal
virtual;

/**
* @notice Hook to inform the optimism ISM of messages published through.
* metadata The metadata for the hook caller
* @param message The message being dispatched
*/
function _postDispatch(bytes calldata metadata, bytes calldata message)
internal
function postDispatch(bytes calldata metadata, bytes calldata message)
external
payable
override
returns (IPostDispatchHook)
{
bytes32 id = message.id();
require(isLatestDispatched(id), "message not latest dispatched");
require(
message.destination() == destinationDomain,
"invalid destination domain"
);
// TODO: handle msg.value?

bytes memory payload = abi.encodeCall(
AbstractMessageIdAuthorizedIsm.verifyMessageId,
message.id()
id
);
_sendMessageId(metadata, payload);

// no next post-dispatch hook
// TODO: consider configuring?
return IPostDispatchHook(address(0));
}

function _sendMessageId(bytes calldata metadata, bytes memory payload)
internal
virtual;
}
60 changes: 60 additions & 0 deletions solidity/contracts/hooks/DefaultHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/

import {Message} from "../libs/Message.sol";
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol";
import {DomainRoutingHook} from "./DomainRoutingHook.sol";

contract ConfigurableDomainRoutingHook is DomainRoutingHook {
using Message for bytes;

/// @notice mapping of destination domain and recipient to custom hook
mapping(bytes32 => address) public customHooks;

constructor(address mailbox, address owner) DomainRoutingHook(owner) {}

function postDispatch(bytes calldata metadata, bytes calldata message)
public
payable
override
{
bytes32 hookKey = keccak256(
abi.encodePacked(message.destination(), message.recipient())
);

address customHookPreset = customHooks[hookKey];
if (customHookPreset != address(0)) {
IPostDispatchHook(customHookPreset).postDispatch{value: msg.value}(
metadata,
message
);
} else {
super.postDispatch(metadata, message);
}
}

// TODO: need to restrict sender
function configCustomHook(
uint32 destinationDomain,
bytes32 recipient,
address hook
) external {
bytes32 hookKey = keccak256(
abi.encodePacked(destinationDomain, recipient)
);
require(customHooks[hookKey] == address(0), "hook already set");
customHooks[hookKey] = hook;
}
}
Loading
Loading