Skip to content

Commit

Permalink
feat: complete bridge adapter invariants
Browse files Browse the repository at this point in the history
  • Loading branch information
sujithsomraaj committed Oct 18, 2023
1 parent 8080134 commit df5f6e8
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 2 deletions.
2 changes: 1 addition & 1 deletion test/invariant-tests/AccessControl.Invariant.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {Vm, Test} from "forge-std/Test.sol";
import "test/Setup.t.sol";

/// handler import
import {AccessControlSenderHandler} from "test/invariant-tests/handlers/AccessControlSender.handler.sol";
import {AccessControlSenderHandler} from "test/invariant-tests/handlers/AccessControlSender.Handler.sol";

contract AccessControlHandlerInvariant is Setup {
AccessControlSenderHandler public handler;
Expand Down
60 changes: 60 additions & 0 deletions test/invariant-tests/BridgeAdapter.Invariant.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
pragma solidity >=0.8.9;

/// library imports
import {Vm, Test} from "forge-std/Test.sol";

/// local imports
import "test/Setup.t.sol";

/// handler import
import {BridgeAdapterHandler} from "test/invariant-tests/handlers/BridgeAdapter.Handler.sol";

/// @notice invariants for bridge adapters receiving messages
contract BridgeAdapterInvariant is Setup {
BridgeAdapterHandler public handler;

/// @notice initializes the setup
function setUp() public override {
/// @dev calls setup to spin up test contracts
super.setUp();

/// @dev selects fork and deploy the handlers
vm.selectFork(fork[BSC_CHAIN_ID]);
handler = new BridgeAdapterHandler(
contractAddress[BSC_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"],
contractAddress[BSC_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"],
contractAddress[BSC_CHAIN_ID]["MMA_RECEIVER"]
);

/// @dev bind the handler as target for invariant
targetContract(address(handler));
}

function invariant_test_bridge_adapter_receivers() public {
if (handler.success() && handler.lastBridge() == 1) {
assertTrue(
WormholeReceiverAdapter(contractAddress[BSC_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]).isMessageExecuted(
handler.lastMessageId()
)
);
assertTrue(
WormholeReceiverAdapter(contractAddress[BSC_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]).deliveryHashStatus(
handler.lastMessageHash()
)
);
}

if (handler.success() && handler.lastBridge() == 2) {
assertTrue(
AxelarReceiverAdapter(contractAddress[BSC_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]).isMessageExecuted(
handler.lastMessageId()
)
);
assertTrue(
AxelarReceiverAdapter(contractAddress[BSC_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]).commandIdStatus(
handler.lastMessageHash()
)
);
}
}
}
2 changes: 1 addition & 1 deletion test/invariant-tests/handlers/AdapterList.Handler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "forge-std/Test.sol";
import {MessageSenderGAC} from "src/controllers/MessageSenderGAC.sol";
import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol";

/// @notice handler for testing maintaining adapter list
/// @notice handler for invariant testing maintaining adapter list
contract AdapterListHandler is Test {
/// @notice local state
MultiBridgeMessageSender public multiBridgeMessageSender;
Expand Down
120 changes: 120 additions & 0 deletions test/invariant-tests/handlers/BridgeAdapter.Handler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.9;

/// library imports
import "forge-std/Test.sol";

/// local imports
import {WormholeReceiverAdapter} from "src/adapters/wormhole/WormholeReceiverAdapter.sol";
import {AxelarReceiverAdapter} from "src/adapters/axelar/AxelarReceiverAdapter.sol";
import {AdapterPayload} from "src/libraries/Types.sol";
import "src/libraries/TypeCasts.sol";
import "src/libraries/Message.sol";
import "src/adapters/axelar/libraries/StringAddressConversion.sol";

/// @notice helper interface of axelar gateway to simulaate approve contract call
interface IAxelarGateway {
function approveContractCall(bytes calldata params, bytes32 commandId) external;

function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)
external;
}

/// @notice handler for invariant testing receiver bridge adapters
contract BridgeAdapterHandler is Test {
/// @notice local state
WormholeReceiverAdapter public wormhole;
AxelarReceiverAdapter public axelar;

address public multiBridgeReceiver;
bytes32 public lastMessageId;
bytes32 public lastMessageHash;

uint256 public lastBridge;

bool public success;

/// @notice modifier to prank caller
modifier prank(address _prankster) {
vm.startPrank(_prankster);
_;
vm.stopPrank();
}

/// @notice initial setup contracts
constructor(address _wormhole, address _axelar, address _multiBridgeReceiver) {
wormhole = WormholeReceiverAdapter(_wormhole);
axelar = AxelarReceiverAdapter(_axelar);
multiBridgeReceiver = _multiBridgeReceiver;
}

/// @notice helper for wormhole receivers
function receiveWormholeMessages(
AdapterPayload memory _payload,
MessageLibrary.Message memory _data,
bytes[] memory _vaas,
bytes32 _deliveryHash
) external prank(wormhole.relayer()) {
success = false;
vm.assume(_payload.msgId != bytes32(0));

lastBridge = 1;
_payload.receiverAdapter = address(wormhole);
_payload.finalDestination = multiBridgeReceiver;
_data.dstChainId = 56;
_data.srcChainId = 1;
_payload.data = abi.encode(_data);

lastMessageId = _payload.msgId;
lastMessageHash = _deliveryHash;
success = true;

wormhole.receiveWormholeMessages(
abi.encode(_payload),
_vaas,
TypeCasts.addressToBytes32(wormhole.senderAdapter()),
wormhole.senderChainId(),
_deliveryHash
);
}

/// @notice helper for axelar receivers
function receiveAxelarMessages(
AdapterPayload memory _payload,
MessageLibrary.Message memory _data,
bytes32 _commandId
) external prank(address(axelar.gateway())) {
lastBridge = 2;
_payload.receiverAdapter = address(axelar);
_payload.finalDestination = multiBridgeReceiver;

_data.dstChainId = 56;
_data.srcChainId = 1;
_payload.data = abi.encode(_data);

/// @notice simulating the payload existence on axelar's gateway
/// @dev helps us bypass NOT_APPROVED_BY_GATEWAY error on axelar adapter
IAxelarGateway(address(axelar.gateway())).approveContractCall(
abi.encode(
"ethereum",
StringAddressConversion.toString(address(axelar.senderAdapter())),
address(axelar),
keccak256(abi.encode(_payload)),
bytes32(0),
0
),
_commandId
);

lastMessageId = _payload.msgId;
lastMessageHash = _commandId;
success = true;

axelar.execute(
_commandId,
axelar.senderChainId(),
StringAddressConversion.toString(axelar.senderAdapter()),
abi.encode(_payload)
);
}
}

0 comments on commit df5f6e8

Please sign in to comment.