From d22798fa3953cf76df5e7d7b76e323985f850a9c Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Mon, 9 Oct 2023 13:09:06 -0700 Subject: [PATCH 1/4] Store hash of execution data Reduces storage gas cost, but requires caller to pass in full execution data. Fixes #35. --- src/MultiBridgeMessageReceiver.sol | 29 +++-- .../IMultiBridgeMessageReceiver.sol | 2 +- src/libraries/Error.sol | 3 + .../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 | 110 +++++++++++++++--- 11 files changed, 320 insertions(+), 101 deletions(-) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 5df92c0..584a365 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -42,8 +42,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 data required for executing a message + mapping(bytes32 msgId => bytes32 execDataHash) public msgExecDataHash; /// @notice whether a message has been sent to the governance timelock for execution mapping(bytes32 msgId => bool scheduled) public isExecutionScheduled; @@ -130,13 +130,15 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// increment quorum ++msgDeliveryCount[msgId]; - /// stores the execution data required - ExecutionData memory prevStored = msgExecData[msgId]; + /// stores the hash of the execution data required + bytes32 prevStoredHash = msgExecDataHash[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)) { + msgExecDataHash[msgId] = keccak256( + abi.encodePacked( + _message.target, _message.callData, _message.nativeValue, _message.nonce, _message.expiration + ) ); } @@ -145,8 +147,17 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } /// @inheritdoc IMultiBridgeMessageReceiver - function scheduleMessageExecution(bytes32 _msgId) external override { - ExecutionData memory _execData = msgExecData[_msgId]; + function scheduleMessageExecution(bytes32 _msgId, ExecutionData calldata _execData) external override { + bytes32 execDataHash = msgExecDataHash[_msgId]; + if ( + keccak256( + abi.encodePacked( + _execData.target, _execData.callData, _execData.value, _execData.nonce, _execData.expiration + ) + ) != execDataHash + ) { + revert Error.EXEC_DATA_HASH_MISMATCH(); + } /// @dev validates if msg execution is not beyond expiration if (block.timestamp > _execData.expiration) { diff --git a/src/interfaces/IMultiBridgeMessageReceiver.sol b/src/interfaces/IMultiBridgeMessageReceiver.sol index b7dfb1d..8df4b91 100644 --- a/src/interfaces/IMultiBridgeMessageReceiver.sol +++ b/src/interfaces/IMultiBridgeMessageReceiver.sol @@ -60,7 +60,7 @@ 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; + function scheduleMessageExecution(bytes32 _msgId, ExecutionData calldata _execData) 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..de5b436 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 data does not match the stored hash + error EXEC_DATA_HASH_MISMATCH(); + /*///////////////////////////////////////////////////////////////// ADAPTER ERRORS ////////////////////////////////////////////////////////////////*/ diff --git a/test/integration-tests/GracePeriodExpiry.t.sol b/test/integration-tests/GracePeriodExpiry.t.sol index a783ff9..4bbf38c 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..e0339f5 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..f2a49b7 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..aa8a023 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..191bd6b 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..c9f570e 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..9fd66fa 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 {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.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, + IMultiBridgeMessageReceiver.ExecutionData({ + 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..4f30dc1 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -10,6 +10,7 @@ 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 { event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); @@ -62,7 +63,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 +77,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 +91,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 +105,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 @@ -118,13 +139,14 @@ 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.msgExecDataHash(msgId), + keccak256( + abi.encodePacked( + message.target, message.callData, message.nativeValue, message.nonce, message.expiration + ) + ) + ); } /// @dev receives message from two adapters @@ -262,7 +284,16 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(wormholeAdapterAddr); receiver.receiveMessage(message); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution( + msgId, + IMultiBridgeMessageReceiver.ExecutionData({ + target: message.target, + callData: message.callData, + value: message.nativeValue, + nonce: message.nonce, + expiration: message.expiration + }) + ); vm.startPrank(axelarAdapterAddr); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); @@ -292,7 +323,16 @@ 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, + IMultiBridgeMessageReceiver.ExecutionData({ + target: message.target, + callData: message.callData, + value: message.nativeValue, + nonce: message.nonce, + expiration: message.expiration + }) + ); assertTrue(receiver.isExecutionScheduled(msgId)); } @@ -315,7 +355,16 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.receiveMessage(message); vm.expectRevert(Error.MSG_EXECUTION_PASSED_DEADLINE.selector); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution( + msgId, + IMultiBridgeMessageReceiver.ExecutionData({ + target: message.target, + callData: message.callData, + value: message.nativeValue, + nonce: message.nonce, + expiration: message.expiration + }) + ); } /// @dev cannot schedule execution of message that has already been scheduled @@ -338,10 +387,28 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(axelarAdapterAddr); receiver.receiveMessage(message); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution( + msgId, + IMultiBridgeMessageReceiver.ExecutionData({ + 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, + IMultiBridgeMessageReceiver.ExecutionData({ + target: message.target, + callData: message.callData, + value: message.nativeValue, + nonce: message.nonce, + expiration: message.expiration + }) + ); } /// @dev cannot schedule message execution without quorum @@ -362,7 +429,16 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.receiveMessage(message); vm.expectRevert(Error.QUORUM_NOT_ACHIEVED.selector); - receiver.scheduleMessageExecution(msgId); + receiver.scheduleMessageExecution( + msgId, + IMultiBridgeMessageReceiver.ExecutionData({ + target: message.target, + callData: message.callData, + value: message.nativeValue, + nonce: message.nonce, + expiration: message.expiration + }) + ); } /// @dev updates governance timelock From bbcc51bd08018d4cb27639fddd5b03b22920818f Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 10 Oct 2023 09:46:39 -0700 Subject: [PATCH 2/4] Rename and refactor to address comments --- src/MultiBridgeMessageReceiver.sol | 129 ++++++++++------ .../IMultiBridgeMessageReceiver.sol | 41 ++--- src/libraries/Error.sol | 4 +- src/libraries/Message.sol | 75 ++++++++-- .../integration-tests/GracePeriodExpiry.t.sol | 51 ++++--- .../MultiMessageAggregation.t.sol | 51 ++++--- test/integration-tests/RemoteAdapterAdd.t.sol | 73 +++++---- .../RemoteAdapterRemove.t.sol | 89 +++++++---- test/integration-tests/RemoteSetQuorum.t.sol | 50 +++++-- .../RemoteTimelockUpdate.t.sol | 70 +++++---- test/integration-tests/TimelockCheck.t.sol | 56 ++++--- .../MultiBridgeMessageReceiver.t.sol | 141 ++++++++++-------- 12 files changed, 533 insertions(+), 297 deletions(-) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 584a365..9cd0d70 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -20,7 +20,10 @@ import "./libraries/Message.sol"; /// governance timelock contract. /// @dev The contract only accepts messages from trusted bridge receiver adapters, each of which implements the /// IMessageReceiverAdapter interface. -contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAware { +contract MultiBridgeMessageReceiver is + IMultiBridgeMessageReceiver, + ExecutorAware +{ /// @notice the id of the source chain that this contract can receive messages from uint256 public immutable srcChainId; /// @notice the global access control contract @@ -37,13 +40,14 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar address public governanceTimelock; /// @notice maintains which bridge adapters have delivered each message - mapping(bytes32 msgId => mapping(address receiverAdapter => bool delivered)) public msgDeliveries; + mapping(bytes32 msgId => mapping(address receiverAdapter => bool delivered)) + public msgDeliveries; /// @notice count of bridge adapters that have delivered each message mapping(bytes32 msgId => uint256 deliveryCount) public msgDeliveryCount; - /// @notice the hash of the data required for executing a message - mapping(bytes32 msgId => bytes32 execDataHash) public msgExecDataHash; + /// @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; @@ -73,7 +77,12 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar ////////////////////////////////////////////////////////////////*/ /// @notice sets the initial parameters - constructor(uint256 _srcChainId, address _gac, address[] memory _receiverAdapters, uint64 _quorum) { + constructor( + uint256 _srcChainId, + address _gac, + address[] memory _receiverAdapters, + uint64 _quorum + ) { if (_srcChainId == 0) { revert Error.INVALID_SENDER_CHAIN_ID(); } @@ -84,7 +93,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar srcChainId = _srcChainId; gac = IGAC(_gac); - for (uint256 i; i < _receiverAdapters.length;) { + for (uint256 i; i < _receiverAdapters.length; ) { _updateReceiverAdapter(_receiverAdapters[i], true); unchecked { ++i; @@ -99,7 +108,9 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// @notice receive messages from allowed bridge receiver adapters /// @param _message is the crosschain message sent by the mma sender - function receiveMessage(MessageLibrary.Message calldata _message) external override onlyReceiverAdapter { + function receiveMessage( + MessageLibrary.Message calldata _message + ) external override onlyReceiverAdapter { if (_message.dstChainId != block.chainid) { revert Error.INVALID_DST_CHAIN(); } @@ -127,40 +138,42 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar msgDeliveries[msgId][msg.sender] = true; - /// increment quorum + /// increment vote count for a message ++msgDeliveryCount[msgId]; - /// stores the hash of the execution data required - bytes32 prevStoredHash = msgExecDataHash[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 (prevStoredHash == bytes32(0)) { - msgExecDataHash[msgId] = keccak256( - abi.encodePacked( - _message.target, _message.callData, _message.nativeValue, _message.nonce, _message.expiration - ) - ); + msgExecParamsHash[msgId] = MessageLibrary + .computeExecutionParamsHash(_message); } string memory bridgeName = IMessageReceiverAdapter(msg.sender).name(); - emit BridgeMessageReceived(msgId, bridgeName, _message.nonce, msg.sender); + emit BridgeMessageReceived( + msgId, + bridgeName, + _message.nonce, + msg.sender + ); } /// @inheritdoc IMultiBridgeMessageReceiver - function scheduleMessageExecution(bytes32 _msgId, ExecutionData calldata _execData) external override { - bytes32 execDataHash = msgExecDataHash[_msgId]; + function scheduleMessageExecution( + bytes32 _msgId, + MessageLibrary.MessageExecutionParams calldata _execParams + ) external override { + bytes32 execParamsHash = msgExecParamsHash[_msgId]; if ( - keccak256( - abi.encodePacked( - _execData.target, _execData.callData, _execData.value, _execData.nonce, _execData.expiration - ) - ) != execDataHash + MessageLibrary.computeExecutionParamsHash(_execParams) != + execParamsHash ) { - revert Error.EXEC_DATA_HASH_MISMATCH(); + 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(); } @@ -178,30 +191,42 @@ 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. /// @dev called by admin to update the timelock contract - function updateGovernanceTimelock(address _governanceTimelock) external onlyGlobalOwner { + function updateGovernanceTimelock( + address _governanceTimelock + ) external onlyGlobalOwner { if (_governanceTimelock == address(0)) { revert Error.ZERO_GOVERNANCE_TIMELOCK(); } address oldGovernanceTimelock = governanceTimelock; governanceTimelock = _governanceTimelock; - emit GovernanceTimelockUpdated(oldGovernanceTimelock, _governanceTimelock); + emit GovernanceTimelockUpdated( + oldGovernanceTimelock, + _governanceTimelock + ); } /// @notice Update bridge receiver adapters. /// @dev called by admin to update receiver bridge adapters on all other chains - function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) - external - override - onlyGlobalOwner - { + function updateReceiverAdapters( + address[] calldata _receiverAdapters, + bool[] calldata _operations + ) external override onlyGlobalOwner { _updateReceiverAdapters(_receiverAdapters, _operations); _validateQuorum(quorum); } @@ -230,16 +255,20 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// @return isExecutionScheduled is true if the message has been sent to the timelock for execution /// @return msgCurrentVotes is the number of bridges that have delivered the message /// @return successfulBridge is the list of bridges that have delivered the message - function getMessageInfo(bytes32 _msgId) public view returns (bool, uint256, string[] memory) { + function getMessageInfo( + bytes32 _msgId + ) public view returns (bool, uint256, string[] memory) { uint256 msgCurrentVotes = msgDeliveryCount[_msgId]; string[] memory successfulBridge = new string[](msgCurrentVotes); if (msgCurrentVotes != 0) { uint256 currIndex; address[] memory executors = getTrustedExecutors(); - for (uint256 i; i < executors.length;) { + for (uint256 i; i < executors.length; ) { if (msgDeliveries[_msgId][executors[i]]) { - successfulBridge[currIndex] = IMessageReceiverAdapter(executors[i]).name(); + successfulBridge[currIndex] = IMessageReceiverAdapter( + executors[i] + ).name(); ++currIndex; } @@ -249,7 +278,11 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } } - return (isExecutionScheduled[_msgId], msgCurrentVotes, successfulBridge); + return ( + isExecutionScheduled[_msgId], + msgCurrentVotes, + successfulBridge + ); } /*///////////////////////////////////////////////////////////////// @@ -265,7 +298,10 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar emit QuorumUpdated(oldValue, _quorum); } - function _updateReceiverAdapters(address[] memory _receiverAdapters, bool[] memory _operations) private { + function _updateReceiverAdapters( + address[] memory _receiverAdapters, + bool[] memory _operations + ) private { uint256 len = _receiverAdapters.length; if (len == 0) { @@ -276,7 +312,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar revert Error.ARRAY_LENGTH_MISMATCHED(); } - for (uint256 i; i < len;) { + for (uint256 i; i < len; ) { _updateReceiverAdapter(_receiverAdapters[i], _operations[i]); unchecked { @@ -285,15 +321,22 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } } - function _updateReceiverAdapter(address _receiverAdapter, bool _add) private { + function _updateReceiverAdapter( + address _receiverAdapter, + bool _add + ) private { if (_receiverAdapter == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - bool success = _add ? _addTrustedExecutor(_receiverAdapter) : _removeTrustedExecutor(_receiverAdapter); + bool success = _add + ? _addTrustedExecutor(_receiverAdapter) + : _removeTrustedExecutor(_receiverAdapter); if (!success) { // only fails because we are either attempting to add an existing adapter, or remove a non-existing adapter - revert Error.UPDATE_RECEIVER_ADAPTER_FAILED(_add ? "adapter already added" : "adapter not found"); + revert Error.UPDATE_RECEIVER_ADAPTER_FAILED( + _add ? "adapter already added" : "adapter not found" + ); } emit BridgeReceiverAdapterUpdated(_receiverAdapter, _add); diff --git a/src/interfaces/IMultiBridgeMessageReceiver.sol b/src/interfaces/IMultiBridgeMessageReceiver.sol index 8df4b91..99d10e6 100644 --- a/src/interfaces/IMultiBridgeMessageReceiver.sol +++ b/src/interfaces/IMultiBridgeMessageReceiver.sol @@ -5,27 +5,16 @@ 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 /// @param nonce is the nonce of the message /// @param receiverAdapter is the address of the receiver adapter that received the message event BridgeMessageReceived( - bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter + bytes32 indexed msgId, + string indexed bridgeName, + uint256 nonce, + address receiverAdapter ); /// @notice emitted when a message has been queued for execution in the destination timelock contract. @@ -35,13 +24,20 @@ interface IMultiBridgeMessageReceiver { /// @param nonce is the nonce of the message /// @param callData is the data that will be passed to the target address through low-level call event MessageExecutionScheduled( - bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData + bytes32 indexed msgId, + address indexed target, + uint256 nativeValue, + uint256 nonce, + bytes callData ); /// @notice emitted when receiver adapter of a specific bridge is updated. /// @param receiverAdapter is the new receiver adapter address /// @param add is true if the receiver adapter was added, false if removed - event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); + event BridgeReceiverAdapterUpdated( + address indexed receiverAdapter, + bool add + ); /// @notice emitted when the quorum for message validity is updated. /// @param oldQuorum is the old quorum value @@ -60,12 +56,19 @@ 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, ExecutionData calldata _execData) 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 /// @param _operations the list of operations to perform for corresponding receiver adapters, true for add, false for remove - function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) external; + function updateReceiverAdapters( + address[] calldata _receiverAdapters, + bool[] calldata _operations + ) external; /// @notice updates the quorum for message validity, which is the number of bridges that must deliver the message for it to be considered valid. /// @param _quorum is the new quorum value diff --git a/src/libraries/Error.sol b/src/libraries/Error.sol index de5b436..66967b3 100644 --- a/src/libraries/Error.sol +++ b/src/libraries/Error.sol @@ -66,8 +66,8 @@ library Error { /// @dev is thrown if refund address is zero (or) invalid error INVALID_REFUND_ADDRESS(); - /// @dev is thrown if execution data does not match the stored hash - error EXEC_DATA_HASH_MISMATCH(); + /// @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..c47050c 100644 --- a/src/libraries/Message.sol +++ b/src/libraries/Message.sol @@ -22,19 +22,70 @@ 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) { - return keccak256( - abi.encodePacked( - _message.srcChainId, - _message.dstChainId, - _message.nonce, - _message.target, - _message.nativeValue, - _message.expiration, - _message.callData - ) - ); + function computeMsgId( + Message memory _message + ) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked( + _message.srcChainId, + _message.dstChainId, + _message.nonce, + _message.target, + _message.nativeValue, + _message.expiration, + _message.callData + ) + ); + } + + 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 4bbf38c..5f9e02b 100644 --- a/test/integration-tests/GracePeriodExpiry.t.sol +++ b/test/integration-tests/GracePeriodExpiry.t.sol @@ -11,7 +11,7 @@ import "test/contracts-mock/MockUniswapReceiver.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -33,8 +33,8 @@ contract GracePeriodExpiryTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -42,10 +42,15 @@ contract GracePeriodExpiryTest is Setup { wormholeFee ); - bytes memory callData = abi.encode(MockUniswapReceiver.setValue.selector, ""); + 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")]); + MultiBridgeMessageSender sender = MultiBridgeMessageSender( + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] + ); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -70,25 +75,31 @@ 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, - IMultiBridgeMessageReceiver.ExecutionData({ - 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()); + 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()); /// increment the time by 21 day (beyond expiry, delay) /// @notice should revert here with TX_EXPIRED error vm.warp(block.timestamp + 21 days); vm.expectRevert(Error.TX_EXPIRED.selector); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); } } diff --git a/test/integration-tests/MultiMessageAggregation.t.sol b/test/integration-tests/MultiMessageAggregation.t.sol index e0339f5..eb159c2 100644 --- a/test/integration-tests/MultiMessageAggregation.t.sol +++ b/test/integration-tests/MultiMessageAggregation.t.sol @@ -11,7 +11,7 @@ import "test/contracts-mock/MockUniswapReceiver.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -33,8 +33,8 @@ contract MultiBridgeMessageAggregationTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -42,10 +42,15 @@ contract MultiBridgeMessageAggregationTest is Setup { wormholeFee ); - bytes memory callData = abi.encode(MockUniswapReceiver.setValue.selector, ""); + 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")]); + MultiBridgeMessageSender sender = MultiBridgeMessageSender( + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] + ); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -70,24 +75,30 @@ 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, - IMultiBridgeMessageReceiver.ExecutionData({ - 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()); + 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()); /// increment the time by 7 days (delay time) vm.warp(block.timestamp + 7 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); assertEq(target.i(), type(uint256).max); } } diff --git a/test/integration-tests/RemoteAdapterAdd.t.sol b/test/integration-tests/RemoteAdapterAdd.t.sol index f2a49b7..f33948b 100644 --- a/test/integration-tests/RemoteAdapterAdd.t.sol +++ b/test/integration-tests/RemoteAdapterAdd.t.sol @@ -10,7 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -52,14 +52,17 @@ contract RemoteAdapterAdd is Setup { _adapterAdd(adaptersToAdd, operation); } - function _adapterAdd(address[] memory adaptersToAdd, bool[] memory operation) private { + function _adapterAdd( + address[] memory adaptersToAdd, + bool[] memory operation + ) private { vm.selectFork(fork[ETHEREUM_CHAIN_ID]); vm.startPrank(caller); /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -70,19 +73,27 @@ contract RemoteAdapterAdd is Setup { _sendAndExecuteMessage(adaptersToAdd, operation, fees); for (uint256 j; j < adaptersToAdd.length; ++j) { - bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) - .isTrustedExecutor(adaptersToAdd[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")]); + 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); + bytes memory callData = abi.encodeWithSelector( + MultiBridgeMessageReceiver.updateReceiverAdapters.selector, + adaptersToAdd, + operation + ); uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -107,23 +118,31 @@ 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, - IMultiBridgeMessageReceiver.ExecutionData({ - 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()); + 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()); /// increment the time by 3 days (delay time) vm.warp(block.timestamp + 3 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); } } diff --git a/test/integration-tests/RemoteAdapterRemove.t.sol b/test/integration-tests/RemoteAdapterRemove.t.sol index aa8a023..92bc873 100644 --- a/test/integration-tests/RemoteAdapterRemove.t.sol +++ b/test/integration-tests/RemoteAdapterRemove.t.sol @@ -10,7 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -25,7 +25,9 @@ contract RemoteAdapterRemove is Setup { /// @dev just remove one adapter and assert function test_remoteRemoveReceiverAdapterSingle() public { address[] memory adaptersToRemove = new address[](1); - adaptersToRemove[0] = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; + adaptersToRemove[0] = contractAddress[DST_CHAIN_ID][ + "AXELAR_RECEIVER_ADAPTER" + ]; /// true = add /// false = remove @@ -43,8 +45,12 @@ contract RemoteAdapterRemove is Setup { _updateDummy(); address[] memory adaptersToRemove = new address[](2); - adaptersToRemove[0] = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; - adaptersToRemove[1] = contractAddress[DST_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]; + adaptersToRemove[0] = contractAddress[DST_CHAIN_ID][ + "AXELAR_RECEIVER_ADAPTER" + ]; + adaptersToRemove[1] = contractAddress[DST_CHAIN_ID][ + "WORMHOLE_RECEIVER_ADAPTER" + ]; /// true = add /// false = remove @@ -57,14 +63,18 @@ contract RemoteAdapterRemove is Setup { _adapterRemove(newQuorum, adaptersToRemove, operation); } - function _adapterRemove(uint256 newQuorum, address[] memory adaptersToRemove, bool[] memory operation) internal { + function _adapterRemove( + uint256 newQuorum, + address[] memory adaptersToRemove, + bool[] memory operation + ) internal { vm.selectFork(fork[ETHEREUM_CHAIN_ID]); vm.startPrank(caller); /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -75,12 +85,18 @@ contract RemoteAdapterRemove is Setup { _sendAndExecuteMessage(newQuorum, adaptersToRemove, operation, fees); /// @dev validates quorum post update - assertEq(MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(), newQuorum); + 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]); + bool isTrusted = MultiBridgeMessageReceiver( + contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] + ).isTrustedExecutor(adaptersToRemove[j]); assert(!isTrusted); } } @@ -95,9 +111,9 @@ contract RemoteAdapterRemove is Setup { operation[0] = true; vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]).updateReceiverAdapters( - newDummyAdapter, operation - ); + MultiBridgeMessageReceiver( + contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"] + ).updateReceiverAdapters(newDummyAdapter, operation); vm.stopPrank(); } @@ -108,10 +124,15 @@ contract RemoteAdapterRemove is Setup { uint256[] memory fees ) private { bytes memory callData = abi.encodeWithSelector( - MultiBridgeMessageReceiver.updateReceiverAdaptersAndQuorum.selector, adaptersToRemove, operation, newQuorum + MultiBridgeMessageReceiver.updateReceiverAdaptersAndQuorum.selector, + adaptersToRemove, + operation, + newQuorum ); uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; - MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); + MultiBridgeMessageSender sender = MultiBridgeMessageSender( + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] + ); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -136,23 +157,31 @@ 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, - IMultiBridgeMessageReceiver.ExecutionData({ - 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()); + 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()); /// increment the time by 7 days (delay time) vm.warp(block.timestamp + 7 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); } } diff --git a/test/integration-tests/RemoteSetQuorum.t.sol b/test/integration-tests/RemoteSetQuorum.t.sol index 191bd6b..0227c7a 100644 --- a/test/integration-tests/RemoteSetQuorum.t.sol +++ b/test/integration-tests/RemoteSetQuorum.t.sol @@ -10,7 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -30,8 +30,8 @@ contract RemoteQuorumUpdate is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -41,15 +41,27 @@ contract RemoteQuorumUpdate is Setup { _sendAndExecuteMessage(newQuorum, fees); - uint256 currQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); + 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); + 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")]); + MultiBridgeMessageSender sender = MultiBridgeMessageSender( + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] + ); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -77,7 +89,7 @@ contract RemoteQuorumUpdate is Setup { /// schedule the message for execution by moving it to governance timelock contract MultiBridgeMessageReceiver(receiverAddr).scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ + MessageLibrary.MessageExecutionParams({ target: receiverAddr, callData: callData, value: 0, @@ -85,16 +97,22 @@ contract RemoteQuorumUpdate is Setup { expiration: expiration }) ); - (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = - _getExecParams(vm.getRecordedLogs()); - - uint256 oldQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); + ( + uint256 txId, + address finalTarget, + uint256 value, + bytes memory data, + uint256 eta + ) = _getExecParams(vm.getRecordedLogs()); + + uint256 oldQuorum = MultiBridgeMessageReceiver( + contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] + ).quorum(); assertEq(oldQuorum, 2); /// increment the time by 3 days (delay time) vm.warp(block.timestamp + 3 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); } } diff --git a/test/integration-tests/RemoteTimelockUpdate.t.sol b/test/integration-tests/RemoteTimelockUpdate.t.sol index c9f570e..ee616bc 100644 --- a/test/integration-tests/RemoteTimelockUpdate.t.sol +++ b/test/integration-tests/RemoteTimelockUpdate.t.sol @@ -10,7 +10,7 @@ import "test/Setup.t.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -30,8 +30,8 @@ contract RemoteTimelockUpdate is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -41,16 +41,28 @@ contract RemoteTimelockUpdate is Setup { _sendAndExecuteMessage(newDelay, fees); - uint256 currDelay = GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).delay(); + 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); + 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")]); + MultiBridgeMessageSender sender = MultiBridgeMessageSender( + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] + ); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( POLYGON_CHAIN_ID, @@ -76,26 +88,34 @@ contract RemoteTimelockUpdate is Setup { vm.selectFork(fork[POLYGON_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver(contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( - msgId, - IMultiBridgeMessageReceiver.ExecutionData({ - target: timelockAddr, - callData: callData, - value: nativeValue, - nonce: nonce, - expiration: expiration - }) - ); - (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = - _getExecParams(vm.getRecordedLogs()); - - uint256 oldDelay = GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).delay(); + MultiBridgeMessageReceiver( + contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")] + ).scheduleMessageExecution( + 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()); + + uint256 oldDelay = GovernanceTimelock( + contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")] + ).delay(); assertEq(oldDelay, 3 days); /// increment the time by 3 days (delay time) vm.warp(block.timestamp + 3 days); - GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); } } diff --git a/test/integration-tests/TimelockCheck.t.sol b/test/integration-tests/TimelockCheck.t.sol index 9fd66fa..8c1459b 100644 --- a/test/integration-tests/TimelockCheck.t.sol +++ b/test/integration-tests/TimelockCheck.t.sol @@ -11,7 +11,7 @@ import "test/contracts-mock/MockUniswapReceiver.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "src/libraries/Message.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -35,8 +35,8 @@ contract TimelockCheckTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee,) = - IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) + .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -44,10 +44,15 @@ contract TimelockCheckTest is Setup { wormholeFee ); - bytes memory callData = abi.encode(MockUniswapReceiver.setValue.selector, ""); + 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")]); + MultiBridgeMessageSender sender = MultiBridgeMessageSender( + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] + ); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -72,32 +77,37 @@ 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, - IMultiBridgeMessageReceiver.ExecutionData({ - 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()); + 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()); /// increment the time by 1 day (less than delay time) /// @notice should revert here with TX_TIMELOCKED error vm.warp(block.timestamp + 1 days); vm.expectRevert(Error.TX_TIMELOCKED.selector); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); /// increment the time by 2 day (delay time) vm.warp(block.timestamp + 2 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( - txId, finalTarget, value, data, eta - ); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) + .executeTransaction(txId, finalTarget, value, data, eta); assertEq(target.i(), type(uint256).max); } } diff --git a/test/unit-tests/MultiBridgeMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol index 4f30dc1..62bfe07 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -13,14 +13,24 @@ import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; contract MultiBridgeMessageReceiverTest is Setup { - event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); + event BridgeReceiverAdapterUpdated( + address indexed receiverAdapter, + bool add + ); event QuorumUpdated(uint64 oldValue, uint64 newValue); event GovernanceTimelockUpdated(address oldTimelock, address newTimelock); event BridgeMessageReceived( - bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter + bytes32 indexed msgId, + string indexed bridgeName, + uint256 nonce, + address receiverAdapter ); event MessageExecutionScheduled( - bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData + bytes32 indexed msgId, + address indexed target, + uint256 nativeValue, + uint256 nonce, + bytes callData ); MultiBridgeMessageReceiver receiver; @@ -33,9 +43,15 @@ contract MultiBridgeMessageReceiverTest is Setup { super.setUp(); vm.selectFork(fork[DST_CHAIN_ID]); - receiver = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]); - axelarAdapterAddr = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; - wormholeAdapterAddr = contractAddress[DST_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]; + receiver = MultiBridgeMessageReceiver( + contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] + ); + axelarAdapterAddr = contractAddress[DST_CHAIN_ID][ + "AXELAR_RECEIVER_ADAPTER" + ]; + wormholeAdapterAddr = contractAddress[DST_CHAIN_ID][ + "WORMHOLE_RECEIVER_ADAPTER" + ]; timelockAddr = contractAddress[DST_CHAIN_ID]["TIMELOCK"]; } @@ -140,12 +156,8 @@ contract MultiBridgeMessageReceiverTest is Setup { assertEq(receiver.msgDeliveryCount(msgId), 1); assertEq( - receiver.msgExecDataHash(msgId), - keccak256( - abi.encodePacked( - message.target, message.callData, message.nativeValue, message.nonce, message.expiration - ) - ) + receiver.msgExecParamsHash(msgId), + MessageLibrary.computeExecutionParamsHash(message) ); } @@ -245,7 +257,9 @@ contract MultiBridgeMessageReceiverTest is Setup { } /// @dev duplicate message delivery should be rejected - function test_receiver_message_duplicate_message_delivery_by_adapter() public { + function test_receiver_message_duplicate_message_delivery_by_adapter() + public + { vm.startPrank(wormholeAdapterAddr); MessageLibrary.Message memory message = MessageLibrary.Message({ @@ -286,13 +300,7 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ - target: message.target, - callData: message.callData, - value: message.nativeValue, - nonce: message.nonce, - expiration: message.expiration - }) + MessageLibrary.extractExecutionParams(message) ); vm.startPrank(axelarAdapterAddr); @@ -325,15 +333,8 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ - target: message.target, - callData: message.callData, - value: message.nativeValue, - nonce: message.nonce, - expiration: message.expiration - }) + MessageLibrary.extractExecutionParams(message) ); - assertTrue(receiver.isExecutionScheduled(msgId)); } @@ -357,13 +358,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.expectRevert(Error.MSG_EXECUTION_PASSED_DEADLINE.selector); receiver.scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ - target: message.target, - callData: message.callData, - value: message.nativeValue, - nonce: message.nonce, - expiration: message.expiration - }) + MessageLibrary.extractExecutionParams(message) ); } @@ -389,7 +384,7 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ + MessageLibrary.MessageExecutionParams({ target: message.target, callData: message.callData, value: message.nativeValue, @@ -401,13 +396,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); receiver.scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ - target: message.target, - callData: message.callData, - value: message.nativeValue, - nonce: message.nonce, - expiration: message.expiration - }) + MessageLibrary.extractExecutionParams(message) ); } @@ -431,13 +420,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.expectRevert(Error.QUORUM_NOT_ACHIEVED.selector); receiver.scheduleMessageExecution( msgId, - IMultiBridgeMessageReceiver.ExecutionData({ - target: message.target, - callData: message.callData, - value: message.nativeValue, - nonce: message.nonce, - expiration: message.expiration - }) + MessageLibrary.extractExecutionParams(message) ); } @@ -446,7 +429,10 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(timelockAddr); vm.expectEmit(true, true, true, true, address(receiver)); - emit GovernanceTimelockUpdated(receiver.governanceTimelock(), address(42)); + emit GovernanceTimelockUpdated( + receiver.governanceTimelock(), + address(42) + ); receiver.updateGovernanceTimelock(address(42)); assertEq(receiver.governanceTimelock(), address(42)); @@ -489,7 +475,12 @@ contract MultiBridgeMessageReceiverTest is Setup { bool[] memory operations = new bool[](1); operations[0] = true; - vm.expectRevert(abi.encodeWithSelector(Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, "adapter already added")); + vm.expectRevert( + abi.encodeWithSelector( + Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, + "adapter already added" + ) + ); receiver.updateReceiverAdapters(updatedAdapters, operations); } @@ -524,7 +515,12 @@ contract MultiBridgeMessageReceiverTest is Setup { assertFalse(receiver.isTrustedExecutor(address(42))); - vm.expectRevert(abi.encodeWithSelector(Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, "adapter not found")); + vm.expectRevert( + abi.encodeWithSelector( + Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, + "adapter not found" + ) + ); receiver.updateReceiverAdapters(updatedAdapters, operations); } @@ -571,7 +567,9 @@ contract MultiBridgeMessageReceiverTest is Setup { } /// @dev cannot remove one receiver adapter without reducing quorum first - function test_update_receiver_adapter_remove_invalid_quorum_threshold() public { + function test_update_receiver_adapter_remove_invalid_quorum_threshold() + public + { vm.startPrank(timelockAddr); address[] memory updatedAdapters = new address[](1); @@ -649,7 +647,11 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 1; /// @dev removes the newly updated adapter by reducing quorum by one - receiver.updateReceiverAdaptersAndQuorum(adapters, new bool[](1), newQuorum); + receiver.updateReceiverAdaptersAndQuorum( + adapters, + new bool[](1), + newQuorum + ); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -677,7 +679,11 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 4; - receiver.updateReceiverAdaptersAndQuorum(addTwoAdapters, addTwoOps, newQuorum); + receiver.updateReceiverAdaptersAndQuorum( + addTwoAdapters, + addTwoOps, + newQuorum + ); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -695,7 +701,11 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 1; - receiver.updateReceiverAdaptersAndQuorum(removeOneAdapter, new bool[](1), newQuorum); + receiver.updateReceiverAdaptersAndQuorum( + removeOneAdapter, + new bool[](1), + newQuorum + ); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -719,7 +729,11 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 3; - receiver.updateReceiverAdaptersAndQuorum(removeAddAdapters, removeAddOps, newQuorum); + receiver.updateReceiverAdaptersAndQuorum( + removeAddAdapters, + removeAddOps, + newQuorum + ); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -746,10 +760,17 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.receiveMessage(message); - (bool isScheduled, uint256 msgCurrentVotes, string[] memory successfulBridge) = receiver.getMessageInfo(msgId); + ( + bool isScheduled, + uint256 msgCurrentVotes, + string[] memory successfulBridge + ) = receiver.getMessageInfo(msgId); assertFalse(isScheduled); assertEq(msgCurrentVotes, 1); assertEq(successfulBridge.length, 1); - assertEq(successfulBridge[0], WormholeReceiverAdapter(wormholeAdapterAddr).name()); + assertEq( + successfulBridge[0], + WormholeReceiverAdapter(wormholeAdapterAddr).name() + ); } } From 9377e1fee2300ce1acc3ad45ee080f898ae0f6e5 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 10 Oct 2023 12:51:43 -0700 Subject: [PATCH 3/4] Run forge fmt --- src/MultiBridgeMessageReceiver.sol | 108 +++++----------- .../IMultiBridgeMessageReceiver.sol | 27 +--- src/libraries/Message.sol | 67 ++++------ .../integration-tests/GracePeriodExpiry.t.sol | 49 +++---- .../MultiMessageAggregation.t.sol | 49 +++---- test/integration-tests/RemoteAdapterAdd.t.sol | 71 ++++------- .../RemoteAdapterRemove.t.sol | 87 +++++-------- test/integration-tests/RemoteSetQuorum.t.sol | 46 ++----- .../RemoteTimelockUpdate.t.sol | 68 ++++------ test/integration-tests/TimelockCheck.t.sol | 54 ++++---- .../MultiBridgeMessageReceiver.t.sol | 120 ++++-------------- 11 files changed, 237 insertions(+), 509 deletions(-) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 9cd0d70..966f078 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -20,10 +20,7 @@ import "./libraries/Message.sol"; /// governance timelock contract. /// @dev The contract only accepts messages from trusted bridge receiver adapters, each of which implements the /// IMessageReceiverAdapter interface. -contract MultiBridgeMessageReceiver is - IMultiBridgeMessageReceiver, - ExecutorAware -{ +contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAware { /// @notice the id of the source chain that this contract can receive messages from uint256 public immutable srcChainId; /// @notice the global access control contract @@ -40,8 +37,7 @@ contract MultiBridgeMessageReceiver is address public governanceTimelock; /// @notice maintains which bridge adapters have delivered each message - mapping(bytes32 msgId => mapping(address receiverAdapter => bool delivered)) - public msgDeliveries; + mapping(bytes32 msgId => mapping(address receiverAdapter => bool delivered)) public msgDeliveries; /// @notice count of bridge adapters that have delivered each message mapping(bytes32 msgId => uint256 deliveryCount) public msgDeliveryCount; @@ -77,12 +73,7 @@ contract MultiBridgeMessageReceiver is ////////////////////////////////////////////////////////////////*/ /// @notice sets the initial parameters - constructor( - uint256 _srcChainId, - address _gac, - address[] memory _receiverAdapters, - uint64 _quorum - ) { + constructor(uint256 _srcChainId, address _gac, address[] memory _receiverAdapters, uint64 _quorum) { if (_srcChainId == 0) { revert Error.INVALID_SENDER_CHAIN_ID(); } @@ -93,7 +84,7 @@ contract MultiBridgeMessageReceiver is srcChainId = _srcChainId; gac = IGAC(_gac); - for (uint256 i; i < _receiverAdapters.length; ) { + for (uint256 i; i < _receiverAdapters.length;) { _updateReceiverAdapter(_receiverAdapters[i], true); unchecked { ++i; @@ -108,9 +99,7 @@ contract MultiBridgeMessageReceiver is /// @notice receive messages from allowed bridge receiver adapters /// @param _message is the crosschain message sent by the mma sender - function receiveMessage( - MessageLibrary.Message calldata _message - ) external override onlyReceiverAdapter { + function receiveMessage(MessageLibrary.Message calldata _message) external override onlyReceiverAdapter { if (_message.dstChainId != block.chainid) { revert Error.INVALID_DST_CHAIN(); } @@ -146,29 +135,20 @@ contract MultiBridgeMessageReceiver is /// stores the message if the amb is the first one delivering the message if (prevStoredHash == bytes32(0)) { - msgExecParamsHash[msgId] = MessageLibrary - .computeExecutionParamsHash(_message); + msgExecParamsHash[msgId] = MessageLibrary.computeExecutionParamsHash(_message); } string memory bridgeName = IMessageReceiverAdapter(msg.sender).name(); - emit BridgeMessageReceived( - msgId, - bridgeName, - _message.nonce, - msg.sender - ); + emit BridgeMessageReceived(msgId, bridgeName, _message.nonce, msg.sender); } /// @inheritdoc IMultiBridgeMessageReceiver - function scheduleMessageExecution( - bytes32 _msgId, - MessageLibrary.MessageExecutionParams calldata _execParams - ) external override { + function scheduleMessageExecution(bytes32 _msgId, MessageLibrary.MessageExecutionParams calldata _execParams) + external + override + { bytes32 execParamsHash = msgExecParamsHash[_msgId]; - if ( - MessageLibrary.computeExecutionParamsHash(_execParams) != - execParamsHash - ) { + if (MessageLibrary.computeExecutionParamsHash(_execParams) != execParamsHash) { revert Error.EXEC_PARAMS_HASH_MISMATCH(); } @@ -191,42 +171,32 @@ contract MultiBridgeMessageReceiver is /// @dev queues the action on timelock for execution IGovernanceTimelock(governanceTimelock).scheduleTransaction( - _execParams.target, - _execParams.value, - _execParams.callData + _execParams.target, _execParams.value, _execParams.callData ); emit MessageExecutionScheduled( - _msgId, - _execParams.target, - _execParams.value, - _execParams.nonce, - _execParams.callData + _msgId, _execParams.target, _execParams.value, _execParams.nonce, _execParams.callData ); } /// @notice update the governance timelock contract. /// @dev called by admin to update the timelock contract - function updateGovernanceTimelock( - address _governanceTimelock - ) external onlyGlobalOwner { + function updateGovernanceTimelock(address _governanceTimelock) external onlyGlobalOwner { if (_governanceTimelock == address(0)) { revert Error.ZERO_GOVERNANCE_TIMELOCK(); } address oldGovernanceTimelock = governanceTimelock; governanceTimelock = _governanceTimelock; - emit GovernanceTimelockUpdated( - oldGovernanceTimelock, - _governanceTimelock - ); + emit GovernanceTimelockUpdated(oldGovernanceTimelock, _governanceTimelock); } /// @notice Update bridge receiver adapters. /// @dev called by admin to update receiver bridge adapters on all other chains - function updateReceiverAdapters( - address[] calldata _receiverAdapters, - bool[] calldata _operations - ) external override onlyGlobalOwner { + function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) + external + override + onlyGlobalOwner + { _updateReceiverAdapters(_receiverAdapters, _operations); _validateQuorum(quorum); } @@ -255,20 +225,16 @@ contract MultiBridgeMessageReceiver is /// @return isExecutionScheduled is true if the message has been sent to the timelock for execution /// @return msgCurrentVotes is the number of bridges that have delivered the message /// @return successfulBridge is the list of bridges that have delivered the message - function getMessageInfo( - bytes32 _msgId - ) public view returns (bool, uint256, string[] memory) { + function getMessageInfo(bytes32 _msgId) public view returns (bool, uint256, string[] memory) { uint256 msgCurrentVotes = msgDeliveryCount[_msgId]; string[] memory successfulBridge = new string[](msgCurrentVotes); if (msgCurrentVotes != 0) { uint256 currIndex; address[] memory executors = getTrustedExecutors(); - for (uint256 i; i < executors.length; ) { + for (uint256 i; i < executors.length;) { if (msgDeliveries[_msgId][executors[i]]) { - successfulBridge[currIndex] = IMessageReceiverAdapter( - executors[i] - ).name(); + successfulBridge[currIndex] = IMessageReceiverAdapter(executors[i]).name(); ++currIndex; } @@ -278,11 +244,7 @@ contract MultiBridgeMessageReceiver is } } - return ( - isExecutionScheduled[_msgId], - msgCurrentVotes, - successfulBridge - ); + return (isExecutionScheduled[_msgId], msgCurrentVotes, successfulBridge); } /*///////////////////////////////////////////////////////////////// @@ -298,10 +260,7 @@ contract MultiBridgeMessageReceiver is emit QuorumUpdated(oldValue, _quorum); } - function _updateReceiverAdapters( - address[] memory _receiverAdapters, - bool[] memory _operations - ) private { + function _updateReceiverAdapters(address[] memory _receiverAdapters, bool[] memory _operations) private { uint256 len = _receiverAdapters.length; if (len == 0) { @@ -312,7 +271,7 @@ contract MultiBridgeMessageReceiver is revert Error.ARRAY_LENGTH_MISMATCHED(); } - for (uint256 i; i < len; ) { + for (uint256 i; i < len;) { _updateReceiverAdapter(_receiverAdapters[i], _operations[i]); unchecked { @@ -321,22 +280,15 @@ contract MultiBridgeMessageReceiver is } } - function _updateReceiverAdapter( - address _receiverAdapter, - bool _add - ) private { + function _updateReceiverAdapter(address _receiverAdapter, bool _add) private { if (_receiverAdapter == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - bool success = _add - ? _addTrustedExecutor(_receiverAdapter) - : _removeTrustedExecutor(_receiverAdapter); + bool success = _add ? _addTrustedExecutor(_receiverAdapter) : _removeTrustedExecutor(_receiverAdapter); if (!success) { // only fails because we are either attempting to add an existing adapter, or remove a non-existing adapter - revert Error.UPDATE_RECEIVER_ADAPTER_FAILED( - _add ? "adapter already added" : "adapter not found" - ); + revert Error.UPDATE_RECEIVER_ADAPTER_FAILED(_add ? "adapter already added" : "adapter not found"); } emit BridgeReceiverAdapterUpdated(_receiverAdapter, _add); diff --git a/src/interfaces/IMultiBridgeMessageReceiver.sol b/src/interfaces/IMultiBridgeMessageReceiver.sol index 99d10e6..f6c91c2 100644 --- a/src/interfaces/IMultiBridgeMessageReceiver.sol +++ b/src/interfaces/IMultiBridgeMessageReceiver.sol @@ -11,10 +11,7 @@ interface IMultiBridgeMessageReceiver { /// @param nonce is the nonce of the message /// @param receiverAdapter is the address of the receiver adapter that received the message event BridgeMessageReceived( - bytes32 indexed msgId, - string indexed bridgeName, - uint256 nonce, - address receiverAdapter + bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter ); /// @notice emitted when a message has been queued for execution in the destination timelock contract. @@ -24,20 +21,13 @@ interface IMultiBridgeMessageReceiver { /// @param nonce is the nonce of the message /// @param callData is the data that will be passed to the target address through low-level call event MessageExecutionScheduled( - bytes32 indexed msgId, - address indexed target, - uint256 nativeValue, - uint256 nonce, - bytes callData + bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData ); /// @notice emitted when receiver adapter of a specific bridge is updated. /// @param receiverAdapter is the new receiver adapter address /// @param add is true if the receiver adapter was added, false if removed - event BridgeReceiverAdapterUpdated( - address indexed receiverAdapter, - bool add - ); + event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); /// @notice emitted when the quorum for message validity is updated. /// @param oldQuorum is the old quorum value @@ -57,18 +47,13 @@ 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 /// @param _execParams are the params for message execution - function scheduleMessageExecution( - bytes32 _msgId, - MessageLibrary.MessageExecutionParams calldata _execParams - ) external; + 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 /// @param _operations the list of operations to perform for corresponding receiver adapters, true for add, false for remove - function updateReceiverAdapters( - address[] calldata _receiverAdapters, - bool[] calldata _operations - ) external; + function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) external; /// @notice updates the quorum for message validity, which is the number of bridges that must deliver the message for it to be considered valid. /// @param _quorum is the new quorum value diff --git a/src/libraries/Message.sol b/src/libraries/Message.sol index c47050c..7bf1f69 100644 --- a/src/libraries/Message.sol +++ b/src/libraries/Message.sol @@ -38,54 +38,37 @@ library MessageLibrary { /// @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) { - return - keccak256( - abi.encodePacked( - _message.srcChainId, - _message.dstChainId, - _message.nonce, - _message.target, - _message.nativeValue, - _message.expiration, - _message.callData - ) - ); + function computeMsgId(Message memory _message) internal pure returns (bytes32) { + return keccak256( + abi.encodePacked( + _message.srcChainId, + _message.dstChainId, + _message.nonce, + _message.target, + _message.nativeValue, + _message.expiration, + _message.callData + ) + ); } - 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 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(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) { + 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 5f9e02b..a873409 100644 --- a/test/integration-tests/GracePeriodExpiry.t.sol +++ b/test/integration-tests/GracePeriodExpiry.t.sol @@ -33,8 +33,8 @@ contract GracePeriodExpiryTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -42,15 +42,10 @@ contract GracePeriodExpiryTest is Setup { wormholeFee ); - bytes memory callData = abi.encode( - MockUniswapReceiver.setValue.selector, - "" - ); + 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")] - ); + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -75,31 +70,25 @@ 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, - 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()); + 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()); /// increment the time by 21 day (beyond expiry, delay) /// @notice should revert here with TX_EXPIRED error vm.warp(block.timestamp + 21 days); vm.expectRevert(Error.TX_EXPIRED.selector); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); } } diff --git a/test/integration-tests/MultiMessageAggregation.t.sol b/test/integration-tests/MultiMessageAggregation.t.sol index eb159c2..94f7eb8 100644 --- a/test/integration-tests/MultiMessageAggregation.t.sol +++ b/test/integration-tests/MultiMessageAggregation.t.sol @@ -33,8 +33,8 @@ contract MultiBridgeMessageAggregationTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -42,15 +42,10 @@ contract MultiBridgeMessageAggregationTest is Setup { wormholeFee ); - bytes memory callData = abi.encode( - MockUniswapReceiver.setValue.selector, - "" - ); + 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")] - ); + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -75,30 +70,24 @@ 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, - 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()); + 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()); /// increment the time by 7 days (delay time) vm.warp(block.timestamp + 7 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); assertEq(target.i(), type(uint256).max); } } diff --git a/test/integration-tests/RemoteAdapterAdd.t.sol b/test/integration-tests/RemoteAdapterAdd.t.sol index f33948b..3ebcd69 100644 --- a/test/integration-tests/RemoteAdapterAdd.t.sol +++ b/test/integration-tests/RemoteAdapterAdd.t.sol @@ -52,17 +52,14 @@ contract RemoteAdapterAdd is Setup { _adapterAdd(adaptersToAdd, operation); } - function _adapterAdd( - address[] memory adaptersToAdd, - bool[] memory operation - ) private { + function _adapterAdd(address[] memory adaptersToAdd, bool[] memory operation) private { vm.selectFork(fork[ETHEREUM_CHAIN_ID]); vm.startPrank(caller); /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -73,27 +70,19 @@ contract RemoteAdapterAdd is Setup { _sendAndExecuteMessage(adaptersToAdd, operation, fees); for (uint256 j; j < adaptersToAdd.length; ++j) { - bool isTrusted = MultiBridgeMessageReceiver( - contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] - ).isTrustedExecutor(adaptersToAdd[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")] - ); + 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 - ); + bytes memory callData = + abi.encodeWithSelector(MultiBridgeMessageReceiver.updateReceiverAdapters.selector, adaptersToAdd, operation); uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -118,31 +107,23 @@ 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, - 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()); + 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()); /// increment the time by 3 days (delay time) vm.warp(block.timestamp + 3 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); } } diff --git a/test/integration-tests/RemoteAdapterRemove.t.sol b/test/integration-tests/RemoteAdapterRemove.t.sol index 92bc873..cd6ca7d 100644 --- a/test/integration-tests/RemoteAdapterRemove.t.sol +++ b/test/integration-tests/RemoteAdapterRemove.t.sol @@ -25,9 +25,7 @@ contract RemoteAdapterRemove is Setup { /// @dev just remove one adapter and assert function test_remoteRemoveReceiverAdapterSingle() public { address[] memory adaptersToRemove = new address[](1); - adaptersToRemove[0] = contractAddress[DST_CHAIN_ID][ - "AXELAR_RECEIVER_ADAPTER" - ]; + adaptersToRemove[0] = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; /// true = add /// false = remove @@ -45,12 +43,8 @@ contract RemoteAdapterRemove is Setup { _updateDummy(); address[] memory adaptersToRemove = new address[](2); - adaptersToRemove[0] = contractAddress[DST_CHAIN_ID][ - "AXELAR_RECEIVER_ADAPTER" - ]; - adaptersToRemove[1] = contractAddress[DST_CHAIN_ID][ - "WORMHOLE_RECEIVER_ADAPTER" - ]; + adaptersToRemove[0] = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; + adaptersToRemove[1] = contractAddress[DST_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]; /// true = add /// false = remove @@ -63,18 +57,14 @@ contract RemoteAdapterRemove is Setup { _adapterRemove(newQuorum, adaptersToRemove, operation); } - function _adapterRemove( - uint256 newQuorum, - address[] memory adaptersToRemove, - bool[] memory operation - ) internal { + function _adapterRemove(uint256 newQuorum, address[] memory adaptersToRemove, bool[] memory operation) internal { vm.selectFork(fork[ETHEREUM_CHAIN_ID]); vm.startPrank(caller); /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -85,18 +75,12 @@ contract RemoteAdapterRemove is Setup { _sendAndExecuteMessage(newQuorum, adaptersToRemove, operation, fees); /// @dev validates quorum post update - assertEq( - MultiBridgeMessageReceiver( - contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] - ).quorum(), - newQuorum - ); + 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]); + bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) + .isTrustedExecutor(adaptersToRemove[j]); assert(!isTrusted); } } @@ -111,9 +95,9 @@ contract RemoteAdapterRemove is Setup { operation[0] = true; vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - MultiBridgeMessageReceiver( - contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"] - ).updateReceiverAdapters(newDummyAdapter, operation); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]).updateReceiverAdapters( + newDummyAdapter, operation + ); vm.stopPrank(); } @@ -124,15 +108,10 @@ contract RemoteAdapterRemove is Setup { uint256[] memory fees ) private { bytes memory callData = abi.encodeWithSelector( - MultiBridgeMessageReceiver.updateReceiverAdaptersAndQuorum.selector, - adaptersToRemove, - operation, - newQuorum + MultiBridgeMessageReceiver.updateReceiverAdaptersAndQuorum.selector, adaptersToRemove, operation, newQuorum ); uint256 expiration = block.timestamp + EXPIRATION_CONSTANT; - MultiBridgeMessageSender sender = MultiBridgeMessageSender( - contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] - ); + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -157,31 +136,23 @@ 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, - 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()); + 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()); /// increment the time by 7 days (delay time) vm.warp(block.timestamp + 7 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); } } diff --git a/test/integration-tests/RemoteSetQuorum.t.sol b/test/integration-tests/RemoteSetQuorum.t.sol index 0227c7a..5721de8 100644 --- a/test/integration-tests/RemoteSetQuorum.t.sol +++ b/test/integration-tests/RemoteSetQuorum.t.sol @@ -30,8 +30,8 @@ contract RemoteQuorumUpdate is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -41,27 +41,15 @@ contract RemoteQuorumUpdate is Setup { _sendAndExecuteMessage(newQuorum, fees); - uint256 currQuorum = MultiBridgeMessageReceiver( - contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] - ).quorum(); + 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 - ); + 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")] - ); + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -97,22 +85,16 @@ contract RemoteQuorumUpdate is Setup { expiration: expiration }) ); - ( - uint256 txId, - address finalTarget, - uint256 value, - bytes memory data, - uint256 eta - ) = _getExecParams(vm.getRecordedLogs()); - - uint256 oldQuorum = MultiBridgeMessageReceiver( - contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] - ).quorum(); + (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = + _getExecParams(vm.getRecordedLogs()); + + uint256 oldQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); assertEq(oldQuorum, 2); /// increment the time by 3 days (delay time) vm.warp(block.timestamp + 3 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); } } diff --git a/test/integration-tests/RemoteTimelockUpdate.t.sol b/test/integration-tests/RemoteTimelockUpdate.t.sol index ee616bc..2b04b71 100644 --- a/test/integration-tests/RemoteTimelockUpdate.t.sol +++ b/test/integration-tests/RemoteTimelockUpdate.t.sol @@ -30,8 +30,8 @@ contract RemoteTimelockUpdate is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -41,28 +41,16 @@ contract RemoteTimelockUpdate is Setup { _sendAndExecuteMessage(newDelay, fees); - uint256 currDelay = GovernanceTimelock( - contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")] - ).delay(); + 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 - ); + 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")] - ); + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( POLYGON_CHAIN_ID, @@ -88,34 +76,26 @@ contract RemoteTimelockUpdate is Setup { vm.selectFork(fork[POLYGON_CHAIN_ID]); vm.recordLogs(); /// schedule the message for execution by moving it to governance timelock contract - MultiBridgeMessageReceiver( - contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")] - ).scheduleMessageExecution( - 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()); - - uint256 oldDelay = GovernanceTimelock( - contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")] - ).delay(); + MultiBridgeMessageReceiver(contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")]).scheduleMessageExecution( + 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()); + + uint256 oldDelay = GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).delay(); assertEq(oldDelay, 3 days); /// increment the time by 3 days (delay time) vm.warp(block.timestamp + 3 days); - GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); } } diff --git a/test/integration-tests/TimelockCheck.t.sol b/test/integration-tests/TimelockCheck.t.sol index 8c1459b..bc78d06 100644 --- a/test/integration-tests/TimelockCheck.t.sol +++ b/test/integration-tests/TimelockCheck.t.sol @@ -35,8 +35,8 @@ contract TimelockCheckTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - (uint256 wormholeFee, ) = IWormholeRelayer(POLYGON_RELAYER) - .quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); + (uint256 wormholeFee,) = + IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice(_wormholeChainId(DST_CHAIN_ID), 0, 0); (, uint256[] memory fees) = _sortTwoAdaptersWithFees( contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")], contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")], @@ -44,15 +44,10 @@ contract TimelockCheckTest is Setup { wormholeFee ); - bytes memory callData = abi.encode( - MockUniswapReceiver.setValue.selector, - "" - ); + 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")] - ); + MultiBridgeMessageSender sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); uint256 nonce = sender.nonce() + 1; sender.remoteCall{value: 2 ether}( DST_CHAIN_ID, @@ -77,37 +72,32 @@ 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, - 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()); + 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()); /// increment the time by 1 day (less than delay time) /// @notice should revert here with TX_TIMELOCKED error vm.warp(block.timestamp + 1 days); vm.expectRevert(Error.TX_TIMELOCKED.selector); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); /// increment the time by 2 day (delay time) vm.warp(block.timestamp + 2 days); - GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]) - .executeTransaction(txId, finalTarget, value, data, eta); + GovernanceTimelock(contractAddress[DST_CHAIN_ID][bytes("TIMELOCK")]).executeTransaction( + txId, finalTarget, value, data, eta + ); assertEq(target.i(), type(uint256).max); } } diff --git a/test/unit-tests/MultiBridgeMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol index 62bfe07..309b48e 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -13,24 +13,14 @@ import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {IMultiBridgeMessageReceiver} from "src/interfaces/IMultiBridgeMessageReceiver.sol"; contract MultiBridgeMessageReceiverTest is Setup { - event BridgeReceiverAdapterUpdated( - address indexed receiverAdapter, - bool add - ); + event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); event QuorumUpdated(uint64 oldValue, uint64 newValue); event GovernanceTimelockUpdated(address oldTimelock, address newTimelock); event BridgeMessageReceived( - bytes32 indexed msgId, - string indexed bridgeName, - uint256 nonce, - address receiverAdapter + bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter ); event MessageExecutionScheduled( - bytes32 indexed msgId, - address indexed target, - uint256 nativeValue, - uint256 nonce, - bytes callData + bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData ); MultiBridgeMessageReceiver receiver; @@ -43,15 +33,9 @@ contract MultiBridgeMessageReceiverTest is Setup { super.setUp(); vm.selectFork(fork[DST_CHAIN_ID]); - receiver = MultiBridgeMessageReceiver( - contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")] - ); - axelarAdapterAddr = contractAddress[DST_CHAIN_ID][ - "AXELAR_RECEIVER_ADAPTER" - ]; - wormholeAdapterAddr = contractAddress[DST_CHAIN_ID][ - "WORMHOLE_RECEIVER_ADAPTER" - ]; + receiver = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]); + axelarAdapterAddr = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; + wormholeAdapterAddr = contractAddress[DST_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]; timelockAddr = contractAddress[DST_CHAIN_ID]["TIMELOCK"]; } @@ -155,10 +139,7 @@ contract MultiBridgeMessageReceiverTest is Setup { assertEq(receiver.msgDeliveryCount(msgId), 1); - assertEq( - receiver.msgExecParamsHash(msgId), - MessageLibrary.computeExecutionParamsHash(message) - ); + assertEq(receiver.msgExecParamsHash(msgId), MessageLibrary.computeExecutionParamsHash(message)); } /// @dev receives message from two adapters @@ -257,9 +238,7 @@ contract MultiBridgeMessageReceiverTest is Setup { } /// @dev duplicate message delivery should be rejected - function test_receiver_message_duplicate_message_delivery_by_adapter() - public - { + function test_receiver_message_duplicate_message_delivery_by_adapter() public { vm.startPrank(wormholeAdapterAddr); MessageLibrary.Message memory message = MessageLibrary.Message({ @@ -298,10 +277,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(wormholeAdapterAddr); receiver.receiveMessage(message); - receiver.scheduleMessageExecution( - msgId, - MessageLibrary.extractExecutionParams(message) - ); + receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); vm.startPrank(axelarAdapterAddr); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); @@ -331,10 +307,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, - MessageLibrary.extractExecutionParams(message) - ); + receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); assertTrue(receiver.isExecutionScheduled(msgId)); } @@ -356,10 +329,7 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.receiveMessage(message); vm.expectRevert(Error.MSG_EXECUTION_PASSED_DEADLINE.selector); - receiver.scheduleMessageExecution( - msgId, - MessageLibrary.extractExecutionParams(message) - ); + receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); } /// @dev cannot schedule execution of message that has already been scheduled @@ -394,10 +364,7 @@ contract MultiBridgeMessageReceiverTest is Setup { ); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); - receiver.scheduleMessageExecution( - msgId, - MessageLibrary.extractExecutionParams(message) - ); + receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); } /// @dev cannot schedule message execution without quorum @@ -418,10 +385,7 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.receiveMessage(message); vm.expectRevert(Error.QUORUM_NOT_ACHIEVED.selector); - receiver.scheduleMessageExecution( - msgId, - MessageLibrary.extractExecutionParams(message) - ); + receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); } /// @dev updates governance timelock @@ -429,10 +393,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(timelockAddr); vm.expectEmit(true, true, true, true, address(receiver)); - emit GovernanceTimelockUpdated( - receiver.governanceTimelock(), - address(42) - ); + emit GovernanceTimelockUpdated(receiver.governanceTimelock(), address(42)); receiver.updateGovernanceTimelock(address(42)); assertEq(receiver.governanceTimelock(), address(42)); @@ -475,12 +436,7 @@ contract MultiBridgeMessageReceiverTest is Setup { bool[] memory operations = new bool[](1); operations[0] = true; - vm.expectRevert( - abi.encodeWithSelector( - Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, - "adapter already added" - ) - ); + vm.expectRevert(abi.encodeWithSelector(Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, "adapter already added")); receiver.updateReceiverAdapters(updatedAdapters, operations); } @@ -515,12 +471,7 @@ contract MultiBridgeMessageReceiverTest is Setup { assertFalse(receiver.isTrustedExecutor(address(42))); - vm.expectRevert( - abi.encodeWithSelector( - Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, - "adapter not found" - ) - ); + vm.expectRevert(abi.encodeWithSelector(Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, "adapter not found")); receiver.updateReceiverAdapters(updatedAdapters, operations); } @@ -567,9 +518,7 @@ contract MultiBridgeMessageReceiverTest is Setup { } /// @dev cannot remove one receiver adapter without reducing quorum first - function test_update_receiver_adapter_remove_invalid_quorum_threshold() - public - { + function test_update_receiver_adapter_remove_invalid_quorum_threshold() public { vm.startPrank(timelockAddr); address[] memory updatedAdapters = new address[](1); @@ -647,11 +596,7 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 1; /// @dev removes the newly updated adapter by reducing quorum by one - receiver.updateReceiverAdaptersAndQuorum( - adapters, - new bool[](1), - newQuorum - ); + receiver.updateReceiverAdaptersAndQuorum(adapters, new bool[](1), newQuorum); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -679,11 +624,7 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 4; - receiver.updateReceiverAdaptersAndQuorum( - addTwoAdapters, - addTwoOps, - newQuorum - ); + receiver.updateReceiverAdaptersAndQuorum(addTwoAdapters, addTwoOps, newQuorum); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -701,11 +642,7 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 1; - receiver.updateReceiverAdaptersAndQuorum( - removeOneAdapter, - new bool[](1), - newQuorum - ); + receiver.updateReceiverAdaptersAndQuorum(removeOneAdapter, new bool[](1), newQuorum); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -729,11 +666,7 @@ contract MultiBridgeMessageReceiverTest is Setup { uint64 newQuorum = 3; - receiver.updateReceiverAdaptersAndQuorum( - removeAddAdapters, - removeAddOps, - newQuorum - ); + receiver.updateReceiverAdaptersAndQuorum(removeAddAdapters, removeAddOps, newQuorum); /// @dev asserts the quorum and adapter lengths assertEq(receiver.quorum(), newQuorum); @@ -760,17 +693,10 @@ contract MultiBridgeMessageReceiverTest is Setup { receiver.receiveMessage(message); - ( - bool isScheduled, - uint256 msgCurrentVotes, - string[] memory successfulBridge - ) = receiver.getMessageInfo(msgId); + (bool isScheduled, uint256 msgCurrentVotes, string[] memory successfulBridge) = receiver.getMessageInfo(msgId); assertFalse(isScheduled); assertEq(msgCurrentVotes, 1); assertEq(successfulBridge.length, 1); - assertEq( - successfulBridge[0], - WormholeReceiverAdapter(wormholeAdapterAddr).name() - ); + assertEq(successfulBridge[0], WormholeReceiverAdapter(wormholeAdapterAddr).name()); } } From f6f281ef281b7f6f72a18495cb952c38ae04b06b Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 10 Oct 2023 17:00:11 -0700 Subject: [PATCH 4/4] Nit fixes to address comment --- src/MultiBridgeMessageReceiver.sol | 9 ++++-- src/MultiBridgeMessageSender.sol | 4 ++- .../MultiBridgeMessageReceiver.t.sol | 30 ++++++++++--------- .../unit-tests/MultiBridgeMessageSender.t.sol | 8 +++-- .../axelar/AxelarReceiverAdapter.t.sol | 17 ++++++----- .../wormhole/WormholeReceiverAdapter.t.sol | 16 +++++----- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 966f078..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 @@ -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(); @@ -135,7 +138,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// stores the message if the amb is the first one delivering the message if (prevStoredHash == bytes32(0)) { - msgExecParamsHash[msgId] = MessageLibrary.computeExecutionParamsHash(_message); + msgExecParamsHash[msgId] = _message.computeExecutionParamsHash(); } string memory bridgeName = IMessageReceiverAdapter(msg.sender).name(); @@ -148,7 +151,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar override { bytes32 execParamsHash = msgExecParamsHash[_msgId]; - if (MessageLibrary.computeExecutionParamsHash(_execParams) != execParamsHash) { + if (_execParams.computeExecutionParamsHash() != execParamsHash) { revert Error.EXEC_PARAMS_HASH_MISMATCH(); } 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/test/unit-tests/MultiBridgeMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol index 309b48e..184c5b4 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -13,6 +13,8 @@ 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); @@ -126,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); @@ -139,7 +141,7 @@ contract MultiBridgeMessageReceiverTest is Setup { assertEq(receiver.msgDeliveryCount(msgId), 1); - assertEq(receiver.msgExecParamsHash(msgId), MessageLibrary.computeExecutionParamsHash(message)); + assertEq(receiver.msgExecParamsHash(msgId), message.computeExecutionParamsHash()); } /// @dev receives message from two adapters @@ -155,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); @@ -268,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)); @@ -277,7 +279,7 @@ contract MultiBridgeMessageReceiverTest is Setup { vm.startPrank(wormholeAdapterAddr); receiver.receiveMessage(message); - receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); vm.startPrank(axelarAdapterAddr); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); @@ -297,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); @@ -307,7 +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, MessageLibrary.extractExecutionParams(message)); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); assertTrue(receiver.isExecutionScheduled(msgId)); } @@ -324,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, MessageLibrary.extractExecutionParams(message)); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); } /// @dev cannot schedule execution of message that has already been scheduled @@ -345,7 +347,7 @@ contract MultiBridgeMessageReceiverTest is Setup { nativeValue: 0, expiration: type(uint256).max }); - bytes32 msgId = MessageLibrary.computeMsgId(message); + bytes32 msgId = message.computeMsgId(); receiver.receiveMessage(message); @@ -364,7 +366,7 @@ contract MultiBridgeMessageReceiverTest is Setup { ); vm.expectRevert(Error.MSG_ID_ALREADY_SCHEDULED.selector); - receiver.scheduleMessageExecution(msgId, MessageLibrary.extractExecutionParams(message)); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); } /// @dev cannot schedule message execution without quorum @@ -380,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, MessageLibrary.extractExecutionParams(message)); + receiver.scheduleMessageExecution(msgId, message.extractExecutionParams()); } /// @dev updates governance timelock @@ -689,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,