From 5dab5e2888c6879fef8d581514764168c02cbd9c Mon Sep 17 00:00:00 2001 From: Dominator008 Date: Tue, 10 Oct 2023 17:17:16 -0700 Subject: [PATCH] Store hash of execution data (#103) * Store hash of execution data Reduces storage gas cost, but requires caller to pass in full execution data. Fixes #35. * Rename and refactor to address comments * Run forge fmt * Nit fixes to address comment --- src/MultiBridgeMessageReceiver.sol | 39 +++++--- src/MultiBridgeMessageSender.sol | 4 +- .../IMultiBridgeMessageReceiver.sol | 18 +--- src/libraries/Error.sol | 3 + src/libraries/Message.sol | 34 +++++++ .../integration-tests/GracePeriodExpiry.t.sol | 24 ++++- .../MultiMessageAggregation.t.sol | 24 ++++- test/integration-tests/RemoteAdapterAdd.t.sol | 44 ++++++--- .../RemoteAdapterRemove.t.sol | 92 +++++++++++-------- test/integration-tests/RemoteSetQuorum.t.sol | 34 +++++-- .../RemoteTimelockUpdate.t.sol | 35 +++++-- test/integration-tests/TimelockCheck.t.sol | 24 ++++- .../MultiBridgeMessageReceiver.t.sol | 77 ++++++++++------ .../unit-tests/MultiBridgeMessageSender.t.sol | 8 +- .../axelar/AxelarReceiverAdapter.t.sol | 17 ++-- .../wormhole/WormholeReceiverAdapter.t.sol | 16 ++-- 16 files changed, 344 insertions(+), 149 deletions(-) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 5df92c0..e852e5d 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -21,6 +21,9 @@ import "./libraries/Message.sol"; /// @dev The contract only accepts messages from trusted bridge receiver adapters, each of which implements the /// IMessageReceiverAdapter interface. contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAware { + using MessageLibrary for MessageLibrary.Message; + using MessageLibrary for MessageLibrary.MessageExecutionParams; + /// @notice the id of the source chain that this contract can receive messages from uint256 public immutable srcChainId; /// @notice the global access control contract @@ -42,8 +45,8 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// @notice count of bridge adapters that have delivered each message mapping(bytes32 msgId => uint256 deliveryCount) public msgDeliveryCount; - /// @notice the data required for executing a message - mapping(bytes32 msgId => ExecutionData execData) public msgExecData; + /// @notice the hash of the params required for executing a message + mapping(bytes32 msgId => bytes32 execParamsHash) public msgExecParamsHash; /// @notice whether a message has been sent to the governance timelock for execution mapping(bytes32 msgId => bool scheduled) public isExecutionScheduled; @@ -114,7 +117,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// this msgId is totally different with each adapters' internal msgId(which is their internal nonce essentially) /// although each adapters' internal msgId is attached at the end of calldata, it's not useful to MultiBridgeMessageReceiver.sol. - bytes32 msgId = MessageLibrary.computeMsgId(_message); + bytes32 msgId = _message.computeMsgId(); if (msgDeliveries[msgId][msg.sender]) { revert Error.DUPLICATE_MESSAGE_DELIVERY_BY_ADAPTER(); @@ -127,17 +130,15 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar msgDeliveries[msgId][msg.sender] = true; - /// increment quorum + /// increment vote count for a message ++msgDeliveryCount[msgId]; - /// stores the execution data required - ExecutionData memory prevStored = msgExecData[msgId]; + /// stores the hash of the execution params required + bytes32 prevStoredHash = msgExecParamsHash[msgId]; /// stores the message if the amb is the first one delivering the message - if (prevStored.target == address(0)) { - msgExecData[msgId] = ExecutionData( - _message.target, _message.callData, _message.nativeValue, _message.nonce, _message.expiration - ); + if (prevStoredHash == bytes32(0)) { + msgExecParamsHash[msgId] = _message.computeExecutionParamsHash(); } string memory bridgeName = IMessageReceiverAdapter(msg.sender).name(); @@ -145,11 +146,17 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } /// @inheritdoc IMultiBridgeMessageReceiver - function scheduleMessageExecution(bytes32 _msgId) external override { - ExecutionData memory _execData = msgExecData[_msgId]; + function scheduleMessageExecution(bytes32 _msgId, MessageLibrary.MessageExecutionParams calldata _execParams) + external + override + { + bytes32 execParamsHash = msgExecParamsHash[_msgId]; + if (_execParams.computeExecutionParamsHash() != execParamsHash) { + revert Error.EXEC_PARAMS_HASH_MISMATCH(); + } /// @dev validates if msg execution is not beyond expiration - if (block.timestamp > _execData.expiration) { + if (block.timestamp > _execParams.expiration) { revert Error.MSG_EXECUTION_PASSED_DEADLINE(); } @@ -167,10 +174,12 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// @dev queues the action on timelock for execution IGovernanceTimelock(governanceTimelock).scheduleTransaction( - _execData.target, _execData.value, _execData.callData + _execParams.target, _execParams.value, _execParams.callData ); - emit MessageExecutionScheduled(_msgId, _execData.target, _execData.value, _execData.nonce, _execData.callData); + emit MessageExecutionScheduled( + _msgId, _execParams.target, _execParams.value, _execParams.nonce, _execParams.callData + ); } /// @notice update the governance timelock contract. diff --git a/src/MultiBridgeMessageSender.sol b/src/MultiBridgeMessageSender.sol index 6a3351c..f5bf467 100644 --- a/src/MultiBridgeMessageSender.sol +++ b/src/MultiBridgeMessageSender.sol @@ -17,6 +17,8 @@ import "./libraries/Error.sol"; /// Both of these are configured in the Global Access Control contract. In the case of Uniswap, both the authorised caller /// and owner should be set to the Uniswap V2 Timelock contract on Ethereum. contract MultiBridgeMessageSender { + using MessageLibrary for MessageLibrary.Message; + /*///////////////////////////////////////////////////////////////// STRUCTS ////////////////////////////////////////////////////////////////*/ @@ -268,7 +270,7 @@ contract MultiBridgeMessageSender { _args.nativeValue, block.timestamp + _args.expiration ); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); (bool[] memory adapterSuccess, uint256 successCount) = _dispatchMessages(adapters, mmaReceiver, _args.dstChainId, message, _args.fees); diff --git a/src/interfaces/IMultiBridgeMessageReceiver.sol b/src/interfaces/IMultiBridgeMessageReceiver.sol index b7dfb1d..f6c91c2 100644 --- a/src/interfaces/IMultiBridgeMessageReceiver.sol +++ b/src/interfaces/IMultiBridgeMessageReceiver.sol @@ -5,20 +5,6 @@ import "../libraries/Message.sol"; /// @notice interface for the multi-bridge message receiver interface IMultiBridgeMessageReceiver { - /// @notice encapsulates data that is relevant to a message's intended transaction execution. - struct ExecutionData { - // target contract address on the destination chain - address target; - // data to pass to target by low-level call - bytes callData; - // value to pass to target by low-level call - uint256 value; - // nonce of the message - uint256 nonce; - // expiration timestamp for the message beyond which it cannot be executed - uint256 expiration; - } - /// @notice emitted when a message has been received from a single bridge. /// @param msgId is the unique identifier of the message /// @param bridgeName is the name of the bridge from which the message was received @@ -60,7 +46,9 @@ interface IMultiBridgeMessageReceiver { /// @notice Sends a message, that has achieved quorum and has not yet expired, to the governance timelock for eventual execution. /// @param _msgId is the unique identifier of the message - function scheduleMessageExecution(bytes32 _msgId) external; + /// @param _execParams are the params for message execution + function scheduleMessageExecution(bytes32 _msgId, MessageLibrary.MessageExecutionParams calldata _execParams) + external; /// @notice adds or removes bridge receiver adapters. /// @param _receiverAdapters the list of receiver adapters to add or remove diff --git a/src/libraries/Error.sol b/src/libraries/Error.sol index dc73ba6..66967b3 100644 --- a/src/libraries/Error.sol +++ b/src/libraries/Error.sol @@ -66,6 +66,9 @@ library Error { /// @dev is thrown if refund address is zero (or) invalid error INVALID_REFUND_ADDRESS(); + /// @dev is thrown if execution params do not match the stored hash + error EXEC_PARAMS_HASH_MISMATCH(); + /*///////////////////////////////////////////////////////////////// ADAPTER ERRORS ////////////////////////////////////////////////////////////////*/ diff --git a/src/libraries/Message.sol b/src/libraries/Message.sol index 8131726..7bf1f69 100644 --- a/src/libraries/Message.sol +++ b/src/libraries/Message.sol @@ -22,6 +22,20 @@ library MessageLibrary { uint256 expiration; } + /// @notice encapsulates data that is relevant to a message's intended transaction execution. + struct MessageExecutionParams { + // target contract address on the destination chain + address target; + // data to pass to target by low-level call + bytes callData; + // value to pass to target by low-level call + uint256 value; + // nonce of the message + uint256 nonce; + // expiration timestamp for the message beyond which it cannot be executed + uint256 expiration; + } + /// @notice computes the message id (32 byte hash of the encoded message parameters) /// @param _message is the cross-chain message function computeMsgId(Message memory _message) internal pure returns (bytes32) { @@ -37,4 +51,24 @@ library MessageLibrary { ) ); } + + function extractExecutionParams(Message memory _message) internal pure returns (MessageExecutionParams memory) { + return MessageExecutionParams({ + target: _message.target, + callData: _message.callData, + value: _message.nativeValue, + nonce: _message.nonce, + expiration: _message.expiration + }); + } + + function computeExecutionParamsHash(MessageExecutionParams memory _params) internal pure returns (bytes32) { + return keccak256( + abi.encodePacked(_params.target, _params.callData, _params.value, _params.nonce, _params.expiration) + ); + } + + function computeExecutionParamsHash(Message memory _message) internal pure returns (bytes32) { + return computeExecutionParamsHash(extractExecutionParams(_message)); + } } diff --git a/test/integration-tests/GracePeriodExpiry.t.sol b/test/integration-tests/GracePeriodExpiry.t.sol index a783ff9..a873409 100644 --- a/test/integration-tests/GracePeriodExpiry.t.sol +++ b/test/integration-tests/GracePeriodExpiry.t.sol @@ -11,6 +11,7 @@ import "test/contracts-mock/MockUniswapReceiver.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -40,11 +41,17 @@ contract GracePeriodExpiryTest is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + bytes memory callData = abi.encode(MockUniswapReceiver.setValue.selector, ""); + uint256 nativeValue = 0; + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, address(target), - abi.encode(MockUniswapReceiver.setValue.selector, ""), - 0, + callData, + nativeValue, EXPIRATION_CONSTANT, refundAddress, fees, @@ -63,7 +70,16 @@ contract GracePeriodExpiryTest is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: address(target), + callData: callData, + value: nativeValue, + nonce: nonce, + expiration: expiration + }) + ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); diff --git a/test/integration-tests/MultiMessageAggregation.t.sol b/test/integration-tests/MultiMessageAggregation.t.sol index f09b6da..94f7eb8 100644 --- a/test/integration-tests/MultiMessageAggregation.t.sol +++ b/test/integration-tests/MultiMessageAggregation.t.sol @@ -11,6 +11,7 @@ import "test/contracts-mock/MockUniswapReceiver.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -40,11 +41,17 @@ contract MultiBridgeMessageAggregationTest is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + bytes memory callData = abi.encode(MockUniswapReceiver.setValue.selector, ""); + uint256 nativeValue = 0; + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, address(target), - abi.encode(MockUniswapReceiver.setValue.selector, ""), - 0, + callData, + nativeValue, EXPIRATION_CONSTANT, refundAddress, fees, @@ -63,7 +70,16 @@ contract MultiBridgeMessageAggregationTest is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: address(target), + callData: callData, + value: nativeValue, + nonce: nonce, + expiration: expiration + }) + ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); diff --git a/test/integration-tests/RemoteAdapterAdd.t.sol b/test/integration-tests/RemoteAdapterAdd.t.sol index 573e16e..3ebcd69 100644 --- a/test/integration-tests/RemoteAdapterAdd.t.sol +++ b/test/integration-tests/RemoteAdapterAdd.t.sol @@ -10,6 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -51,7 +52,7 @@ contract RemoteAdapterAdd is Setup { _adapterAdd(adaptersToAdd, operation); } - function _adapterAdd(address[] memory adaptersToAdd, bool[] memory operation) internal { + function _adapterAdd(address[] memory adaptersToAdd, bool[] memory operation) private { vm.selectFork(fork[ETHEREUM_CHAIN_ID]); vm.startPrank(caller); @@ -65,10 +66,28 @@ contract RemoteAdapterAdd is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + _sendAndExecuteMessage(adaptersToAdd, operation, fees); + + for (uint256 j; j < adaptersToAdd.length; ++j) { + bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) + .isTrustedExecutor(adaptersToAdd[j]); + assert(isTrusted); + } + } + + function _sendAndExecuteMessage(address[] memory adaptersToAdd, bool[] memory operation, uint256[] memory fees) + private + { + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + bytes memory callData = + abi.encodeWithSelector(MultiBridgeMessageReceiver.updateReceiverAdapters.selector, adaptersToAdd, operation); + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, - address(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]), - abi.encodeWithSelector(MultiBridgeMessageReceiver.updateReceiverAdapters.selector, adaptersToAdd, operation), + contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")], + callData, 0, EXPIRATION_CONSTANT, refundAddress, @@ -88,7 +107,16 @@ contract RemoteAdapterAdd is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")], + callData: callData, + value: 0, + nonce: nonce, + expiration: expiration + }) + ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); @@ -97,11 +125,5 @@ contract RemoteAdapterAdd is Setup { GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( txId, finalTarget, value, data, eta ); - - for (uint256 j; j < adaptersToAdd.length; ++j) { - bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) - .isTrustedExecutor(adaptersToAdd[j]); - assert(isTrusted); - } } } diff --git a/test/integration-tests/RemoteAdapterRemove.t.sol b/test/integration-tests/RemoteAdapterRemove.t.sol index d5f2011..cd6ca7d 100644 --- a/test/integration-tests/RemoteAdapterRemove.t.sol +++ b/test/integration-tests/RemoteAdapterRemove.t.sol @@ -10,6 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -70,15 +71,52 @@ contract RemoteAdapterRemove is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + _sendAndExecuteMessage(newQuorum, adaptersToRemove, operation, fees); + + /// @dev validates quorum post update + assertEq(MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(), newQuorum); + + /// @dev validates adapters post update + for (uint256 j; j < adaptersToRemove.length; ++j) { + bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) + .isTrustedExecutor(adaptersToRemove[j]); + assert(!isTrusted); + } + } + + function _updateDummy() private { + address[] memory newDummyAdapter = new address[](1); + newDummyAdapter[0] = address(420); + + /// true = add + /// false = remove + bool[] memory operation = new bool[](1); + operation[0] = true; + + vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]).updateReceiverAdapters( + newDummyAdapter, operation + ); + vm.stopPrank(); + } + + function _sendAndExecuteMessage( + uint256 newQuorum, + address[] memory adaptersToRemove, + bool[] memory operation, + uint256[] memory fees + ) private { + bytes memory callData = abi.encodeWithSelector( + MultiBridgeMessageReceiver.updateReceiverAdaptersAndQuorum.selector, adaptersToRemove, operation, newQuorum + ); + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, - address(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]), - abi.encodeWithSelector( - MultiBridgeMessageReceiver.updateReceiverAdaptersAndQuorum.selector, - adaptersToRemove, - operation, - newQuorum - ), + contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")], + callData, 0, EXPIRATION_CONSTANT, refundAddress, @@ -98,7 +136,16 @@ contract RemoteAdapterRemove is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")], + callData: callData, + value: 0, + nonce: nonce, + expiration: expiration + }) + ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); @@ -107,32 +154,5 @@ contract RemoteAdapterRemove is Setup { GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( txId, finalTarget, value, data, eta ); - - /// @dev validates quorum post update - uint256 currQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); - assertEq(currQuorum, newQuorum); - - /// @dev validates adapters post update - for (uint256 j; j < adaptersToRemove.length; ++j) { - bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) - .isTrustedExecutor(adaptersToRemove[j]); - assert(!isTrusted); - } - } - - function _updateDummy() internal { - address[] memory newDummyAdapter = new address[](1); - newDummyAdapter[0] = address(420); - - /// true = add - /// false = remove - bool[] memory operation = new bool[](1); - operation[0] = true; - - vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]).updateReceiverAdapters( - newDummyAdapter, operation - ); - vm.stopPrank(); } } diff --git a/test/integration-tests/RemoteSetQuorum.t.sol b/test/integration-tests/RemoteSetQuorum.t.sol index ac10f04..5721de8 100644 --- a/test/integration-tests/RemoteSetQuorum.t.sol +++ b/test/integration-tests/RemoteSetQuorum.t.sol @@ -10,6 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -37,10 +38,23 @@ contract RemoteQuorumUpdate is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + _sendAndExecuteMessage(newQuorum, fees); + + uint256 currQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); + assertEq(currQuorum, newQuorum); + } + + function _sendAndExecuteMessage(uint256 newQuorum, uint256[] memory fees) private { + address receiverAddr = contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]; + bytes memory callData = abi.encodeWithSelector(MultiBridgeMessageReceiver.updateQuorum.selector, newQuorum); + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, - address(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]), - abi.encodeWithSelector(MultiBridgeMessageReceiver.updateQuorum.selector, newQuorum), + receiverAddr, + callData, 0, EXPIRATION_CONSTANT, refundAddress, @@ -61,7 +75,16 @@ contract RemoteQuorumUpdate is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution(msgId); + MultiBridgeMessageReceiver(receiverAddr).scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: receiverAddr, + callData: callData, + value: 0, + nonce: nonce, + expiration: expiration + }) + ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); @@ -73,8 +96,5 @@ contract RemoteQuorumUpdate is Setup { GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( txId, finalTarget, value, data, eta ); - - uint256 currQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); - assertEq(currQuorum, newQuorum); } } diff --git a/test/integration-tests/RemoteTimelockUpdate.t.sol b/test/integration-tests/RemoteTimelockUpdate.t.sol index 4c1bb28..2b04b71 100644 --- a/test/integration-tests/RemoteTimelockUpdate.t.sol +++ b/test/integration-tests/RemoteTimelockUpdate.t.sol @@ -10,6 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -37,11 +38,25 @@ contract RemoteTimelockUpdate is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + _sendAndExecuteMessage(newDelay, fees); + + uint256 currDelay = GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).delay(); + assertEq(currDelay, newDelay); + } + + function _sendAndExecuteMessage(uint256 newDelay, uint256[] memory fees) private { + address timelockAddr = contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]; + bytes memory callData = abi.encodeWithSelector(GovernanceTimelock.setDelay.selector, newDelay); + uint256 nativeValue = 0; + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + sender.remoteCall{value: 2 ether}( POLYGON_CHAIN_ID, - address(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]), - abi.encodeWithSelector(GovernanceTimelock.setDelay.selector, newDelay), - 0, + timelockAddr, + callData, + nativeValue, EXPIRATION_CONSTANT, refundAddress, fees, @@ -62,7 +77,14 @@ contract RemoteTimelockUpdate is Setup { vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract MultiBridgeMessageReceiver(contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( - msgId + msgId, + MessageLibrary.MessageExecutionParams({ + target: timelockAddr, + callData: callData, + value: nativeValue, + nonce: nonce, + expiration: expiration + }) ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); @@ -75,8 +97,5 @@ contract RemoteTimelockUpdate is Setup { GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( txId, finalTarget, value, data, eta ); - - uint256 currDelay = GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).delay(); - assertEq(currDelay, newDelay); } } diff --git a/test/integration-tests/TimelockCheck.t.sol b/test/integration-tests/TimelockCheck.t.sol index 1a4891d..bc78d06 100644 --- a/test/integration-tests/TimelockCheck.t.sol +++ b/test/integration-tests/TimelockCheck.t.sol @@ -11,6 +11,7 @@ import "test/contracts-mock/MockUniswapReceiver.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -42,11 +43,17 @@ contract TimelockCheckTest is Setup { 0.01 ether, wormholeFee ); - MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + + bytes memory callData = abi.encode(MockUniswapReceiver.setValue.selector, ""); + uint256 nativeValue = 0; + uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + uint256 nonce = sender.nonce() + 1; + sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, address(target), - abi.encode(MockUniswapReceiver.setValue.selector, ""), - 0, + callData, + nativeValue, EXPIRATION_CONSTANT, refundAddress, fees, @@ -65,7 +72,16 @@ contract TimelockCheckTest is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: address(target), + callData: callData, + value: nativeValue, + nonce: nonce, + expiration: expiration + }) + ); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); diff --git a/test/unit-tests/MultiBridgeMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol index 2572d85..184c5b4 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -10,8 +10,11 @@ import "src/adapters/wormhole/WormholeReceiverAdapter.sol"; import "src/libraries/Error.sol"; import "src/libraries/Message.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; +import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; contract MultiBridgeMessageReceiverTest is Setup { + using MessageLibrary for MessageLibrary.Message; + event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); event QuorumUpdated(uint64 oldValue, uint64 newValue); event GovernanceTimelockUpdated(address oldTimelock, address newTimelock); @@ -62,7 +65,12 @@ contract MultiBridgeMessageReceiverTest is Setup { receiverAdapters[0] = address(43); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new MultiBridgeMessageReceiver(SRC_CHAIN_ID, address(0), receiverAdapters, 1); + new MultiBridgeMessageReceiver( + SRC_CHAIN_ID, + address(0), + receiverAdapters, + 1 + ); } /// @dev cannot be called with receiver adapters containing zero address @@ -71,7 +79,12 @@ contract MultiBridgeMessageReceiverTest is Setup { receiverAdapters[0] = address(0); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new MultiBridgeMessageReceiver(SRC_CHAIN_ID, address(42), receiverAdapters, 1); + new MultiBridgeMessageReceiver( + SRC_CHAIN_ID, + address(42), + receiverAdapters, + 1 + ); } /// @dev cannot be called with zero quorum @@ -80,7 +93,12 @@ contract MultiBridgeMessageReceiverTest is Setup { receiverAdapters[0] = address(42); vm.expectRevert(Error.INVALID_QUORUM_THRESHOLD.selector); - new MultiBridgeMessageReceiver(SRC_CHAIN_ID, address(43), receiverAdapters, 0); + new MultiBridgeMessageReceiver( + SRC_CHAIN_ID, + address(43), + receiverAdapters, + 0 + ); } /// @dev cannot be called with quorum too large @@ -89,7 +107,12 @@ contract MultiBridgeMessageReceiverTest is Setup { receiverAdapters[0] = address(42); vm.expectRevert(Error.INVALID_QUORUM_THRESHOLD.selector); - new MultiBridgeMessageReceiver(SRC_CHAIN_ID, address(43), receiverAdapters, 2); + new MultiBridgeMessageReceiver( + SRC_CHAIN_ID, + address(43), + receiverAdapters, + 2 + ); } /// @dev receives message from one adapter @@ -105,7 +128,7 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); vm.expectEmit(true, true, true, true, address(receiver)); emit BridgeMessageReceived(msgId, "WORMHOLE", 42, wormholeAdapterAddr); @@ -118,13 +141,7 @@ contract MultiBridgeMessageReceiverTest is Setup { assertEq(receiver.msgDeliveryCount(msgId), 1); - (address target, bytes memory callData, uint256 nativeValue, uint256 nonce, uint256 expiration) = - receiver.msgExecData(msgId); - assertEq(target, message.target); - assertEq(callData, message.callData); - assertEq(nativeValue, message.nativeValue); - assertEq(nonce, message.nonce); - assertEq(expiration, message.expiration); + assertEq(receiver.msgExecParamsHash(msgId), message.computeExecutionParamsHash()); } /// @dev receives message from two adapters @@ -140,7 +157,7 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); @@ -253,7 +270,7 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); // Reduce quorum first vm.startPrank(address(timelockAddr)); @@ -262,7 +279,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(wormholeAdapterAddr); receiver.receiveMessage(message); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); vm.startPrank(axelarAdapterAddr); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); @@ -282,7 +299,7 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); @@ -292,8 +309,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.expectEmit(true, true, true, true, address(receiver)); emit MessageExecutionScheduled(msgId, address(42), 0, 42, bytes("42")); - receiver.scheduleMessageExecution(msgId); - + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); assertTrue(receiver.isExecutionScheduled(msgId)); } @@ -310,12 +326,12 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: 0 }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); vm.expectRevert(Error.MSG_EXECUTION_PASSED_DEADLINE.selector); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); } /// @dev cannot schedule execution of message that has already been scheduled @@ -331,17 +347,26 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); vm.startPrank(axelarAdapterAddr); receiver.receiveMessage(message); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution( + msgId, + MessageLibrary.MessageExecutionParams({ + target: message.target, + callData: message.callData, + value: message.nativeValue, + nonce: message.nonce, + expiration: message.expiration + }) + ); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); } /// @dev cannot schedule message execution without quorum @@ -357,12 +382,12 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); vm.expectRevert(Error.QUORUM_NOT_ACHIEVED.selector); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); } /// @dev updates governance timelock @@ -666,7 +691,7 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); diff --git a/test/unit-tests/MultiBridgeMessageSender.t.sol b/test/unit-tests/MultiBridgeMessageSender.t.sol index 5e4fa4e..a61f997 100644 --- a/test/unit-tests/MultiBridgeMessageSender.t.sol +++ b/test/unit-tests/MultiBridgeMessageSender.t.sol @@ -17,6 +17,8 @@ import "src/libraries/Message.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; contract MultiBridgeMessageSenderTest is Setup { + using MessageLibrary for MessageLibrary.Message; + event MultiBridgeMessageSent( bytes32 indexed msgId, uint256 nonce, @@ -86,7 +88,7 @@ contract MultiBridgeMessageSenderTest is Setup { nativeValue: 0, expiration: block.timestamp + expiration }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); vm.expectEmit(true, true, true, true, address(sender)); emit MultiBridgeMessageSent( @@ -161,7 +163,7 @@ contract MultiBridgeMessageSenderTest is Setup { nativeValue: 0, expiration: block.timestamp + EXPIRATION_CONSTANT }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); uint256[] memory fees = new uint256[](1); (uint256 wormholeFee,) = IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice( @@ -539,7 +541,7 @@ contract MultiBridgeMessageSenderTest is Setup { nativeValue: 0, expiration: block.timestamp + expiration }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); vm.expectEmit(true, true, true, true, address(sender)); emit MessageSendFailed(failingAdapterAddr, message); diff --git a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol index 96e6d35..b03c10f 100644 --- a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol @@ -16,6 +16,7 @@ import "src/libraries/Types.sol"; import {AxelarReceiverAdapter} from "src/adapters/axelar/AxelarReceiverAdapter.sol"; contract AxelarReceiverAdapterTest is Setup { + using MessageLibrary for MessageLibrary.Message; using StringAddressConversion for address; event MessageIdExecuted(uint256 indexed fromChainId, bytes32 indexed messageId); @@ -105,7 +106,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -137,7 +138,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -164,7 +165,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -191,7 +192,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -218,7 +219,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -247,7 +248,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -274,7 +275,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -301,7 +302,7 @@ contract AxelarReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, diff --git a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol index 6ac06b8..66da381 100644 --- a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol @@ -15,6 +15,8 @@ import "src/libraries/TypeCasts.sol"; import {WormholeReceiverAdapter} from "src/adapters/wormhole/WormholeReceiverAdapter.sol"; contract WormholeReceiverAdapterTest is Setup { + using MessageLibrary for MessageLibrary.Message; + event MessageIdExecuted(uint256 indexed fromChainId, bytes32 indexed messageId); event SenderAdapterUpdated(address indexed oldSenderAdapter, address indexed newSenderAdapter); @@ -104,7 +106,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -140,7 +142,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -170,7 +172,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -201,7 +203,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -234,7 +236,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -264,7 +266,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId, @@ -295,7 +297,7 @@ contract WormholeReceiverAdapterTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); AdapterPayload memory payload = AdapterPayload({ msgId: msgId,