Unit Testing

Recommended Telepathy testing patterns.

Testing

To test cross-chain contracts, we leverage mocking patterns. MockTelepathy simulates the behavior of TelepathyRouter without the overhead of generating and relaying proofs. An example is below.

pragma solidity 0.8.16;

import "forge-std/console.sol";
import "ds-test/test.sol";
import "forge-std/Vm.sol";
import "forge-std/Test.sol";

import "src/amb/mocks/MockTelepathy.sol";

import "./ExampleCounter.sol";

contract CounterTest is Test {
    uint32 constant SOURCE_CHAIN = 1;
    uint32 constant TARGET_CHAIN = 100;

    MockTelepathy router;
    MockTelepathy receiver;
    SourceCounter source;
    TargetCounter target;

    function setUp() public {
        router = new MockTelepathy(SOURCE_CHAIN);
        receiver = new MockTelepathy(TARGET_CHAIN);
        router.addTelepathyReceiver(TARGET_CHAIN, receiver);

        source = new SourceCounter(address(router), TARGET_CHAIN);
        target = new TargetCounter(address(receiver));
    }

    function test_IncrementOne() public {
        source.increment(1, address(target));
        router.executeNextMessage();
        require(target.counter() == 1);
    }

    function test_IncrementSeveral() public {
        source.increment(2, address(target));
        router.executeNextMessage();
        require(target.counter() == 2);
        source.increment(123456789, address(target));
        router.executeNextMessage();
        require(target.counter() == 123456791);
    }

    function test_IncrementOverflow() public {
        source.increment(
            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, address(target)
        );
        router.executeNextMessage();
        require(
            target.counter() == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
        );
        source.increment(2, address(target));
        router.executeNextMessage();
        require(target.counter() == 1);
    }
}

We specify our router and receiver to be MockTelepathy contracts that simulate the behavior of TelepathyRouter on the source and destination chain, respectively. We then specify our counter contracts on the source and contract chains with source and target.

To test source and target, we use source.increment()... to increment. Then, we must call router.executeNextMessage() to make our MockTelepathy routers relay the call to target. In doing so, we implicitly call target.handleTelepathyImpl(...)! Without calls to router.executeNextMessage(), our messages would be in a queue on the mock source chain, waiting to be relayed to the specified destination chain.

MockTelepathy Methods

These are methods unique to MockTelepathy that don't exist in TelepathyRouter.

  • addTelepathyReceiver(uint32 _chainId, MockTelepathy _receiver): This method tells a source chain router which MockTelepathy instance to route messages to that are sent to _chainId.

  • executeNextMessage(): Broadcast next message in queue to receiver MockTelepathy instance

MockTelepathy can be used with forge testing. Examples can be found below:

Last updated