From 3a8b8b68b5bbd64612886ef8193a64217c63d73c Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 12 Sep 2023 19:27:39 -0700 Subject: [PATCH] Address review comments Various fixes --- src/adapters/BaseSenderAdapter.sol | 2 +- src/adapters/Celer/CelerReceiverAdapter.sol | 11 +- .../Wormhole/WormholeReceiverAdapter.sol | 20 +- src/adapters/axelar/AxelarReceiverAdapter.sol | 22 +- src/interfaces/IBridgeReceiverAdapter.sol | 5 +- src/libraries/Error.sol | 10 +- test/Setup.t.sol | 4 +- .../adapters/BaseSenderAdapter.t.sol | 22 +- .../axelar/AxelarReceiverAdapter.t.sol | 223 ++++++------------ .../adapters/axelar/AxelarSenderAdapter.t.sol | 9 +- .../wormhole/WormholeReceiverAdapter.t.sol | 90 ++++--- .../wormhole/WormholeSenderAdapter.t.sol | 9 +- 12 files changed, 178 insertions(+), 249 deletions(-) diff --git a/src/adapters/BaseSenderAdapter.sol b/src/adapters/BaseSenderAdapter.sol index 40424c2..fc15633 100644 --- a/src/adapters/BaseSenderAdapter.sol +++ b/src/adapters/BaseSenderAdapter.sol @@ -27,7 +27,7 @@ abstract contract BaseSenderAdapter is IBridgeSenderAdapter { modifier onlyGlobalOwner() { if (!gac.isGlobalOwner(msg.sender)) { - revert Error.INVALID_PRIVILEGED_CALLER(); + revert Error.CALLER_NOT_OWNER(); } _; } diff --git a/src/adapters/Celer/CelerReceiverAdapter.sol b/src/adapters/Celer/CelerReceiverAdapter.sol index f98ac2a..d1add48 100644 --- a/src/adapters/Celer/CelerReceiverAdapter.sol +++ b/src/adapters/Celer/CelerReceiverAdapter.sol @@ -73,22 +73,15 @@ contract CelerReceiverAdapter is IBridgeReceiverAdapter, IMessageReceiverApp { ////////////////////////////////////////////////////////////////*/ /// @inheritdoc IBridgeReceiverAdapter - function updateSenderAdapter(bytes memory _senderChain, address _senderAdapter) external override onlyGlobalOwner { - uint64 _senderChainDecoded = abi.decode(_senderChain, (uint64)); - - if (_senderChainDecoded == 0) { - revert Error.ZERO_CHAIN_ID(); - } - + function updateSenderAdapter(address _senderAdapter) external override onlyGlobalOwner { if (_senderAdapter == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } address oldAdapter = senderAdapter; senderAdapter = _senderAdapter; - senderChain = _senderChainDecoded; - emit SenderAdapterUpdated(oldAdapter, _senderAdapter, _senderChain); + emit SenderAdapterUpdated(oldAdapter, _senderAdapter); } /// @dev accepts incoming messages from celer message bus diff --git a/src/adapters/Wormhole/WormholeReceiverAdapter.sol b/src/adapters/Wormhole/WormholeReceiverAdapter.sol index f26a384..30f8082 100644 --- a/src/adapters/Wormhole/WormholeReceiverAdapter.sol +++ b/src/adapters/Wormhole/WormholeReceiverAdapter.sol @@ -21,12 +21,12 @@ contract WormholeReceiverAdapter is IBridgeReceiverAdapter, IWormholeReceiver { string public constant name = "wormhole"; address public immutable relayer; IGAC public immutable gac; + uint16 public immutable senderChain = uint16(2); // Wormhole chain ID for Ethereum /*///////////////////////////////////////////////////////////////// STATE VARIABLES ////////////////////////////////////////////////////////////////*/ address public senderAdapter; - uint16 public senderChain; mapping(uint256 => uint16) public chainIdMap; @@ -67,22 +67,15 @@ contract WormholeReceiverAdapter is IBridgeReceiverAdapter, IWormholeReceiver { ////////////////////////////////////////////////////////////////*/ /// @inheritdoc IBridgeReceiverAdapter - function updateSenderAdapter(bytes memory _senderChain, address _senderAdapter) external override onlyGlobalOwner { - uint16 _senderChainDecoded = abi.decode(_senderChain, (uint16)); - - if (_senderChainDecoded == 0) { - revert Error.ZERO_CHAIN_ID(); - } - + function updateSenderAdapter(address _senderAdapter) external override onlyGlobalOwner { if (_senderAdapter == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } address oldAdapter = senderAdapter; senderAdapter = _senderAdapter; - senderChain = _senderChainDecoded; - emit SenderAdapterUpdated(oldAdapter, _senderAdapter, _senderChain); + emit SenderAdapterUpdated(oldAdapter, _senderAdapter); } /// @dev maps the MMA chain id to bridge specific chain id @@ -137,7 +130,12 @@ contract WormholeReceiverAdapter is IBridgeReceiverAdapter, IWormholeReceiver { isMessageExecuted[decodedPayload.msgId] = true; deliveryHashStatus[deliveryHash] = true; - /// @dev step-4: validate the destination + /// @dev step-4: validate the receive adapter + if (decodedPayload.receiverAdapter != address(this)) { + revert Error.INVALID_RECEIVER_ADAPTER(); + } + + /// @dev step-5: validate the destination if (decodedPayload.finalDestination != gac.getMultiMessageReceiver(block.chainid)) { revert Error.INVALID_FINAL_DESTINATION(); } diff --git a/src/adapters/axelar/AxelarReceiverAdapter.sol b/src/adapters/axelar/AxelarReceiverAdapter.sol index 9e753fe..570ceed 100644 --- a/src/adapters/axelar/AxelarReceiverAdapter.sol +++ b/src/adapters/axelar/AxelarReceiverAdapter.sol @@ -20,6 +20,7 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IBridgeReceiverAdapter { using StringAddressConversion for string; string public constant name = "axelar"; + string public constant senderChain = "ethereum"; IAxelarGateway public immutable gateway; IGAC public immutable gac; @@ -28,7 +29,6 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IBridgeReceiverAdapter { STATE VARIABLES ////////////////////////////////////////////////////////////////*/ address public senderAdapter; - string public senderChain; mapping(bytes32 => bool) public isMessageExecuted; mapping(bytes32 => bool) public commandIdStatus; @@ -56,22 +56,15 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IBridgeReceiverAdapter { ////////////////////////////////////////////////////////////////*/ /// @inheritdoc IBridgeReceiverAdapter - function updateSenderAdapter(bytes memory _senderChain, address _senderAdapter) external override onlyGlobalOwner { - string memory _senderChainDecoded = abi.decode(_senderChain, (string)); - - if (keccak256(abi.encode(_senderChainDecoded)) == keccak256(abi.encode(""))) { - revert Error.ZERO_CHAIN_ID(); - } - + function updateSenderAdapter(address _senderAdapter) external override onlyGlobalOwner { if (_senderAdapter == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } address oldAdapter = senderAdapter; senderAdapter = _senderAdapter; - senderChain = _senderChainDecoded; - emit SenderAdapterUpdated(oldAdapter, _senderAdapter, _senderChain); + emit SenderAdapterUpdated(oldAdapter, _senderAdapter); } /// @dev accepts new cross-chain messages from axelar gateway @@ -87,7 +80,7 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IBridgeReceiverAdapter { revert Error.INVALID_SENDER_CHAIN_ID(); } - /// @dev step-2: validate the caller + /// @dev step-2: validate the contract call if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, keccak256(payload))) { revert Error.NOT_APPROVED_BY_GATEWAY(); } @@ -106,7 +99,12 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IBridgeReceiverAdapter { revert MessageIdAlreadyExecuted(msgId); } - /// @dev step-5: validate the destination + /// @dev step-5: validate the receive adapter + if (decodedPayload.receiverAdapter != address(this)) { + revert Error.INVALID_RECEIVER_ADAPTER(); + } + + /// @dev step-6: validate the destination if (decodedPayload.finalDestination != gac.getMultiMessageReceiver(block.chainid)) { revert Error.INVALID_FINAL_DESTINATION(); } diff --git a/src/interfaces/IBridgeReceiverAdapter.sol b/src/interfaces/IBridgeReceiverAdapter.sol index 900eea3..23f412d 100644 --- a/src/interfaces/IBridgeReceiverAdapter.sol +++ b/src/interfaces/IBridgeReceiverAdapter.sol @@ -8,7 +8,7 @@ interface IBridgeReceiverAdapter is MessageExecutor { /*///////////////////////////////////////////////////////////////// EVENTS ////////////////////////////////////////////////////////////////*/ - event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter, bytes senderChain); + event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter); /*///////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS @@ -18,8 +18,7 @@ interface IBridgeReceiverAdapter is MessageExecutor { function name() external view returns (string memory); /// @dev allows global admin to update the sender adapter - /// @param _senderChain is the bridge native sender chain (ETH) as bytes /// @param _senderAdapter is the bridge's sender adapter deployed to Ethereum /// note: access controlled to be called by the global admin contract - function updateSenderAdapter(bytes memory _senderChain, address _senderAdapter) external; + function updateSenderAdapter(address _senderAdapter) external; } diff --git a/src/libraries/Error.sol b/src/libraries/Error.sol index 03bba80..3c5d2a7 100644 --- a/src/libraries/Error.sol +++ b/src/libraries/Error.sol @@ -17,7 +17,7 @@ library Error { /// @dev is thrown if the length of two arrays are mismatched error ARRAY_LENGTH_MISMATCHED(); - /// @dev is thrown if caller is not owner of the contract + /// @dev is thrown if caller is not the privileged caller error INVALID_PRIVILEGED_CALLER(); /// @dev is thrown if caller is invalid receiver adapter @@ -33,7 +33,7 @@ library Error { error MSG_ID_ALREADY_EXECUTED(); /// @dev is thrown if message conflicts with current storage - error NEW_MESSAGE_CONFLITS_WITH_OLD_DATA(); + error NEW_MESSAGE_CONFLICTS_WITH_OLD_DATA(); /// @dev is thrown if bridge adapter already delivered the message to multi message receiver error DUPLICATE_MESSAGE_DELIVERY_BY_ADAPTER(); @@ -75,13 +75,13 @@ library Error { /// @dev is thrown if caller is not multi message sender error CALLER_NOT_MULTI_MESSAGE_SENDER(); - /// @dev is thrown if sender chain is not allowed on reciever adapter + /// @dev is thrown if sender chain is not allowed on receiver adapter error INVALID_SENDER_CHAIN_ID(); - /// @dev is thrown if sender adapter is not allowed on reciever adapter + /// @dev is thrown if sender adapter is not allowed on receiver adapter error INVALID_SENDER_ADAPTER(); - /// @dev is thrown if final destination is not mma receiver on reciever adapter + /// @dev is thrown if final destination is not mma receiver on receiver adapter error INVALID_FINAL_DESTINATION(); /// @dev is thrown if chain id is zero diff --git a/test/Setup.t.sol b/test/Setup.t.sol index 81f0f4b..e28cb4f 100644 --- a/test/Setup.t.sol +++ b/test/Setup.t.sol @@ -345,11 +345,11 @@ abstract contract Setup is Test { vm.selectFork(fork[chainId]); WormholeReceiverAdapter(contractAddress[chainId]["WORMHOLE_RECEIVER_ADAPTER"]).updateSenderAdapter( - abi.encode(_wormholeChainId(1)), contractAddress[1]["WORMHOLE_SENDER_ADAPTER"] + contractAddress[1]["WORMHOLE_SENDER_ADAPTER"] ); AxelarReceiverAdapter(contractAddress[chainId]["AXELAR_RECEIVER_ADAPTER"]).updateSenderAdapter( - abi.encode(_axelarChainId(1)), contractAddress[1]["AXELAR_SENDER_ADAPTER"] + contractAddress[1]["AXELAR_SENDER_ADAPTER"] ); unchecked { diff --git a/test/unit-tests/adapters/BaseSenderAdapter.t.sol b/test/unit-tests/adapters/BaseSenderAdapter.t.sol index f95b556..80c7ba3 100644 --- a/test/unit-tests/adapters/BaseSenderAdapter.t.sol +++ b/test/unit-tests/adapters/BaseSenderAdapter.t.sol @@ -12,9 +12,6 @@ import {AxelarSenderAdapter} from "src/adapters/axelar/AxelarSenderAdapter.sol"; contract AxelarSenderAdapterTest is Setup { event ReceiverAdapterUpdated(uint256 dstChainId, address receiverAdapter); - uint256 constant SRC_CHAIN_ID = 1; - uint256 constant DST_CHAIN_ID = 137; - // Test base contract with Axelar adapter AxelarSenderAdapter adapter; @@ -30,29 +27,26 @@ contract AxelarSenderAdapterTest is Setup { function test_update_receiver_adapter() public { vm.startPrank(owner); - uint256[] memory dstChainIds = new uint256[](2); - dstChainIds[0] = 56; - dstChainIds[1] = DST_CHAIN_ID; address[] memory receiverAdapters = new address[](2); receiverAdapters[0] = address(42); receiverAdapters[1] = address(43); vm.expectEmit(true, true, true, true, address(adapter)); - emit ReceiverAdapterUpdated(56, address(42)); + emit ReceiverAdapterUpdated(BSC_CHAIN_ID, address(42)); vm.expectEmit(true, true, true, true, address(adapter)); - emit ReceiverAdapterUpdated(DST_CHAIN_ID, address(43)); + emit ReceiverAdapterUpdated(POLYGON_CHAIN_ID, address(43)); - adapter.updateReceiverAdapter(dstChainIds, receiverAdapters); + adapter.updateReceiverAdapter(DST_CHAINS, receiverAdapters); - assertEq(adapter.receiverAdapters(56), address(42)); - assertEq(adapter.receiverAdapters(DST_CHAIN_ID), address(43)); + assertEq(adapter.receiverAdapters(BSC_CHAIN_ID), address(42)); + assertEq(adapter.receiverAdapters(POLYGON_CHAIN_ID), address(43)); } - /// @dev only privileged caller can update receiver adapter - function test_update_receiver_adapter_only_privileged_caller() public { + /// @dev only global owner can update receiver adapter + function test_update_receiver_adapter_only_global_owner() public { vm.startPrank(caller); - vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); + vm.expectRevert(Error.CALLER_NOT_OWNER.selector); adapter.updateReceiverAdapter(new uint256[](0), new address[](0)); } diff --git a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol index dc76ac4..8439f98 100644 --- a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol @@ -19,10 +19,7 @@ contract AxelarReceiverAdapterTest is Setup { using StringAddressConversion for address; event MessageIdExecuted(uint256 indexed fromChainId, bytes32 indexed messageId); - event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter, bytes senderChain); - - uint256 constant SRC_CHAIN_ID = 1; - uint256 constant DST_CHAIN_ID = 137; + event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter); AxelarReceiverAdapter adapter; @@ -39,6 +36,7 @@ contract AxelarReceiverAdapterTest is Setup { // checks existing setup assertEq(address(adapter.gateway()), POLYGON_GATEWAY); assertEq(address(adapter.gac()), contractAddress[DST_CHAIN_ID]["GAC"]); + assertEq(adapter.senderChain(), "ethereum"); } /// @dev gets the name @@ -51,30 +49,19 @@ contract AxelarReceiverAdapterTest is Setup { vm.startPrank(owner); vm.expectEmit(true, true, true, true, address(adapter)); - emit SenderAdapterUpdated( - contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"], address(42), abi.encode("ethereum") - ); + emit SenderAdapterUpdated(contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"], address(42)); - adapter.updateSenderAdapter(abi.encode("ethereum"), address(42)); + adapter.updateSenderAdapter(address(42)); assertEq(adapter.senderAdapter(), address(42)); - assertEq(adapter.senderChain(), "ethereum"); } - /// @dev only privileged caller can update sender adapter - function test_update_sender_adapter_only_privileged_caller() public { + /// @dev only global owner can update sender adapter + function test_update_sender_adapter_only_global_owner() public { vm.startPrank(caller); - vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); - adapter.updateSenderAdapter(abi.encode("ethereum"), address(42)); - } - - /// @dev cannot update sender adapter with zero chain ID - function test_update_sender_adapter_zero_chain_id() public { - vm.startPrank(owner); - - vm.expectRevert(Error.ZERO_CHAIN_ID.selector); - adapter.updateSenderAdapter(abi.encode(""), address(42)); + vm.expectRevert(Error.CALLER_NOT_OWNER.selector); + adapter.updateSenderAdapter(address(42)); } /// @dev cannot update sender adapter with zero address @@ -82,28 +69,12 @@ contract AxelarReceiverAdapterTest is Setup { vm.startPrank(owner); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - adapter.updateSenderAdapter(abi.encode("ethereum"), address(0)); + adapter.updateSenderAdapter(address(0)); } /// @dev executes message function test_execute() public { - vm.startPrank(owner); - - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(true /* validate */)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); - - // change receiver adapter on dst chain to the dummy one - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); - - vm.startPrank(caller); + (AxelarReceiverAdapter dummyAdapter, address senderAdapter, address receiverAddr) = _prepareDummyAdapter(true); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -119,7 +90,7 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(dummyAdapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -135,22 +106,7 @@ contract AxelarReceiverAdapterTest is Setup { /// @dev cannot execute message with invalid sender chain ID function test_execute_invalid_sender_chain_id() public { - vm.startPrank(owner); - - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(true)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); - - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); - - vm.startPrank(caller); + (AxelarReceiverAdapter dummyAdapter, address senderAdapter, address receiverAddr) = _prepareDummyAdapter(true); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -166,7 +122,7 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(dummyAdapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -177,22 +133,7 @@ contract AxelarReceiverAdapterTest is Setup { /// @dev cannot execute message that is not approved by the Axelar gateway function test_execute_not_approved_by_gateway() public { - vm.startPrank(owner); - - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(false)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); - - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); - - vm.startPrank(caller); + (AxelarReceiverAdapter dummyAdapter, address senderAdapter, address receiverAddr) = _prepareDummyAdapter(false); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -208,7 +149,7 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(dummyAdapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -219,22 +160,7 @@ contract AxelarReceiverAdapterTest is Setup { /// @dev cannot execute message with invalid sender adapter function test_execute_invalid_sender_adapter() public { - vm.startPrank(owner); - - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(true)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); - - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); - - vm.startPrank(caller); + (AxelarReceiverAdapter dummyAdapter,, address receiverAddr) = _prepareDummyAdapter(true); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -250,33 +176,18 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(dummyAdapter), finalDestination: receiverAddr, data: abi.encode(message) }); vm.expectRevert(Error.INVALID_SENDER_ADAPTER.selector); - dummyAdapter.execute(bytes32("commandId"), "ethereum", address(44).toString(), abi.encode(payload)); + dummyAdapter.execute(bytes32("commandId"), "ethereum", address(43).toString(), abi.encode(payload)); } /// @dev cannot execute message that is already executed function test_execute_message_id_already_executed() public { - vm.startPrank(owner); - - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(true)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); - - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); - - vm.startPrank(caller); + (AxelarReceiverAdapter dummyAdapter, address senderAdapter, address receiverAddr) = _prepareDummyAdapter(true); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -292,7 +203,7 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(dummyAdapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -303,24 +214,36 @@ contract AxelarReceiverAdapterTest is Setup { dummyAdapter.execute(bytes32("commandId"), "ethereum", senderAdapter.toString(), abi.encode(payload)); } - /// @dev cannot execute message with invalid final destination - function test_execute_invalid_final_destination() public { - vm.startPrank(owner); + /// @dev cannot execute message with invalid receiver adapter + function test_execute_invalid_receiver_adapter() public { + (AxelarReceiverAdapter dummyAdapter, address senderAdapter,) = _prepareDummyAdapter(true); - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(true)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); + MessageLibrary.Message memory message = MessageLibrary.Message({ + srcChainId: SRC_CHAIN_ID, + dstChainId: DST_CHAIN_ID, + target: address(42), + nonce: 0, + callData: bytes("42"), + nativeValue: 0, + expiration: type(uint256).max + }); + bytes32 msgId = MessageLibrary.computeMsgId(message); - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); + AdapterPayload memory payload = AdapterPayload({ + msgId: msgId, + senderAdapterCaller: address(42), + receiverAdapter: address(43), + finalDestination: address(44), + data: abi.encode(message) + }); - vm.startPrank(caller); + vm.expectRevert(Error.INVALID_RECEIVER_ADAPTER.selector); + dummyAdapter.execute(bytes32("commandId"), "ethereum", senderAdapter.toString(), abi.encode(payload)); + } + + /// @dev cannot execute message with invalid final destination + function test_execute_invalid_final_destination() public { + (AxelarReceiverAdapter dummyAdapter, address senderAdapter,) = _prepareDummyAdapter(true); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -336,8 +259,8 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), - finalDestination: address(44), + receiverAdapter: address(dummyAdapter), + finalDestination: address(43), data: abi.encode(message) }); @@ -347,22 +270,7 @@ contract AxelarReceiverAdapterTest is Setup { /// @dev reverts if message fails to be received function test_execute_message_failure() public { - vm.startPrank(owner); - - address senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; - AxelarReceiverAdapter dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(true)), contractAddress[DST_CHAIN_ID]["GAC"]); - dummyAdapter.updateSenderAdapter(abi.encode("ethereum"), senderAdapter); - - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - address receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - address[] memory receiverAdapters = new address[](1); - receiverAdapters[0] = address(dummyAdapter); - bool[] memory operations = new bool[](1); - operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapter(receiverAdapters, operations); - - vm.startPrank(caller); + (AxelarReceiverAdapter dummyAdapter, address senderAdapter, address receiverAddr) = _prepareDummyAdapter(true); MessageLibrary.Message memory message = MessageLibrary.Message({ srcChainId: SRC_CHAIN_ID, @@ -378,13 +286,38 @@ contract AxelarReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(dummyAdapter), finalDestination: receiverAddr, data: abi.encode(message) }); - // NOTE: Forge mangles low level error and doesn't allow checking for partial signature match - vm.expectRevert(); + vm.expectRevert( + abi.encodeWithSelector( + MessageExecutor.MessageFailure.selector, msgId, abi.encodePacked(Error.INVALID_TARGET.selector) + ) + ); dummyAdapter.execute(bytes32("commandId"), "ethereum", senderAdapter.toString(), abi.encode(payload)); } + + function _prepareDummyAdapter(bool _validateCall) + internal + returns (AxelarReceiverAdapter dummyAdapter, address senderAdapter, address receiverAddr) + { + vm.startPrank(owner); + + senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; + dummyAdapter = + new AxelarReceiverAdapter(address(new MockAxelarGateway(_validateCall)), contractAddress[DST_CHAIN_ID]["GAC"]); + dummyAdapter.updateSenderAdapter(senderAdapter); + + vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); + receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; + address[] memory receiverAdapters = new address[](1); + receiverAdapters[0] = address(dummyAdapter); + bool[] memory operations = new bool[](1); + operations[0] = true; + MultiMessageReceiver(receiverAddr).updateReceiverAdapters(receiverAdapters, operations); + + vm.startPrank(caller); + } } diff --git a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol index 7cc8925..a3cc6b2 100644 --- a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol @@ -14,9 +14,6 @@ contract AxelarSenderAdapterTest is Setup { bytes32 indexed messageId, address indexed from, uint256 indexed toChainId, address to, bytes data ); - uint256 constant SRC_CHAIN_ID = 1; - uint256 constant DST_CHAIN_ID = 137; - address senderAddr; AxelarSenderAdapter adapter; @@ -99,11 +96,11 @@ contract AxelarSenderAdapterTest is Setup { assertEq(adapter.chainIdMap(DST_CHAIN_ID), "42"); } - /// @dev only privileged caller can set chain ID map - function test_set_chain_id_map_only_privileged_caller() public { + /// @dev only global owner can set chain ID map + function test_set_chain_id_map_only_global_owner() public { vm.startPrank(caller); - vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); + vm.expectRevert(Error.CALLER_NOT_OWNER.selector); adapter.setChainIdMap(new uint256[](0), new string[](0)); } diff --git a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol index 2b9902f..4f2b7d6 100644 --- a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol @@ -16,10 +16,7 @@ import {WormholeReceiverAdapter} from "src/adapters/Wormhole/WormholeReceiverAda contract WormholeReceiverAdapterTest is Setup { event MessageIdExecuted(uint256 indexed fromChainId, bytes32 indexed messageId); - event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter, bytes senderChain); - - uint256 constant SRC_CHAIN_ID = 1; - uint256 constant DST_CHAIN_ID = 137; + event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter); WormholeReceiverAdapter adapter; @@ -48,38 +45,28 @@ contract WormholeReceiverAdapterTest is Setup { vm.startPrank(owner); vm.expectEmit(true, true, true, true, address(adapter)); - emit SenderAdapterUpdated( - contractAddress[SRC_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"], address(42), abi.encode(uint16(2)) - ); + emit SenderAdapterUpdated(contractAddress[SRC_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"], address(42)); - adapter.updateSenderAdapter(abi.encode(uint16(2)), address(42)); + adapter.updateSenderAdapter(address(42)); assertEq(adapter.senderAdapter(), address(42)); assertEq(adapter.senderChain(), uint16(2)); } - /// @dev only privileged caller can update sender adapter - function test_update_sender_adapter_only_privileged_caller() public { + /// @dev only global owner can update sender adapter + function test_update_sender_adapter_only_global_owner() public { vm.startPrank(caller); - vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); - adapter.updateSenderAdapter(abi.encode(uint16(2)), address(42)); - } - - /// @dev cannot update sender adapter with zero chain ID - function test_update_sender_adapter_zero_chain_id() public { - vm.startPrank(owner); - - vm.expectRevert(Error.ZERO_CHAIN_ID.selector); - adapter.updateSenderAdapter(abi.encode(uint16(0)), address(42)); + vm.expectRevert(Error.CALLER_NOT_OWNER.selector); + adapter.updateSenderAdapter(address(42)); } - /// @dev cannot update sender adapter with zero address + function test_update_sender_adapter_zero_address_input() public { vm.startPrank(owner); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - adapter.updateSenderAdapter(abi.encode(uint16(2)), address(0)); + adapter.updateSenderAdapter(address(0)); } /// @dev sets chain ID map @@ -95,11 +82,11 @@ contract WormholeReceiverAdapterTest is Setup { assertEq(adapter.chainIdMap(1234), uint16(5678)); } - /// @dev only privileged caller can set chain ID map - function test_set_chain_id_map_only_privileged_caller() public { + /// @dev only global owner can set chain ID map + function test_set_chain_id_map_only_global_owner() public { vm.startPrank(caller); - vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); + vm.expectRevert(Error.CALLER_NOT_OWNER.selector); adapter.setChainIdMap(new uint256[](0), new uint16[](0)); } @@ -131,7 +118,7 @@ contract WormholeReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(adapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -167,7 +154,7 @@ contract WormholeReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(adapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -197,14 +184,14 @@ contract WormholeReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(adapter), finalDestination: receiverAddr, data: abi.encode(message) }); vm.expectRevert(Error.INVALID_SENDER_ADAPTER.selector); adapter.receiveWormholeMessages( - abi.encode(payload), new bytes[](0), TypeCasts.addressToBytes32(address(44)), uint16(2), bytes32("1234") + abi.encode(payload), new bytes[](0), TypeCasts.addressToBytes32(address(43)), uint16(2), bytes32("1234") ); } @@ -228,7 +215,7 @@ contract WormholeReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(adapter), finalDestination: receiverAddr, data: abi.encode(message) }); @@ -242,8 +229,8 @@ contract WormholeReceiverAdapterTest is Setup { ); } - /// @dev cannot receive message with invalid final destination - function test_receive_wormhole_messages_invalid_final_destination() public { + /// @dev cannot receive message with invalid receiver adapter + function test_receive_wormhole_messages_invalid_receiver_adapter() public { vm.startPrank(POLYGON_RELAYER); address senderAdapter = contractAddress[SRC_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"]; @@ -266,6 +253,36 @@ contract WormholeReceiverAdapterTest is Setup { data: abi.encode(message) }); + vm.expectRevert(Error.INVALID_RECEIVER_ADAPTER.selector); + adapter.receiveWormholeMessages( + abi.encode(payload), new bytes[](0), TypeCasts.addressToBytes32(senderAdapter), uint16(2), bytes32("1234") + ); + } + + /// @dev cannot receive message with invalid final destination + function test_receive_wormhole_messages_invalid_final_destination() public { + vm.startPrank(POLYGON_RELAYER); + + address senderAdapter = contractAddress[SRC_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"]; + MessageLibrary.Message memory message = MessageLibrary.Message({ + srcChainId: SRC_CHAIN_ID, + dstChainId: DST_CHAIN_ID, + target: address(42), + nonce: 0, + callData: bytes("42"), + nativeValue: 0, + expiration: type(uint256).max + }); + bytes32 msgId = MessageLibrary.computeMsgId(message); + + AdapterPayload memory payload = AdapterPayload({ + msgId: msgId, + senderAdapterCaller: address(42), + receiverAdapter: address(adapter), + finalDestination: address(43), + data: abi.encode(message) + }); + vm.expectRevert(Error.INVALID_FINAL_DESTINATION.selector); adapter.receiveWormholeMessages( abi.encode(payload), new bytes[](0), TypeCasts.addressToBytes32(senderAdapter), uint16(2), bytes32("1234") @@ -292,13 +309,16 @@ contract WormholeReceiverAdapterTest is Setup { AdapterPayload memory payload = AdapterPayload({ msgId: msgId, senderAdapterCaller: address(42), - receiverAdapter: address(43), + receiverAdapter: address(adapter), finalDestination: receiverAddr, data: abi.encode(message) }); - // NOTE: Forge mangles low level error and doesn't allow checking for partial signature match - vm.expectRevert(); + vm.expectRevert( + abi.encodeWithSelector( + MessageExecutor.MessageFailure.selector, msgId, abi.encodePacked(Error.INVALID_TARGET.selector) + ) + ); adapter.receiveWormholeMessages( abi.encode(payload), new bytes[](0), TypeCasts.addressToBytes32(senderAdapter), uint16(2), bytes32("1234") ); diff --git a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol index 4bbeea2..525af6d 100644 --- a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol @@ -15,9 +15,6 @@ contract WormholeSenderAdapterTest is Setup { bytes32 indexed messageId, address indexed from, uint256 indexed toChainId, address to, bytes data ); - uint256 constant SRC_CHAIN_ID = 1; - uint256 constant DST_CHAIN_ID = 137; - address senderAddr; WormholeSenderAdapter adapter; @@ -98,11 +95,11 @@ contract WormholeSenderAdapterTest is Setup { assertEq(adapter.chainIdMap(DST_CHAIN_ID), 42); } - /// @dev only privileged caller can set chain ID map - function test_set_chain_id_map_only_privileged_caller() public { + /// @dev only global owner can set chain ID map + function test_set_chain_id_map_only_global_owner() public { vm.startPrank(caller); - vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); + vm.expectRevert(Error.CALLER_NOT_OWNER.selector); adapter.setChainIdMap(new uint256[](0), new uint16[](0)); }