Unit Testing
Recommended Telepathy testing patterns.
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.addTelepathyReceiver(uint32 _chainId, MockTelepathy _receiver)
: This method tells a source chain router whichMockTelepathy
instance to route messages to that are sent to_chainId
.executeNextMessage()
: Broadcast next message in queue to receiverMockTelepathy
instance
MockTelepathy
can be used with forge
testing. Examples can be found below: