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

Add RoutingIsm #1985

Merged
merged 28 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
356717b
Add RoutingIsm
asaj Mar 22, 2023
72936f5
Merge branch 'main' into asaj/routing
asaj Mar 22, 2023
1cff464
Comments and ICA ISM
asaj Mar 22, 2023
c00b1f5
Add ICA routing ISM
asaj Mar 22, 2023
6dca359
rm
asaj Mar 22, 2023
9b4d5ef
Merge branch 'main' into asaj/routing
asaj Mar 22, 2023
6d554fd
test use of mailbox default ISM
asaj Mar 22, 2023
c68c6e0
Remove duplicate test
asaj Mar 22, 2023
0651853
Merge branch 'main' into asaj/routing
asaj Mar 29, 2023
b734c66
Add tests
asaj Mar 29, 2023
454788f
Add DomainRoutingIsmFactory
asaj Apr 4, 2023
19fba46
Merge main
asaj Apr 4, 2023
696348e
cleanup
asaj Apr 4, 2023
7fb391c
Merge branch 'main' into asaj/routing
asaj Apr 4, 2023
fe1c223
Merge branch 'main' into asaj/routing
asaj Apr 4, 2023
13d9ace
more coverage
asaj Apr 4, 2023
7924193
Merge branch 'asaj/routing' of github.com:abacus-network/abacus-monor…
asaj Apr 4, 2023
8a28813
Test factory
asaj Apr 4, 2023
f27e08a
Merge branch 'main' into asaj/routing
asaj Apr 5, 2023
4e143c9
Merge branch 'main' into asaj/routing
asaj Apr 5, 2023
27c776f
Merge branch 'asaj/routing' of github.com:abacus-network/abacus-monor…
asaj Apr 6, 2023
edc1701
Merge branch 'main' into asaj/routing
asaj Apr 6, 2023
d896d66
Merge branch 'main' into asaj/routing
asaj Apr 12, 2023
fc5cf95
Merge branch 'asaj/routing' of github.com:abacus-network/abacus-monor…
asaj Apr 12, 2023
a0a8987
Comments
asaj Apr 12, 2023
b5d2579
Fix tests
asaj Apr 12, 2023
6e287c5
Merge branch 'main' into asaj/routing
asaj Apr 17, 2023
409faf9
Pragma
asaj Apr 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions solidity/contracts/isms/routing/AbstractRoutingIsm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../../../interfaces/IInterchainSecurityModule.sol";
import {IRoutingIsm} from "../../../interfaces/IRoutingIsm.sol";

/**
* @title RoutingIsm
*/
abstract contract AbstractRoutingIsm is IRoutingIsm {
// ============ Constants ============

uint8 public constant moduleType =
uint8(IInterchainSecurityModule.Types.ROUTING);

// ============ Virtual Functions ============
// ======= OVERRIDE THESE TO IMPLEMENT =======

/**
* @notice Returns the ISM responsible for verifying _message
* @dev Can change based on the content of _message
* @param _message Hyperlane formatted interchain message
* @return module The ISM to use to verify _message
*/
function route(bytes calldata _message)
public
view
virtual
returns (IInterchainSecurityModule);

// ============ Public Functions ============

/**
* @notice Requires that m-of-n validators verify a merkle root,
* and verifies a merkle proof of `_message` against that root.
* @param _metadata ABI encoded module metadata (see RoutingIsmMetadata.sol)
* @param _message Formatted Hyperlane message (see Message.sol).
*/
function verify(bytes calldata _metadata, bytes calldata _message)
public
returns (bool)
{
require(route(_message).verify(_metadata, _message), "!verify");
return true;
asaj marked this conversation as resolved.
Show resolved Hide resolved
}
}
52 changes: 52 additions & 0 deletions solidity/contracts/isms/routing/DomainRoutingIsm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
// ============ External Imports ============
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

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

