packages/contracts-core/test/suite/client/BaseClient.t.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {
BaseClientOptimisticPeriod,
CallerNotDestination,
IncorrectNonce,
IncorrectSender,
IncorrectRecipient,
ZeroProofMaturity
} from "../../../contracts/libs/Errors.sol";
import {MessageRecipient} from "../../../contracts/client/MessageRecipient.sol";
import {BaseClientHarness} from "../../harnesses/client/BaseClientHarness.t.sol";
import {SynapseTest} from "../../utils/SynapseTest.t.sol";
import {InterfaceOrigin} from "../../mocks/OriginMock.t.sol";
import {RawBaseMessage, RawHeader, RawRequest} from "../../utils/libs/SynapseStructs.t.sol";
// solhint-disable func-name-mixedcase
// solhint-disable no-empty-blocks
contract BaseClientTest is SynapseTest {
BaseClientHarness public client;
// Deploy mocks instead of the production contracts
constructor() SynapseTest(0) {}
function setUp() public override {
super.setUp();
client = new BaseClientHarness(origin, destination);
}
function test_sendBaseMessage(
address user,
uint32 destination_,
uint256 tipsValue,
RawRequest memory rr,
uint32 nonce,
bytes32 msgHash,
bytes memory content
) public {
vm.assume(destination_ != 0 && destination_ != DOMAIN_LOCAL);
vm.label(user, "User");
// Set some sensible limit for fuzzed tips values
tipsValue = tipsValue % (2 ** 32);
uint192 encodedRequest = rr.encodeRequest();
vm.deal(user, tipsValue);
// Get expected values for sending a message
bytes32 recipient = client.trustedSender(destination_);
uint32 optimisticPeriod = client.optimisticPeriod();
bytes memory expectedCall = abi.encodeWithSelector(
InterfaceOrigin.sendBaseMessage.selector, destination_, recipient, optimisticPeriod, encodedRequest, content
);
MessageRecipient.MessageRequest memory request =
MessageRecipient.MessageRequest({gasDrop: rr.gasDrop, gasLimit: rr.gasLimit, version: rr.version});
// Mock returned values for sendBaseMessage call
vm.mockCall(
origin, abi.encodeWithSelector(InterfaceOrigin.sendBaseMessage.selector), abi.encode(nonce, msgHash)
);
vm.expectCall(origin, tipsValue, expectedCall);
vm.prank(user);
(uint32 nonce_, bytes32 msgHash_) =
client.sendBaseMessage{value: tipsValue}(destination_, tipsValue, request, content);
assertEq(nonce_, nonce);
assertEq(msgHash_, msgHash);
}
function test_sendBaseMessage_revert_recipientNotSet(
address user,
uint256 tipsValue,
MessageRecipient.MessageRequest memory request
) public {
// There is no trustedSender for this domain => will revert in BaseClient
uint32 destination_ = 0;
vm.label(user, "User");
// Set some sensible limit for fuzzed tips values
tipsValue = tipsValue % (2 ** 32);
vm.deal(user, tipsValue);
vm.expectRevert(IncorrectRecipient.selector);
vm.prank(user);
client.sendBaseMessage{value: tipsValue}(destination_, tipsValue, request, "");
}
function test_sendBaseMessage_tipsValueNotMsgValue() public {
address user = makeAddr("User");
uint32 destination_ = 1;
uint256 tipsValue = 1337;
uint256 msgValue = 6969;
// Use empty request for this test
MessageRecipient.MessageRequest memory request;
vm.deal(user, msgValue);
bytes memory expectedCall = abi.encodeWithSelector(InterfaceOrigin.sendBaseMessage.selector);
// Should call origin with provided tipsValue as msg.value
vm.expectCall(origin, tipsValue, expectedCall);
vm.prank(user);
client.sendBaseMessage{value: msgValue}(destination_, tipsValue, request, "");
}
function test_getMinimumTipsValue(
uint32 destination_,
RawRequest memory rr,
uint256 contentLength,
uint256 expectedResult
) public {
uint192 encodedRequest = rr.encodeRequest();
MessageRecipient.MessageRequest memory request =
MessageRecipient.MessageRequest({gasDrop: rr.gasDrop, gasLimit: rr.gasLimit, version: rr.version});
// (destination, paddedRequest, contentLength)
bytes memory expectedCall = abi.encodeWithSelector(
InterfaceOrigin.getMinimumTipsValue.selector, destination_, encodedRequest, contentLength
);
vm.mockCall(origin, expectedCall, abi.encode(expectedResult));
vm.expectCall(origin, expectedCall);
uint256 result = client.getMinimumTipsValue(destination_, request, contentLength);
assertEq(result, expectedResult);
}
function test_receiveBaseMessage(
RawHeader memory rh,
uint256 rootSubmittedAt,
uint256 secondsPassed,
uint32 version,
bytes memory content
) public {
vm.assume(rh.origin != 0 && rh.origin != DOMAIN_LOCAL && rh.nonce != 0);
// Get expected values for receiving a message
uint32 optimisticPeriod = client.optimisticPeriod();
bytes32 sender = client.trustedSender(rh.origin);
// Set some sensible restrictions for timestamps
rootSubmittedAt = bound(rootSubmittedAt, 1, 1e10);
secondsPassed = bound(secondsPassed, optimisticPeriod, 2 * optimisticPeriod);
vm.warp(rootSubmittedAt + secondsPassed);
vm.expectEmit();
// msg.value should be zero
emit BaseMessageReceived(0, rh.origin, rh.nonce, version, content);
vm.prank(destination);
client.receiveBaseMessage(rh.origin, rh.nonce, sender, secondsPassed, version, content);
}
function test_receiveBaseMessage_revert_notDestination(RawHeader memory rh, uint256 rootSubmittedAt, address caller)
public
{
vm.assume(rh.origin != 0 && rh.origin != DOMAIN_LOCAL && rh.nonce != 0);
vm.assume(caller != destination);
// Get expected values for receiving a message
uint32 optimisticPeriod = client.optimisticPeriod();
bytes32 sender = client.trustedSender(rh.origin);
// Set some sensible restrictions for timestamps
rootSubmittedAt = bound(rootSubmittedAt, 1, 1e10);
vm.warp(rootSubmittedAt + optimisticPeriod);
vm.expectRevert(CallerNotDestination.selector);
vm.prank(caller);
client.receiveBaseMessage(rh.origin, rh.nonce, sender, optimisticPeriod, 0, "");
}
function test_receiveBaseMessage_revert_notTrustedSender(
RawHeader memory rh,
uint256 rootSubmittedAt,
bytes32 sender
) public {
vm.assume(rh.origin != 0 && rh.origin != DOMAIN_LOCAL && rh.nonce != 0);
vm.assume(sender != client.trustedSender(rh.origin));
// Get expected values for receiving a message
uint32 optimisticPeriod = client.optimisticPeriod();
// Set some sensible restrictions for timestamps
rootSubmittedAt = bound(rootSubmittedAt, 1, 1e10);
vm.warp(rootSubmittedAt + optimisticPeriod);
vm.expectRevert(IncorrectSender.selector);
vm.prank(destination);
client.receiveBaseMessage(rh.origin, rh.nonce, sender, optimisticPeriod, 0, "");
}
function test_receiveBaseMessage_revert_zeroNonce(RawHeader memory rh, uint256 rootSubmittedAt) public {
vm.assume(rh.origin != 0 && rh.origin != DOMAIN_LOCAL);
rh.nonce = 0;
// Get expected values for receiving a message
uint32 optimisticPeriod = client.optimisticPeriod();
bytes32 sender = client.trustedSender(rh.origin);
// Set some sensible restrictions for timestamps
rootSubmittedAt = bound(rootSubmittedAt, 1, 1e10);
vm.warp(rootSubmittedAt + optimisticPeriod);
vm.expectRevert(IncorrectNonce.selector);
vm.prank(destination);
client.receiveBaseMessage(rh.origin, rh.nonce, sender, optimisticPeriod, 0, "");
}
function test_receiveBaseMessage_revert_optimisticPeriodNotOver(
RawHeader memory rh,
uint256 rootSubmittedAt,
uint256 secondsPassed
) public {
vm.assume(rh.origin != 0 && rh.origin != DOMAIN_LOCAL && rh.nonce != 0);
// Get expected values for receiving a message
uint32 optimisticPeriod = client.optimisticPeriod();
bytes32 sender = client.trustedSender(rh.origin);
// Set some sensible restrictions for timestamps
rootSubmittedAt = bound(rootSubmittedAt, 1, 1e10);
secondsPassed = bound(secondsPassed, 1, optimisticPeriod - 1);
vm.warp(rootSubmittedAt + secondsPassed);
vm.expectRevert(BaseClientOptimisticPeriod.selector);
vm.prank(destination);
client.receiveBaseMessage(rh.origin, rh.nonce, sender, secondsPassed, 0, "");
}
function test_receiveBaseMessage_revert_optimisticPeriodMinus1Second() public {
uint32 timePassed = client.optimisticPeriod() - 1;
bytes32 sender = client.trustedSender(DOMAIN_REMOTE);
skip(timePassed);
vm.expectRevert(BaseClientOptimisticPeriod.selector);
vm.prank(destination);
client.receiveBaseMessage({
origin_: DOMAIN_REMOTE,
nonce: 1,
sender: sender,
proofMaturity: timePassed,
version: 0,
content: ""
});
}
function test_receiveBaseMessage_revert_zeroProofMaturity(RawHeader memory rh, uint256 rootSubmittedAt) public {
vm.assume(rh.origin != 0 && rh.origin != DOMAIN_LOCAL && rh.nonce != 0);
uint32 optimisticPeriod = 0;
// Get expected values for receiving a message
bytes32 sender = client.trustedSender(rh.origin);
// Set some sensible restrictions for timestamps
rootSubmittedAt = bound(rootSubmittedAt, 1, 1e10);
vm.warp(rootSubmittedAt);
vm.expectRevert(ZeroProofMaturity.selector);
vm.prank(destination);
client.receiveBaseMessage(rh.origin, rh.nonce, sender, optimisticPeriod, 0, "");
}
}