packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {FastBridgeV2DstBaseTest, IFastBridgeV2} from "./FastBridgeV2.Dst.Base.t.sol";
import {ExcessiveReturnValueRecipient} from "./mocks/ExcessiveReturnValueRecipient.sol";
import {IncorrectReturnValueRecipient} from "./mocks/IncorrectReturnValueRecipient.sol";
import {NoOpContract} from "./mocks/NoOpContract.sol";
import {NoReturnValueRecipient} from "./mocks/NoReturnValueRecipient.sol";
import {NonPayableRecipient} from "./mocks/NonPayableRecipient.sol";
// solhint-disable func-name-mixedcase, ordering
contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest {
event BridgeRelayed(
bytes32 indexed transactionId,
address indexed relayer,
address indexed to,
uint32 originChainId,
address originToken,
address destToken,
uint256 originAmount,
uint256 destAmount,
uint256 chainGasAmount
);
uint256 public constant ZAP_NATIVE = 1_337_420;
address public excessiveReturnValueRecipient;
address public incorrectReturnValueRecipient;
address public noOpRecipient;
address public noReturnValueRecipient;
address public nonPayableRecipient;
function setUp() public virtual override {
super.setUp();
excessiveReturnValueRecipient = address(new ExcessiveReturnValueRecipient());
vm.label(excessiveReturnValueRecipient, "ExcessiveReturnValueRecipient");
incorrectReturnValueRecipient = address(new IncorrectReturnValueRecipient());
vm.label(incorrectReturnValueRecipient, "IncorrectReturnValueRecipient");
noOpRecipient = address(new NoOpContract());
vm.label(noOpRecipient, "NoOpRecipient");
noReturnValueRecipient = address(new NoReturnValueRecipient());
vm.label(noReturnValueRecipient, "NoReturnValueRecipient");
nonPayableRecipient = address(new NonPayableRecipient());
vm.label(nonPayableRecipient, "NonPayableRecipient");
}
function setTokenTestRecipient(address recipient) public {
userB = recipient;
tokenParams.to = recipient;
tokenTx.destRecipient = recipient;
}
function setEthTestRecipient(address recipient) public {
userB = recipient;
ethParams.to = recipient;
ethTx.destRecipient = recipient;
}
function assertEmptyZapData(bytes memory zapData) public pure {
assertEq(zapData.length, 0, "Invalid setup: zapData are not empty");
}
function expectBridgeRelayed(
IFastBridgeV2.BridgeTransactionV2 memory bridgeTx,
bytes32 txId,
address relayer
)
public
virtual
{
uint256 chainGasAmount = bridgeTx.destToken == ETH_ADDRESS ? 0 : bridgeTx.zapNative;
vm.expectEmit(address(fastBridge));
emit BridgeRelayed({
transactionId: txId,
relayer: relayer,
to: bridgeTx.destRecipient,
originChainId: bridgeTx.originChainId,
originToken: bridgeTx.originToken,
destToken: bridgeTx.destToken,
originAmount: bridgeTx.originAmount,
destAmount: bridgeTx.destAmount,
chainGasAmount: chainGasAmount
});
}
function checkRelayedViews(bytes32 txId, address expectedRelayer) public view {
assertTrue(fastBridge.bridgeRelays(txId));
(uint48 blockNumber, uint48 blockTimestamp, address relayer) = fastBridge.bridgeRelayDetails(txId);
assertEq(blockNumber, block.number);
assertEq(blockTimestamp, block.timestamp);
assertEq(relayer, expectedRelayer);
}
function checkTokenBalances(address recipient, address relayCaller) public view {
assertEq(dstToken.balanceOf(recipient), tokenParams.destAmount);
assertEq(dstToken.balanceOf(relayCaller), LEFTOVER_BALANCE);
assertEq(dstToken.balanceOf(address(fastBridge)), 0);
}
function checkEthBalances(address recipient, address relayCaller) public view {
assertEq(recipient.balance, ethParams.destAmount);
assertEq(relayCaller.balance, LEFTOVER_BALANCE);
assertEq(address(fastBridge).balance, 0);
}
/// @notice RelayerA completes the ERC20 bridge request
function test_relay_token() public {
bytes32 txId = getTxId(tokenTx);
expectBridgeRelayed(tokenTx, txId, relayerA);
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
checkRelayedViews({txId: txId, expectedRelayer: relayerA});
checkTokenBalances({recipient: userB, relayCaller: relayerA});
}
/// @notice RelayerB completes the ERC20 bridge request, using relayerA's address
function test_relay_token_withRelayerAddress() public {
bytes32 txId = getTxId(tokenTx);
expectBridgeRelayed(tokenTx, txId, relayerA);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx});
checkRelayedViews({txId: txId, expectedRelayer: relayerA});
checkTokenBalances({recipient: userB, relayCaller: relayerB});
}
/// @notice RelayerB completes the ETH bridge request
function test_relay_eth() public {
bytes32 txId = getTxId(ethTx);
expectBridgeRelayed(ethTx, txId, relayerB);
relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
checkRelayedViews({txId: txId, expectedRelayer: relayerB});
checkEthBalances({recipient: userB, relayCaller: relayerB});
}
/// @notice RelayerA completes the ETH bridge request, using relayerB's address
function test_relay_eth_withRelayerAddress() public {
bytes32 txId = getTxId(ethTx);
expectBridgeRelayed(ethTx, txId, relayerB);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
checkRelayedViews({txId: txId, expectedRelayer: relayerB});
checkEthBalances({recipient: userB, relayCaller: relayerA});
}
/// @notice RelayerA completes the ETH bridge request, using relayerB's address
function test_relay_eth_withRelayerAddress_checkBlockData() public {
vm.roll(987_654_321);
vm.warp(123_456_789);
bytes32 txId = getTxId(ethTx);
expectBridgeRelayed(ethTx, txId, relayerB);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
assertTrue(fastBridge.bridgeRelays(txId));
(uint48 recordedBlockNumber, uint48 recordedBlockTimestamp, address recordedRelayer) =
fastBridge.bridgeRelayDetails(txId);
assertEq(recordedBlockNumber, 987_654_321);
assertEq(recordedBlockTimestamp, 123_456_789);
assertEq(recordedRelayer, relayerB);
checkEthBalances({recipient: userB, relayCaller: relayerA});
}
// ══════════════════════════════════════════ RELAYS WITH CALL VALUE ═══════════════════════════════════════════════
function test_relay_token_withZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
bytes32 txId = getTxId(tokenTx);
expectBridgeRelayed(tokenTx, txId, relayerA);
relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx});
checkRelayedViews({txId: txId, expectedRelayer: relayerA});
checkTokenBalances({recipient: userB, relayCaller: relayerA});
assertEq(userB.balance, ZAP_NATIVE);
}
function test_relay_token_withRelayerAddressZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
bytes32 txId = getTxId(tokenTx);
expectBridgeRelayed(tokenTx, txId, relayerA);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx});
checkRelayedViews({txId: txId, expectedRelayer: relayerA});
checkTokenBalances({recipient: userB, relayCaller: relayerB});
assertEq(userB.balance, ZAP_NATIVE);
}
// ═════════════════════════════════════ EXCESSIVE RETURN VALUE RECIPIENT ══════════════════════════════════════════
// Note: in this test, the zapData are not present, and the below test functions succeed.
// Override them in the derived tests where zapData are present to check for a revert.
function test_relay_token_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(excessiveReturnValueRecipient);
test_relay_token();
}
function test_relay_token_withRelayerAddress_excessiveReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(excessiveReturnValueRecipient);
test_relay_token_withRelayerAddress();
}
function test_relay_token_withZapNative_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(excessiveReturnValueRecipient);
test_relay_token_withZapNative();
}
function test_relay_token_withRelayerAddressZapNative_excessiveReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(excessiveReturnValueRecipient);
test_relay_token_withRelayerAddressZapNative();
}
function test_relay_eth_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(excessiveReturnValueRecipient);
test_relay_eth();
}
function test_relay_eth_withRelayerAddress_excessiveReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(excessiveReturnValueRecipient);
test_relay_eth_withRelayerAddress();
}
// ═════════════════════════════════════ INCORRECT RETURN VALUE RECIPIENT ══════════════════════════════════════════
// Note: in this test, the zapData are not present, and the below test functions succeed.
// Override them in the derived tests where zapData are present to check for a revert.
function test_relay_token_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(incorrectReturnValueRecipient);
test_relay_token();
}
function test_relay_token_withRelayerAddress_incorrectReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(incorrectReturnValueRecipient);
test_relay_token_withRelayerAddress();
}
function test_relay_token_withZapNative_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(incorrectReturnValueRecipient);
test_relay_token_withZapNative();
}
function test_relay_token_withRelayerAddressZapNative_incorrectReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(incorrectReturnValueRecipient);
test_relay_token_withRelayerAddressZapNative();
}
function test_relay_eth_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(incorrectReturnValueRecipient);
test_relay_eth();
}
function test_relay_eth_withRelayerAddress_incorrectReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(incorrectReturnValueRecipient);
test_relay_eth_withRelayerAddress();
}
// ═══════════════════════════════════════════ NON PAYABLE RECIPIENT ═══════════════════════════════════════════════
/// @notice Should not affect the ERC20 transfer
function test_relay_token_nonPayableRecipient() public {
setTokenTestRecipient(nonPayableRecipient);
test_relay_token();
}
function test_relay_token_withRelayerAddress_nonPayableRecipient() public {
setTokenTestRecipient(nonPayableRecipient);
test_relay_token_withRelayerAddress();
}
function test_relay_token_withZapNative_nonPayableRecipient_revert() public {
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(nonPayableRecipient);
vm.expectRevert();
relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddressZapNative_nonPayableRecipient_revert() public {
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(nonPayableRecipient);
vm.expectRevert();
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx});
}
function test_relay_eth_revert_nonPayableRecipient() public {
setEthTestRecipient(nonPayableRecipient);
vm.expectRevert();
relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
}
function test_relay_eth_withRelayerAddress_revert_nonPayableRecipient() public {
setEthTestRecipient(nonPayableRecipient);
vm.expectRevert();
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
}
// ══════════════════════════════════════════════ NO-OP RECIPIENT ══════════════════════════════════════════════════
// Note: in this test, the zapData are not present, and the below test functions succeed.
// Override them in the derived tests where zapData are present to check for a revert.
function test_relay_token_noOpRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(noOpRecipient);
test_relay_token();
}
function test_relay_token_withRelayerAddress_noOpRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(noOpRecipient);
test_relay_token_withRelayerAddress();
}
function test_relay_token_withZapNative_noOpRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(noOpRecipient);
test_relay_token_withZapNative();
}
function test_relay_token_withRelayerAddressZapNative_noOpRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(noOpRecipient);
test_relay_token_withRelayerAddressZapNative();
}
function test_relay_eth_noOpRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(noOpRecipient);
test_relay_eth();
}
function test_relay_eth_withRelayerAddress_noOpRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(noOpRecipient);
test_relay_eth_withRelayerAddress();
}
// ═════════════════════════════════════════ NO RETURN VALUE RECIPIENT ═════════════════════════════════════════════
// Note: in this test, the zapData are not present, and the below test functions succeed.
// Override them in the derived tests where zapData are present to check for a revert.
function test_relay_token_noReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(noReturnValueRecipient);
test_relay_token();
}
function test_relay_token_withRelayerAddress_noReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestRecipient(noReturnValueRecipient);
test_relay_token_withRelayerAddress();
}
function test_relay_token_withZapNative_noReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(noReturnValueRecipient);
test_relay_token_withZapNative();
}
function test_relay_token_withRelayerAddressZapNative_noReturnValueRecipient_revertWhenZapDataPresent()
public
virtual
{
assertEmptyZapData(tokenTx.zapData);
setTokenTestZapNative(ZAP_NATIVE);
setTokenTestRecipient(noReturnValueRecipient);
test_relay_token_withRelayerAddressZapNative();
}
function test_relay_eth_noReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(noReturnValueRecipient);
test_relay_eth();
}
function test_relay_eth_withRelayerAddress_noReturnValueRecipient_revertWhenZapDataPresent() public virtual {
assertEmptyZapData(ethTx.zapData);
setEthTestRecipient(noReturnValueRecipient);
test_relay_eth_withRelayerAddress();
}
// ══════════════════════════════════════════════════ REVERTS ══════════════════════════════════════════════════════
function test_relay_revert_requestV1() public {
// V1 doesn't have any version field
expectRevertUnsupportedVersion(0);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relay(mockRequestV1);
}
function test_relay_revert_invalidRequestV2() public {
expectRevertInvalidEncodedTx();
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relay(invalidRequestV2);
}
function test_relay_revert_requestV3() public {
expectRevertUnsupportedVersion(3);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relay(mockRequestV3);
}
function test_relay_revert_chainIncorrect() public {
vm.chainId(SRC_CHAIN_ID);
vm.expectRevert(ChainIncorrect.selector);
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_revert_transactionRelayed() public {
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
vm.expectRevert(TransactionRelayed.selector);
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_revert_deadlineExceeded() public {
skip(DEADLINE + 1);
vm.expectRevert(DeadlineExceeded.selector);
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_withRelayerAddress_revert_requestV1() public {
// V1 doesn't have any version field
expectRevertUnsupportedVersion(0);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relayV2(mockRequestV1, relayerB);
}
function test_relay_withRelayerAddress_revert_invalidRequestV2() public {
expectRevertInvalidEncodedTx();
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relayV2(invalidRequestV2, relayerB);
}
function test_relay_withRelayerAddress_revert_requestV3() public {
expectRevertUnsupportedVersion(3);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relayV2(mockRequestV3, relayerB);
}
function test_relay_withRelayerAddress_revert_chainIncorrect() public {
vm.chainId(SRC_CHAIN_ID);
vm.expectRevert(ChainIncorrect.selector);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_withRelayerAddress_revert_transactionRelayed() public {
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
vm.expectRevert(TransactionRelayed.selector);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_withRelayerAddress_revert_deadlineExceeded() public {
skip(DEADLINE + 1);
vm.expectRevert(DeadlineExceeded.selector);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_withRelayerAddress_revert_zeroAddr() public {
vm.expectRevert(ZeroAddress.selector);
relayWithAddress({caller: relayerA, relayer: address(0), msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_withZapNative_revert_zeroZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
vm.expectRevert(MsgValueIncorrect.selector);
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_withZapNative_revert_lowerZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
vm.expectRevert(MsgValueIncorrect.selector);
relay({caller: relayerA, msgValue: ZAP_NATIVE - 1, bridgeTx: tokenTx});
}
function test_relay_token_withZapNative_revert_higherZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
vm.expectRevert(MsgValueIncorrect.selector);
relay({caller: relayerA, msgValue: ZAP_NATIVE + 1, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddressZapNative_revert_zeroZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
vm.expectRevert(MsgValueIncorrect.selector);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddressZapNative_revert_lowerZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
vm.expectRevert(MsgValueIncorrect.selector);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE - 1, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddressZapNative_revert_higherZapNative() public {
setTokenTestZapNative(ZAP_NATIVE);
vm.expectRevert(MsgValueIncorrect.selector);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE + 1, bridgeTx: tokenTx});
}
function test_relay_eth_withZapNative_revert_notSupported() public {
setEthTestZapNative(ZAP_NATIVE);
// Neither destAmount, ZAP_NATIVE, nor destAmount + ZAP_NATIVE should work here
vm.expectRevert(ZapNativeNotSupported.selector);
relay({caller: relayerB, msgValue: ZAP_NATIVE, bridgeTx: ethTx});
vm.expectRevert(ZapNativeNotSupported.selector);
relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
vm.expectRevert(ZapNativeNotSupported.selector);
relay({caller: relayerB, msgValue: ethParams.destAmount + ZAP_NATIVE, bridgeTx: ethTx});
}
function test_relay_eth_withRelayerAddressZapNative_revert_notSupported() public {
setEthTestZapNative(ZAP_NATIVE);
// Neither destAmount, ZAP_NATIVE, nor destAmount + ZAP_NATIVE should work here
vm.expectRevert(ZapNativeNotSupported.selector);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ZAP_NATIVE, bridgeTx: ethTx});
vm.expectRevert(ZapNativeNotSupported.selector);
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx});
vm.expectRevert(ZapNativeNotSupported.selector);
relayWithAddress({
caller: relayerA,
relayer: relayerB,
msgValue: ethParams.destAmount + ZAP_NATIVE,
bridgeTx: ethTx
});
}
function test_relay_token_revert_approvedZero() public {
vm.prank(relayerA);
dstToken.approve(address(fastBridge), 0);
vm.expectRevert();
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_revert_approvedNotEnough() public {
vm.prank(relayerA);
dstToken.approve(address(fastBridge), tokenParams.destAmount - 1);
vm.expectRevert();
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_revert_nonZeroMsgValue() public {
vm.expectRevert();
relay({caller: relayerA, msgValue: tokenParams.destAmount, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddress_revert_approvedZero() public {
vm.prank(relayerB);
dstToken.approve(address(fastBridge), 0);
vm.expectRevert();
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddress_revert_approvedNotEnough() public {
vm.prank(relayerB);
dstToken.approve(address(fastBridge), tokenParams.destAmount - 1);
vm.expectRevert();
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx});
}
function test_relay_token_withRelayerAddress_revert_nonZeroMsgValue() public {
vm.expectRevert();
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: tokenParams.destAmount, bridgeTx: tokenTx});
}
function test_relay_eth_revert_lowerMsgValue() public {
vm.expectRevert();
relay({caller: relayerB, msgValue: ethParams.destAmount - 1, bridgeTx: ethTx});
}
function test_relay_eth_revert_higherMsgValue() public {
vm.expectRevert();
relay({caller: relayerB, msgValue: ethParams.destAmount + 1, bridgeTx: ethTx});
}
function test_relay_eth_revert_zeroMsgValue() public {
vm.expectRevert();
relay({caller: relayerB, msgValue: 0, bridgeTx: ethTx});
}
function test_relay_eth_withRelayerAddress_revert_lowerMsgValue() public {
vm.expectRevert();
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount - 1, bridgeTx: ethTx});
}
function test_relay_eth_withRelayerAddress_revert_higherMsgValue() public {
vm.expectRevert();
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount + 1, bridgeTx: ethTx});
}
function test_relay_eth_withRelayerAddress_revert_zeroMsgValue() public {
vm.expectRevert();
relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: 0, bridgeTx: ethTx});
}
}