/**
* @title DomainRoutingIsm
*/
contract DomainRoutingIsm is AbstractRoutingIsm, Ownable {
// ============ Public Storage ============
mapping(uint32 => IInterchainSecurityModule) public modules;

// ============ Events ============

/**
* @notice Emitted when a module is set for a domain
* @param domain The origin domain.
* @param module The ISM to use.
*/
event ModuleSet(uint32 indexed domain, IInterchainSecurityModule module);

// ============ Constructor ============

// solhint-disable-next-line no-empty-blocks
constructor() Ownable() {}

// ============ External Functions ============
function set(uint32 _domain, IInterchainSecurityModule _module)
external
onlyOwner
{
modules[_domain] = _module;
emit ModuleSet(_domain, _module);
}

// ============ Public Functions ============

function route(bytes calldata _message)
public
view
virtual
override
returns (IInterchainSecurityModule)
{
return modules[Message.origin(_message)];
}
}
37 changes: 37 additions & 0 deletions solidity/contracts/isms/routing/InterchainAccountIsm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {AbstractRoutingIsm} from "./AbstractRoutingIsm.sol";
import {IMailbox} from "../../../interfaces/IMailbox.sol";
import {IInterchainSecurityModule} from "../../../interfaces/IInterchainSecurityModule.sol";
import {Message} from "../../libs/Message.sol";
import {InterchainAccountMessage} from "../../libs/middleware/InterchainAccountMessage.sol";

