The home for Hyperlane core contracts, sdk packages, and other infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hyperlane-monorepo/solidity/test/Router.t.sol

171 lines
6.6 KiB

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import {TestRouter} from "../contracts/test/TestRouter.sol";
import {TestMailbox} from "../contracts/test/TestMailbox.sol";
import {TestInterchainGasPaymaster} from "../contracts/test/TestInterchainGasPaymaster.sol";
import {TestIsm} from "../contracts/test/TestIsm.sol";
import {TestMerkleTreeHook} from "../contracts/test/TestMerkleTreeHook.sol";
import {TypeCasts} from "../contracts/libs/TypeCasts.sol";
contract RouterTest is Test {
TestRouter router;
TestMailbox mailbox;
TestInterchainGasPaymaster igp;
TestMerkleTreeHook requiredHook;
TestIsm ism;
uint32 localDomain = 1000;
uint32 origin = 1;
uint32 destination = 2;
uint32 destinationWithoutRouter = 3;
bytes body = "0xdeadbeef";
event Dispatch(
address indexed sender,
uint32 indexed destination,
bytes32 indexed recipient,
bytes message
);
function setUp() public {
mailbox = new TestMailbox(localDomain);
igp = new TestInterchainGasPaymaster();
router = new TestRouter(address(mailbox));
ism = new TestIsm();
requiredHook = new TestMerkleTreeHook(address(mailbox));
mailbox.initialize(
address(this),
address(ism),
address(igp),
address(requiredHook)
);
router.initialize(address(igp), address(ism));
}
function testInitialize() public {
assertEq(address(router.hook()), address(igp));
assertEq(address(router.interchainSecurityModule()), address(ism));
assertEq(address(router.owner()), address(this));
assertEq(address(router.mailbox()), address(mailbox));
vm.expectRevert(
bytes("Initializable: contract is already initialized")
);
router.initialize(address(igp), address(ism));
}
function testEnrolledMailboxAndRouter(bytes32 sender) public {
bytes32 recipient = TypeCasts.addressToBytes32(address(router));
router.enrollRemoteRouter(origin, sender);
mailbox.testHandle(origin, sender, recipient, body);
}
function testUnenrolledMailbox(bytes32 sender) public {
vm.expectRevert(bytes("MailboxClient: sender not mailbox"));
router.handle(origin, sender, body);
}
function testUnenrolledRouter(bytes32 sender) public {
bytes32 recipient = TypeCasts.addressToBytes32(address(router));
vm.expectRevert(bytes("No router enrolled for domain: 1"));
mailbox.testHandle(origin, sender, recipient, body);
}
function testOwnerEnrollRouter(bytes32 remoteRouter) public {
vm.assume(remoteRouter != bytes32(0));
assertEq(router.isRemoteRouter(origin, remoteRouter), false);
vm.expectRevert(bytes("No router enrolled for domain: 1"));
router.mustHaveRemoteRouter(origin);
router.enrollRemoteRouter(origin, remoteRouter);
assertEq(router.isRemoteRouter(origin, remoteRouter), true);
assertEq(router.mustHaveRemoteRouter(origin), remoteRouter);
}
function testOwnerUnenrollRouter(bytes32 remoteRouter) public {
vm.assume(remoteRouter != bytes32(0));
assertEq(router.isRemoteRouter(origin, remoteRouter), false);
vm.expectRevert(bytes("No router enrolled for domain: 1"));
router.unenrollRemoteRouter(origin);
router.enrollRemoteRouter(origin, remoteRouter);
router.unenrollRemoteRouter(origin);
assertEq(router.isRemoteRouter(origin, remoteRouter), false);
}
function testNotOwnerEnrollRouter(
address notOwner,
bytes32 remoteRouter
) public {
vm.assume(notOwner != router.owner());
vm.prank(notOwner);
vm.expectRevert(bytes("Ownable: caller is not the owner"));
router.enrollRemoteRouter(origin, remoteRouter);
}
function testOwnerBatchEnrollRouter(bytes32 remoteRouter) public {
vm.assume(remoteRouter != bytes32(0));
assertEq(router.isRemoteRouter(origin, remoteRouter), false);
vm.expectRevert(bytes("No router enrolled for domain: 1"));
router.mustHaveRemoteRouter(origin);
uint32[] memory domains = new uint32[](1);
domains[0] = origin;
bytes32[] memory addresses = new bytes32[](1);
addresses[0] = remoteRouter;
router.enrollRemoteRouters(domains, addresses);
assertEq(router.isRemoteRouter(origin, remoteRouter), true);
assertEq(router.mustHaveRemoteRouter(origin), remoteRouter);
}
function testOwnerBatchUnenrollRouter(bytes32 remoteRouter) public {
vm.assume(remoteRouter != bytes32(0));
assertEq(router.isRemoteRouter(origin, remoteRouter), false);
vm.expectRevert(bytes("No router enrolled for domain: 1"));
router.mustHaveRemoteRouter(origin);
uint32[] memory domains = new uint32[](1);
domains[0] = origin;
bytes32[] memory addresses = new bytes32[](1);
addresses[0] = remoteRouter;
router.enrollRemoteRouters(domains, addresses);
router.unenrollRemoteRouters(domains);
assertEq(router.isRemoteRouter(origin, remoteRouter), false);
}
function testReturnDomains(bytes32 remoteRouter) public {
uint32[] memory domains = new uint32[](2);
domains[0] = origin;
domains[1] = destination;
bytes32[] memory addresses = new bytes32[](2);
addresses[0] = remoteRouter;
addresses[1] = remoteRouter;
router.enrollRemoteRouters(domains, addresses);
assertEq(router.domains()[0], domains[0]);
assertEq(router.domains()[1], domains[1]);
}
function testDispatch(bytes32 remoteRouter) public {
vm.assume(remoteRouter != bytes32(0));
router.enrollRemoteRouter(destination, remoteRouter);
uint256 fee = mailbox.quoteDispatch(destination, remoteRouter, body);
vm.expectEmit(true, true, true, true, address(mailbox));
vm.prank(address(router));
bytes memory message = mailbox.buildOutboundMessage(
destination,
remoteRouter,
body
);
emit Dispatch(address(router), destination, remoteRouter, message);
router.dispatch{value: fee}(destination, body);
vm.expectRevert(bytes("No router enrolled for domain: 3"));
router.dispatch(destinationWithoutRouter, body);
}
function testDispatchInsufficientPayment(bytes32 remoteRouter) public {
vm.assume(remoteRouter != bytes32(0));
router.enrollRemoteRouter(destination, remoteRouter);
vm.expectRevert(bytes("IGP: insufficient interchain gas payment"));
router.dispatch(destination, body);
}
}