Skip to content

Commit

Permalink
Fix forge tests post V3 (#2661)
Browse files Browse the repository at this point in the history
- fixes GasRouter expectRevert message
- added TestMerkleRootHook for proof() and fixes MerkleRootMultisig test
- fixes ERC5164 tests post v3 changes

- added contract name to mailbox and abstractHook error messages
- removed unnecessary tests for "message too large"
- downgrade slither in actions to 0.3.0 because of their recent "missing
inheritance" bug on main

- V3

Yes

Unit tests
  • Loading branch information
aroralanuk authored and yorhodes committed Sep 13, 2023
1 parent 760dce6 commit 6a32287
Show file tree
Hide file tree
Showing 19 changed files with 144 additions and 401 deletions.
22 changes: 15 additions & 7 deletions solidity/contracts/Mailbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,17 @@ contract Mailbox is IMailbox, Versioned, Ownable {
* @param _module The new default ISM. Must be a contract.
*/
function setDefaultIsm(address _module) external onlyOwner {
require(Address.isContract(_module), "!contract");
require(Address.isContract(_module), "Mailbox: !contract");
defaultIsm = IInterchainSecurityModule(_module);
emit DefaultIsmSet(_module);
}

/**
* @notice Sets the default post dispatch hook for the Mailbox.
* @param _hook The new default post dispatch hook. Must be a contract.
*/
function setDefaultHook(address _hook) external onlyOwner {
require(Address.isContract(_hook), "!contract");
require(Address.isContract(_hook), "Mailbox: !contract");
defaultHook = IPostDispatchHook(_hook);
emit DefaultHookSet(_hook);
}
Expand Down Expand Up @@ -158,8 +162,9 @@ contract Mailbox is IMailbox, Versioned, Ownable {

nonce += 1;
latestDispatchedId = id;
emit DispatchId(id);

emit Dispatch(message);
emit DispatchId(id);

/// INTERACTIONS ///

Expand All @@ -186,15 +191,15 @@ contract Mailbox is IMailbox, Versioned, Ownable {
/// CHECKS ///

// Check that the message was intended for this mailbox.
require(_message.version() == VERSION, "bad version");
require(_message.version() == VERSION, "Mailbox: bad version");
require(
_message.destination() == localDomain,
"unexpected destination"
"Mailbox: unexpected destination"
);

// Check that the message hasn't already been delivered.
bytes32 _id = _message.id();
require(delivered(_id) == false, "already delivered");
require(delivered(_id) == false, "Mailbox: already delivered");

// Get the recipient's ISM.
address recipient = _message.recipientAddress();
Expand All @@ -214,7 +219,10 @@ contract Mailbox is IMailbox, Versioned, Ownable {
/// INTERACTIONS ///

// Verify the message via the ISM.
require(ism.verify(_metadata, _message), "verification failed");
require(
ism.verify(_metadata, _message),
"Mailbox: verification failed"
);

// Deliver the message to the recipient.
IMessageRecipient(recipient).handle{value: msg.value}(
Expand Down
7 changes: 5 additions & 2 deletions solidity/contracts/hooks/AbstractMessageIdAuthHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ abstract contract AbstractMessageIdAuthHook is
uint32 _destinationDomain,
address _ism
) MailboxClient(mailbox) {
require(_ism != address(0), "invalid ISM");
require(_destinationDomain != 0, "invalid destination domain");
require(_ism != address(0), "AbstractMessageIdAuthHook: invalid ISM");
require(
_destinationDomain != 0,
"AbstractMessageIdAuthHook: invalid destination domain"
);
ism = _ism;
destinationDomain = _destinationDomain;
}
Expand Down
1 change: 1 addition & 0 deletions solidity/contracts/hooks/ERC5164Hook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ contract ERC5164Hook is AbstractMessageIdAuthHook {
bytes calldata, /* metadata */
bytes memory payload
) internal override {
require(msg.value == 0, "ERC5164Hook: no value allowed");
dispatcher.dispatchMessage(destinationDomain, ism, payload);
}
}
30 changes: 0 additions & 30 deletions solidity/contracts/interfaces/IMessageDispatcher.sol

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ abstract contract AbstractMessageIdAuthorizedIsm is
* @dev Only callable by the L2 messenger.
* @param messageId Hyperlane Id of the message.
*/
function verifyMessageId(bytes32 messageId) external payable {
function verifyMessageId(bytes32 messageId) external payable virtual {
require(
_isAuthorized(),
"AbstractMessageIdAuthorizedIsm: sender is not the hook"
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion solidity/contracts/mock/MockERC5164.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT or Apache-2.0
pragma solidity ^0.8.13;

import {IMessageDispatcher} from "../interfaces/IMessageDispatcher.sol";
import {IMessageDispatcher} from "../interfaces/hooks/IMessageDispatcher.sol";

contract MockMessageDispatcher is IMessageDispatcher {
function dispatchMessage(
Expand Down
20 changes: 3 additions & 17 deletions solidity/contracts/test/TestMailbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,9 @@ import {IMessageRecipient} from "../interfaces/IMessageRecipient.sol";
contract TestMailbox is Mailbox {
using TypeCasts for bytes32;

constructor(uint32 _localDomain) Mailbox(_localDomain, msg.sender) {} // solhint-disable-line no-empty-blocks

// function proof() external view returns (bytes32[32] memory) {
// bytes32[32] memory _zeroes = MerkleLib.zeroHashes();
// uint256 _index = tree.count - 1;
// bytes32[32] memory _proof;

// for (uint256 i = 0; i < 32; i++) {
// uint256 _ithBit = (_index >> i) & 0x01;
// if (_ithBit == 1) {
// _proof[i] = tree.branch[i];
// } else {
// _proof[i] = _zeroes[i];
// }
// }
// return _proof;
// }
constructor(uint32 _localDomain, address _owner)
Mailbox(_localDomain, _owner)
{} // solhint-disable-line no-empty-blocks

function testHandle(
uint32 _origin,
Expand Down
25 changes: 25 additions & 0 deletions solidity/contracts/test/TestMerkleTreeHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

import {MerkleLib} from "../libs/Merkle.sol";
import {MerkleTreeHook} from "../hooks/MerkleTreeHook.sol";

contract TestMerkleTreeHook is MerkleTreeHook {
constructor(address _mailbox) MerkleTreeHook(_mailbox) {}

function proof() external view returns (bytes32[32] memory) {
bytes32[32] memory _zeroes = MerkleLib.zeroHashes();
uint256 _index = _tree.count - 1;
bytes32[32] memory _proof;

for (uint256 i = 0; i < 32; i++) {
uint256 _ithBit = (_index >> i) & 0x01;
if (_ithBit == 1) {
_proof[i] = _tree.branch[i];
} else {
_proof[i] = _zeroes[i];
}
}
return _proof;
}
}
3 changes: 2 additions & 1 deletion solidity/slither.config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"filter_paths": "lib|node_modules|test|Mock*|Test*",
"compile_force_framework": "foundry",
"exclude_informational": true
"exclude_informational": true,
"no_fail": true
}
4 changes: 3 additions & 1 deletion solidity/test/GasRouter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ contract GasRouterTest is Test {

vm.deal(address(this), requiredPayment + 1);
passRefund = false;
vm.expectRevert("Interchain gas payment refund failed");
vm.expectRevert(
"Address: unable to send value, recipient may have reverted"
);
originRouter.dispatchWithGas{value: requiredPayment + 1}(
remoteDomain,
""
Expand Down
4 changes: 2 additions & 2 deletions solidity/test/hyperlaneConnectionClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ describe('HyperlaneConnectionClient', async () => {
beforeEach(async () => {
const mailboxFactory = new Mailbox__factory(signer);
const domain = 1000;
mailbox = await mailboxFactory.deploy(domain);
newMailbox = await mailboxFactory.deploy(domain);
mailbox = await mailboxFactory.deploy(domain, signer.address);
newMailbox = await mailboxFactory.deploy(domain, signer.address);

const connectionClientFactory = new TestHyperlaneConnectionClient__factory(
signer,
Expand Down
65 changes: 42 additions & 23 deletions solidity/test/isms/ERC5164ISM.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,31 @@ pragma solidity ^0.8.13;

import {Test} from "forge-std/Test.sol";

import {LibBit} from "../../contracts/libs/LibBit.sol";
import {Message} from "../../contracts/libs/Message.sol";
import {MessageUtils} from "./IsmTestUtils.sol";
import {TypeCasts} from "../../contracts/libs/TypeCasts.sol";

import {IMessageDispatcher} from "../../contracts/interfaces/IMessageDispatcher.sol";
import {IMessageDispatcher} from "../../contracts/interfaces/hooks/IMessageDispatcher.sol";
import {ERC5164Hook} from "../../contracts/hooks/ERC5164Hook.sol";
import {AbstractMessageIdAuthorizedIsm} from "../../contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol";
import {ERC5164ISM} from "../../contracts/isms/hook/ERC5164ISM.sol";
import {TestMailbox} from "../../contracts/test/TestMailbox.sol";
import {TestRecipient} from "../../contracts/test/TestRecipient.sol";
import {MockMessageDispatcher, MockMessageExecutor} from "../../contracts/mock/MockERC5164.sol";

contract ERC5164ISMTest is Test {
using LibBit for uint256;
using TypeCasts for address;
using Message for bytes;
using MessageUtils for bytes;

IMessageDispatcher internal dispatcher;
MockMessageExecutor internal executor;

ERC5164Hook internal hook;
ERC5164ISM internal ism;
TestMailbox internal srcMailbox;
TestRecipient internal testRecipient;

uint32 internal constant TEST1_DOMAIN = 1;
Expand Down Expand Up @@ -55,14 +61,15 @@ contract ERC5164ISMTest is Test {
}

function deployContracts() public {
srcMailbox = new TestMailbox(TEST1_DOMAIN, address(this));
ism = new ERC5164ISM(address(executor));
address mailbox = address(0); // TODO: check?
hook = new ERC5164Hook(
mailbox,
address(srcMailbox),
TEST2_DOMAIN,
address(ism),
address(dispatcher)
);
ism.setAuthorizedHook(address(hook));
}

///////////////////////////////////////////////////////////////////
Expand All @@ -81,15 +88,17 @@ contract ERC5164ISMTest is Test {
address(dispatcher)
);

vm.expectRevert("ERC5164Hook: invalid destination domain");
vm.expectRevert(
"AbstractMessageIdAuthHook: invalid destination domain"
);
hook = new ERC5164Hook(
address(dispatcher),
0,
address(ism),
address(dispatcher)
);

vm.expectRevert("ERC5164Hook: invalid ISM");
vm.expectRevert("AbstractMessageIdAuthHook: invalid ISM");
hook = new ERC5164Hook(
address(dispatcher),
TEST2_DOMAIN,
Expand All @@ -113,6 +122,7 @@ contract ERC5164ISMTest is Test {
AbstractMessageIdAuthorizedIsm.verifyMessageId,
(messageId)
);
srcMailbox.updateLatestDispatchedId(messageId);

// note: not checking for messageId since this is implementation dependent on each vendor
vm.expectEmit(false, true, true, true, address(dispatcher));
Expand All @@ -130,12 +140,32 @@ contract ERC5164ISMTest is Test {
function test_postDispatch_RevertWhen_ChainIDNotSupported() public {
deployContracts();

encodedMessage = _encodeTestMessage(0, address(this));
encodedMessage = MessageUtils.formatMessage(
VERSION,
0,
TEST1_DOMAIN,
TypeCasts.addressToBytes32(address(this)),
3, // unsupported chain id
TypeCasts.addressToBytes32(address(testRecipient)),
testMessage
);
srcMailbox.updateLatestDispatchedId(Message.id(encodedMessage));

vm.expectRevert("ERC5164Hook: invalid destination domain");
vm.expectRevert(
"AbstractMessageIdAuthHook: invalid destination domain"
);
hook.postDispatch(bytes(""), encodedMessage);
}

function test_postDispatch_RevertWhen_msgValueNotAllowed() public payable {
deployContracts();

srcMailbox.updateLatestDispatchedId(messageId);

vm.expectRevert("ERC5164Hook: no value allowed");
hook.postDispatch{value: 1}(bytes(""), encodedMessage);
}

/* ============ ISM.verifyMessageId ============ */

function test_verifyMessageId() public {
Expand All @@ -144,7 +174,7 @@ contract ERC5164ISMTest is Test {
vm.startPrank(address(executor));

ism.verifyMessageId(messageId);
assertTrue(ism.verifiedMessages(messageId));
assertTrue(ism.verifiedMessages(messageId).isBitSet(255));

vm.stopPrank();
}
Expand All @@ -155,7 +185,9 @@ contract ERC5164ISMTest is Test {
vm.startPrank(alice);

// needs to be called by the authorized hook contract on Ethereum
vm.expectRevert("ERC5164ISM: sender is not the executor");
vm.expectRevert(
"AbstractMessageIdAuthorizedIsm: sender is not the hook"
);
ism.verifyMessageId(messageId);

vm.stopPrank();
Expand Down Expand Up @@ -190,19 +222,6 @@ contract ERC5164ISMTest is Test {
vm.stopPrank();
}

function test_verify_RevertWhen_InvalidSender() public {
deployContracts();

vm.startPrank(address(executor));

ism.verifyMessageId(messageId);

bool verified = ism.verify(new bytes(0), encodedMessage);
assertFalse(verified);

vm.stopPrank();
}

/* ============ helper functions ============ */

function _encodeTestMessage(uint32 _msgCount, address _receipient)
Expand All @@ -211,7 +230,7 @@ contract ERC5164ISMTest is Test {
returns (bytes memory)
{
return
abi.encodePacked(
MessageUtils.formatMessage(
VERSION,
_msgCount,
TEST1_DOMAIN,
Expand Down
Loading

0 comments on commit 6a32287

Please sign in to comment.