/**
* @title InterchainAccountIsm
*/
contract InterchainAccountIsm is AbstractRoutingIsm {
IMailbox private immutable mailbox;

// ============ Constructor ============
constructor(address _mailbox) {
mailbox = IMailbox(_mailbox);
}

// ============ Public Functions ============

function route(bytes calldata _message)
public
view
virtual
override
returns (IInterchainSecurityModule)
{
address _ism = InterchainAccountMessage.ism(Message.body(_message));
if (_ism == address(0)) {
return mailbox.defaultIsm();
} else {
return IInterchainSecurityModule(_ism);
}
asaj marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,13 @@ library InterchainAccountMessage {
{
return abi.decode(_message, (bytes32, bytes32, CallLib.Call[]));
}

/**
* @notice Parses and returns the ISM address from the provided message
* @param _message The interchain account message
* @return The ISM encoded in the message
*/
function ism(bytes calldata _message) internal pure returns (address) {
return address(bytes20(_message[44:64]));
}
}
3 changes: 3 additions & 0 deletions solidity/contracts/mock/MockHyperlaneEnvironment.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contract MockHyperlaneEnvironment {
isms[originDomain] = new TestIsm();
isms[destinationDomain] = new TestIsm();

originMailbox.setDefaultIsm(isms[originDomain]);
destinationMailbox.setDefaultIsm(isms[destinationDomain]);

mailboxes[_originDomain] = originMailbox;
mailboxes[_destinationDomain] = destinationMailbox;

Expand Down
68 changes: 59 additions & 9 deletions solidity/contracts/mock/MockMailbox.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Versioned} from "../upgrade/Versioned.sol";
import {TypeCasts} from "../libs/TypeCasts.sol";
import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol";
import {IInterchainSecurityModule, ISpecifiesInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";

contract MockMailbox {
contract MockMailbox is Versioned {
using TypeCasts for address;
using TypeCasts for bytes32;
// Domain of chain on which the contract is deployed

// ============ Constants ============
uint32 public immutable localDomain;
uint32 public immutable VERSION = 0;
uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;

uint256 public outboundNonce = 0;
uint256 public inboundUnprocessedNonce = 0;
uint256 public inboundProcessedNonce = 0;
uint32 public outboundNonce = 0;
uint32 public inboundUnprocessedNonce = 0;
uint32 public inboundProcessedNonce = 0;
IInterchainSecurityModule public defaultIsm;
mapping(uint32 => MockMailbox) public remoteMailboxes;
mapping(uint256 => Message) public inboundMessages;
mapping(uint256 => MockMessage) public inboundMessages;

struct Message {
struct MockMessage {
uint32 nonce;
asaj marked this conversation as resolved.
Show resolved Hide resolved
uint32 origin;
address sender;
address recipient;
Expand All @@ -31,6 +34,10 @@ contract MockMailbox {
localDomain = _domain;
}

function setDefaultIsm(IInterchainSecurityModule _module) external {
defaultIsm = _module;
}

function addRemoteMailbox(uint32 _domain, MockMailbox _mailbox) external {
remoteMailboxes[_domain] = _mailbox;
}
Expand All @@ -47,6 +54,7 @@ contract MockMailbox {
"Missing remote mailbox"
);
_destinationMailbox.addInboundMessage(
outboundNonce,
localDomain,
msg.sender,
_recipientAddress.bytes32ToAddress(),
Expand All @@ -57,12 +65,14 @@ contract MockMailbox {
}

function addInboundMessage(
uint32 _nonce,
uint32 _origin,
address _sender,
address _recipient,
bytes calldata _body
) external {
inboundMessages[inboundUnprocessedNonce] = Message(
inboundMessages[inboundUnprocessedNonce] = MockMessage(
_nonce,
_origin,
_sender,
_recipient,
Expand All @@ -72,12 +82,52 @@ contract MockMailbox {
}

function processNextInboundMessage() public {
Message memory _message = inboundMessages[inboundProcessedNonce];
MockMessage memory _message = inboundMessages[inboundProcessedNonce];
address _recipient = _message.recipient;
IInterchainSecurityModule _ism = _recipientIsm(_recipient);
if (address(_ism) != address(0)) {
// Do not pass any metadata
asaj marked this conversation as resolved.
Show resolved Hide resolved
require(_ism.verify("", _encode(_message)), "ISM verify failed");
}

IMessageRecipient(_message.recipient).handle(
_message.origin,
_message.sender.addressToBytes32(),
_message.body
);
inboundProcessedNonce++;
}

function _encode(MockMessage memory _message)
private
view
returns (bytes memory)
{
return
abi.encodePacked(
VERSION,
_message.nonce,
_message.origin,
TypeCasts.addressToBytes32(_message.sender),
localDomain,
TypeCasts.addressToBytes32(_message.recipient),
_message.body
);
}

function _recipientIsm(address _recipient)
private
view
returns (IInterchainSecurityModule)
{
try
ISpecifiesInterchainSecurityModule(_recipient)
.interchainSecurityModule()
returns (IInterchainSecurityModule _val) {
if (address(_val) != address(0)) {
return _val;
}
} catch {}
return defaultIsm;
}
}
4 changes: 4 additions & 0 deletions solidity/contracts/test/TestIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ contract TestIsm is IInterchainSecurityModule {
uint8 public constant moduleType = 0;
bool public accept;

constructor() {
accept = true;
}

function setAccept(bool _val) external {
accept = _val;
}
Expand Down
8 changes: 8 additions & 0 deletions solidity/interfaces/IInterchainSecurityModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
pragma solidity >=0.6.11;

interface IInterchainSecurityModule {
enum Types {
UNUSED_0,
ROUTING,
AGGREGATION,
LEGACY_MULTISIG,
MULTISIG
}

/**
* @notice Returns an enum that represents the type of security model
* encoded by this ISM.
Expand Down
2 changes: 2 additions & 0 deletions solidity/interfaces/IMailbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pragma solidity >=0.8.0;
import {IInterchainSecurityModule} from "./IInterchainSecurityModule.sol";

interface IMailbox {
function defaultIsm() external view returns (IInterchainSecurityModule);

function localDomain() external view returns (uint32);

function dispatch(
Expand Down
17 changes: 17 additions & 0 deletions solidity/interfaces/IRoutingIsm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.0;

import {IInterchainSecurityModule} from "./IInterchainSecurityModule.sol";

interface IRoutingIsm is IInterchainSecurityModule {
/**
* @notice Returns the ISM responsible for verifying _message
* @dev Can change based on the content of _message
* @param _message Hyperlane formatted interchain message
* @return module The ISM to use to verify _message
*/
function route(bytes calldata _message)
external
view
returns (IInterchainSecurityModule);
}
Loading