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.
169 lines
6.6 KiB
169 lines
6.6 KiB
1 year ago
|
// 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.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);
|
||
|
}
|
||
|
}
|