From 29b9789ecdd465da81cda44c61eadc84ead57285 Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 21 Sep 2023 19:20:16 +1000 Subject: [PATCH] Refactoring and cleanup (#79) --- README.md | 12 +- ...ver.sol => MultiBridgeMessageReceiver.sol} | 27 ++-- ...ender.sol => MultiBridgeMessageSender.sol} | 43 +++--- src/adapters/BaseReceiverAdapter.sol | 36 +++++ src/adapters/BaseSenderAdapter.sol | 28 ++-- src/adapters/axelar/AxelarReceiverAdapter.sol | 48 ++---- src/adapters/axelar/AxelarSenderAdapter.sol | 8 +- .../wormhole/WormholeReceiverAdapter.sol | 62 ++------ .../wormhole/WormholeSenderAdapter.sol | 8 +- src/controllers/GAC.sol | 95 +----------- src/controllers/GovernanceTimelock.sol | 2 +- src/controllers/MessageReceiverGAC.sol | 26 ++++ src/controllers/MessageSenderGAC.sol | 111 ++++++++++++++ src/interfaces/IGAC.sol | 64 -------- src/interfaces/IMessageSenderAdapter.sol | 32 ---- .../IMultiBridgeMessageReceiver.sol | 78 ++++++++++ src/interfaces/IMultiMessageReceiver.sol | 37 ----- .../IMessageReceiverAdapter.sol | 2 +- .../adapters/IMessageSenderAdapter.sol | 32 ++++ src/interfaces/controllers/IGAC.sol | 15 ++ .../{ => controllers}/IGovernanceTimelock.sol | 0 src/libraries/Message.sol | 2 +- test/Setup.t.sol | 140 ++++++++---------- ...iverGac.sol => ZeroAddressReceiverGAC.sol} | 6 +- .../integration-tests/GracePeriodExpiry.t.sol | 8 +- .../MultiMessageAggregation.t.sol | 10 +- test/integration-tests/RemoteAdapterAdd.t.sol | 12 +- .../RemoteAdapterRemove.t.sol | 19 ++- test/integration-tests/RemoteSetQuorum.t.sol | 14 +- .../RemoteTimelockUpdate.t.sol | 8 +- test/integration-tests/TimelockCheck.t.sol | 8 +- test/unit-tests/MessageReceiverGAC.t.sol | 73 +++++++++ .../{GAC.t.sol => MessageSenderGAC.t.sol} | 82 +++++----- ...t.sol => MultiBridgeMessageReceiver.t.sol} | 32 ++-- ...r.t.sol => MultiBridgeMessageSender.t.sol} | 32 ++-- .../adapters/BaseSenderAdapter.t.sol | 13 +- .../axelar/AxelarReceiverAdapter.t.sol | 14 +- .../adapters/axelar/AxelarSenderAdapter.t.sol | 2 +- .../wormhole/WormholeReceiverAdapter.t.sol | 39 +---- .../wormhole/WormholeSenderAdapter.t.sol | 4 +- 40 files changed, 666 insertions(+), 618 deletions(-) rename src/{MultiMessageReceiver.sol => MultiBridgeMessageReceiver.sol} (91%) rename src/{MultiMessageSender.sol => MultiBridgeMessageSender.sol} (91%) create mode 100644 src/adapters/BaseReceiverAdapter.sol create mode 100644 src/controllers/MessageReceiverGAC.sol create mode 100644 src/controllers/MessageSenderGAC.sol delete mode 100644 src/interfaces/IGAC.sol delete mode 100644 src/interfaces/IMessageSenderAdapter.sol create mode 100644 src/interfaces/IMultiBridgeMessageReceiver.sol delete mode 100644 src/interfaces/IMultiMessageReceiver.sol rename src/interfaces/{ => adapters}/IMessageReceiverAdapter.sol (96%) create mode 100644 src/interfaces/adapters/IMessageSenderAdapter.sol create mode 100644 src/interfaces/controllers/IGAC.sol rename src/interfaces/{ => controllers}/IGovernanceTimelock.sol (100%) rename test/contracts-mock/{ZeroAddressReceiverGac.sol => ZeroAddressReceiverGAC.sol} (57%) create mode 100644 test/unit-tests/MessageReceiverGAC.t.sol rename test/unit-tests/{GAC.t.sol => MessageSenderGAC.t.sol} (58%) rename test/unit-tests/{MultiMessageReceiver.t.sol => MultiBridgeMessageReceiver.t.sol} (94%) rename test/unit-tests/{MultiMessageSender.t.sol => MultiBridgeMessageSender.t.sol} (94%) diff --git a/README.md b/README.md index 93fc582..bc72ebd 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,12 @@ On the destination chain, if 2 of the 3 AMB agree with each other, we would cons The flow of the message and how it is transformed and relayed is detailed below: 1. Uniswap Ethereum governance structure, `src`, approves to execute a message `msg` on destination chain `dst`. -2. Uniswap governance sends `msg` to `MultiMessageSender`. -3. `MultiMessageSender` relays `msg` to different adapters `adapter`. +2. Uniswap governance sends `msg` to `MultiBridgeMessageSender`. +3. `MultiBridgeMessageSender` relays `msg` to different adapters `adapter`. 4. `adapter` encodes `msg` into the corresponding formatted message, `formatted_msg`, and sends it to the hardcoded AMB contracts `AMB`. 5. Each `AMB` independently carries `formatted_msg` to `dst`. 6. On the destination chain, another set of `adapters` decodes `formatted_msgs` into the original `msg`. -7. `msg` is collected inside the `MultiMessageReceiver` contract. +7. `msg` is collected inside the `MultiBridgeMessageReceiver` contract. 8. If 2 out of 3 `msg` is the same, the `msg` will be executed on `dst`. ![Illustration of ](https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyWOfgotvwuIBhzylK0ud%2Fuploads%2Fco073eKSrR7xUmhObi7v%2FMMA_Highlevel.png?alt=media&token=bff8ec55-c04f-4ab9-b362-caae601154db) @@ -97,8 +97,8 @@ All code changes must be thoroughly tested. Please ensure that your tests cover ## Contracts ``` contracts -├── MultiMessageReceiver.sol -├── MultiMessageSender.sol +├── MultiBridgeMessageReceiver.sol +├── MultiBridgeMessageSender.sol ├── adapters │   ├── BaseSenderAdapter.sol │   ├── axelar @@ -126,7 +126,7 @@ contracts │   ├── IGovernanceTimelock.sol │   ├── IMessageReceiverAdapter.sol │   ├── IMessageSenderAdapter.sol -│   └── IMultiMessageReceiver.sol +│   └── IMultiBridgeMessageReceiver.sol └── libraries ├── Error.sol ├── Message.sol diff --git a/src/MultiMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol similarity index 91% rename from src/MultiMessageReceiver.sol rename to src/MultiBridgeMessageReceiver.sol index bc4e6bd..52d95c9 100644 --- a/src/MultiMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -5,24 +5,24 @@ pragma solidity >=0.8.9; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; /// interfaces -import "./interfaces/IMessageReceiverAdapter.sol"; -import "./interfaces/IMultiMessageReceiver.sol"; +import "./interfaces/adapters/IMessageReceiverAdapter.sol"; +import "./interfaces/IMultiBridgeMessageReceiver.sol"; import "./interfaces/EIP5164/ExecutorAware.sol"; -import "./interfaces/IGovernanceTimelock.sol"; +import "./interfaces/controllers/IGovernanceTimelock.sol"; /// libraries import "./libraries/Error.sol"; import "./libraries/Message.sol"; /// @title Multi-bridge message receiver. -/// @notice This contract is deployed on each destination chain, and receives messages sent by the MultiMessageSender +/// @notice This contract is deployed on each destination chain, and receives messages sent by the MultiBridgeMessageSender.sol /// contract on the source chain, through multiple bridge adapters. A message is considered valid and can be executed /// if it has been delivered by enough trusted bridge receiver adapters (i.e. has achieved a quorum threshold), /// before the message's expiration. If a message is successfully validated in time, it is queued for execution on the /// governance timelock contract. /// @dev The contract only accepts messages from trusted bridge receiver adapters, each of which implements the /// IMessageReceiverAdapter interface. -contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializable { +contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAware, Initializable { /*///////////////////////////////////////////////////////////////// STATE VARIABLES ////////////////////////////////////////////////////////////////*/ @@ -116,7 +116,7 @@ contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializ } /// 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 MultiMessageReceiver. + /// although each adapters' internal msgId is attached at the end of calldata, it's not useful to MultiBridgeMessageReceiver.sol. bytes32 msgId = MessageLibrary.computeMsgId(_message); if (msgDeliveries[msgId][msg.sender]) { @@ -143,13 +143,11 @@ contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializ } string memory bridgeName = IMessageReceiverAdapter(msg.sender).name(); - emit SingleBridgeMsgReceived(msgId, bridgeName, _message.nonce, msg.sender); + emit BridgeMessageReceived(msgId, bridgeName, _message.nonce, msg.sender); } - /// @notice Execute the message (invoke external call according to the message content) if the message - /// @dev has reached the power threshold (the same message has been delivered by enough multiple bridges). - /// Param values can be found in the MultiMessageSent event from the source chain MultiMessageSender contract. - function executeMessage(bytes32 msgId) external { + /// @inheritdoc IMultiBridgeMessageReceiver + function executeMessage(bytes32 msgId) external override { ExecutionData memory _execData = msgExecData[msgId]; /// @dev validates if msg execution is not beyond expiration @@ -181,6 +179,7 @@ contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializ /// @dev called by admin to update receiver bridge adapters on all other chains function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) external + override onlyGovernanceTimelock { _updateReceiverAdapters(_receiverAdapters, _operations); @@ -192,7 +191,7 @@ contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializ uint64 _newQuorum, address[] calldata _receiverAdapters, bool[] calldata _operations - ) external onlyGovernanceTimelock { + ) external override onlyGovernanceTimelock { /// @dev updates quorum here _updateQuorum(_newQuorum); @@ -201,7 +200,7 @@ contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializ } /// @notice Update power quorum threshold of message execution. - function updateQuorum(uint64 _quorum) external onlyGovernanceTimelock { + function updateQuorum(uint64 _quorum) external override onlyGovernanceTimelock { _updateQuorum(_quorum); } @@ -281,6 +280,6 @@ contract MultiMessageReceiver is IMultiMessageReceiver, ExecutorAware, Initializ revert Error.INVALID_QUORUM_THRESHOLD(); } } - emit ReceiverAdapterUpdated(_receiverAdapter, _add); + emit BridgeReceiverAdapterUpdated(_receiverAdapter, _add); } } diff --git a/src/MultiMessageSender.sol b/src/MultiBridgeMessageSender.sol similarity index 91% rename from src/MultiMessageSender.sol rename to src/MultiBridgeMessageSender.sol index 67eac90..a3f9f49 100644 --- a/src/MultiMessageSender.sol +++ b/src/MultiBridgeMessageSender.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.9; /// interfaces -import "./interfaces/IMessageSenderAdapter.sol"; -import "./interfaces/IMultiMessageReceiver.sol"; -import "./interfaces/IGAC.sol"; +import "./interfaces/adapters/IMessageSenderAdapter.sol"; +import "./interfaces/IMultiBridgeMessageReceiver.sol"; +import "./controllers/MessageSenderGAC.sol"; /// libraries import "./libraries/Message.sol"; @@ -16,13 +16,13 @@ import "./libraries/Error.sol"; /// The contract has only a single authorised caller that can send messages, and an owner that can change key parameters. /// 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 MultiMessageSender { +contract MultiBridgeMessageSender { /*/////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /// @dev Global Access Controller (GAC) contract - IGAC public immutable gac; + MessageSenderGAC public immutable senderGAC; /// @dev the minimum and maximum duration that a message's expiration parameter can be set to uint256 public constant MIN_EXPIRATION = 2 days; @@ -51,10 +51,10 @@ contract MultiMessageSender { /// @param target is the target execution address on the destination chain /// @param callData is the data to be sent to _target by low-level call(eg. address(_target).call(_callData)) /// @param nativeValue is the value to be sent to _target by low-level call (eg. address(_target).call{value: _nativeValue}(_callData)) - /// @param expiration refers to the number of days that a message remains valid before it is considered stale and can no longer be executed. + /// @param expiration refers to the number seconds that a message remains valid before it is considered stale and can no longer be executed. /// @param senderAdapters are the sender adapters that were used to send the message /// @param adapterSuccess are the message sending success status for each of the corresponding adapters listed in senderAdapters - event MultiMessageSent( + event MultiBridgeMessageSent( bytes32 indexed msgId, uint256 nonce, uint256 indexed dstChainId, @@ -82,7 +82,7 @@ contract MultiMessageSender { /// @dev checks if msg.sender is the owner configured in GAC modifier onlyOwner() { - if (msg.sender != gac.getGlobalOwner()) { + if (msg.sender != senderGAC.getGlobalOwner()) { revert Error.CALLER_NOT_OWNER(); } _; @@ -90,7 +90,7 @@ contract MultiMessageSender { /// @dev checks if msg.sender is the authorised caller configured in GAC modifier onlyCaller() { - if (msg.sender != gac.getMultiMessageCaller()) { + if (msg.sender != senderGAC.getAuthorisedCaller()) { revert Error.INVALID_PRIVILEGED_CALLER(); } _; @@ -109,13 +109,13 @@ contract MultiMessageSender { CONSTRUCTOR ////////////////////////////////////////////////////////////////*/ - /// @param _gac is the controller/registry of MMA - constructor(address _gac) { - if (_gac == address(0)) { + /// @param _senderGAC is the controller/registry of MMA + constructor(address _senderGAC) { + if (_senderGAC == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - gac = IGAC(_gac); + senderGAC = MessageSenderGAC(_senderGAC); } /*///////////////////////////////////////////////////////////////// @@ -131,7 +131,7 @@ contract MultiMessageSender { /// @param _target is the target execution point on the destination chain /// @param _callData is the data to be sent to _target by low-level call(eg. address(_target).call(_callData)) /// @param _nativeValue is the value to be sent to _target by low-level call (eg. address(_target).call{value: _nativeValue}(_callData)) - /// @param _expiration refers to the number of days that a message remains valid before it is considered stale and can no longer be executed. + /// @param _expiration refers to the number of seconds that a message remains valid before it is considered stale and can no longer be executed. /// @param _refundAddress refers to the refund address for any extra native tokens paid function remoteCall( uint256 _dstChainId, @@ -149,7 +149,7 @@ contract MultiMessageSender { /// @param _target is the target execution point on the destination chain /// @param _callData is the data to be sent to _target by low-level call(eg. address(_target).call(_callData)) /// @param _nativeValue is the value to be sent to _target by low-level call (eg. address(_target).call{value: _nativeValue}(_callData)) - /// @param _expiration refers to the number of days that a message remains valid before it is considered stale and can no longer be executed. + /// @param _expiration refers to the number of seconds that a message remains valid before it is considered stale and can no longer be executed. /// @param _excludedAdapters are the sender adapters to be excluded from relaying the message /// @param _refundAddress refers to the refund address for any extra native tokens paid function remoteCall( @@ -195,7 +195,7 @@ contract MultiMessageSender { /// @notice A helper function for estimating total required message fee by all available message bridges. function estimateTotalMessageFee( uint256 _dstChainId, - address _multiMessageReceiver, + address _multiBridgeMessageReceiver, address _target, bytes calldata _callData, uint256 _nativeValue @@ -208,11 +208,12 @@ contract MultiMessageSender { address[] storage adapters = senderAdapters; /// @dev generates the dst chain function call - data = abi.encodeWithSelector(IMultiMessageReceiver.receiveMessage.selector, message); + data = abi.encodeWithSelector(IMultiBridgeMessageReceiver.receiveMessage.selector, message); for (uint256 i; i < adapters.length; ++i) { - uint256 fee = - IMessageSenderAdapter(adapters[i]).getMessageFee(uint256(_dstChainId), _multiMessageReceiver, data); + uint256 fee = IMessageSenderAdapter(adapters[i]).getMessageFee( + uint256(_dstChainId), _multiBridgeMessageReceiver, data + ); totalFee += fee; } @@ -247,7 +248,7 @@ contract MultiMessageSender { revert Error.INVALID_REFUND_ADDRESS(); } - address mmaReceiver = gac.getMultiMessageReceiver(_dstChainId); + address mmaReceiver = senderGAC.getRemoteMultiBridgeMessageReceiver(_dstChainId); if (mmaReceiver == address(0)) { revert Error.ZERO_RECEIVER_ADAPTER(); @@ -267,7 +268,7 @@ contract MultiMessageSender { } bool[] memory adapterSuccesses = _dispatchMessages(adapters, mmaReceiver, _dstChainId, message); - emit MultiMessageSent( + emit MultiBridgeMessageSent( msgId, nonce, _dstChainId, _target, _callData, _nativeValue, _expiration, adapters, adapterSuccesses ); diff --git a/src/adapters/BaseReceiverAdapter.sol b/src/adapters/BaseReceiverAdapter.sol new file mode 100644 index 0000000..b82fe3b --- /dev/null +++ b/src/adapters/BaseReceiverAdapter.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.9; + +import "../interfaces/adapters/IMessageReceiverAdapter.sol"; +import "../controllers/MessageReceiverGAC.sol"; + +abstract contract BaseReceiverAdapter is IMessageReceiverAdapter { + MessageReceiverGAC public immutable receiverGAC; + address public senderAdapter; + + modifier onlyGlobalOwner() { + if (!receiverGAC.isGlobalOwner(msg.sender)) { + revert Error.CALLER_NOT_OWNER(); + } + _; + } + + constructor(address _receiverGAC) { + if (_receiverGAC == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + receiverGAC = MessageReceiverGAC(_receiverGAC); + } + + /// @inheritdoc IMessageReceiverAdapter + function updateSenderAdapter(address _newSender) external override onlyGlobalOwner { + if (_newSender == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + + address oldSender = senderAdapter; + senderAdapter = _newSender; + + emit SenderAdapterUpdated(oldSender, _newSender); + } +} diff --git a/src/adapters/BaseSenderAdapter.sol b/src/adapters/BaseSenderAdapter.sol index 7f6204c..1a76a4a 100644 --- a/src/adapters/BaseSenderAdapter.sol +++ b/src/adapters/BaseSenderAdapter.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.9; -import "../interfaces/IGAC.sol"; import "../libraries/Error.sol"; -import "../interfaces/IMessageSenderAdapter.sol"; +import "../interfaces/adapters/IMessageSenderAdapter.sol"; +import "../controllers/MessageSenderGAC.sol"; abstract contract BaseSenderAdapter is IMessageSenderAdapter { - IGAC public immutable gac; + MessageSenderGAC public immutable senderGAC; /*///////////////////////////////////////////////////////////////// STATE VARIABLES @@ -18,15 +18,15 @@ abstract contract BaseSenderAdapter is IMessageSenderAdapter { /*///////////////////////////////////////////////////////////////// MODIFIER ////////////////////////////////////////////////////////////////*/ - modifier onlyMultiMessageSender() { - if (msg.sender != gac.getMultiMessageSender()) { + modifier onlyMultiBridgeMessageSender() { + if (msg.sender != senderGAC.getMultiBridgeMessageSender()) { revert Error.CALLER_NOT_MULTI_MESSAGE_SENDER(); } _; } modifier onlyGlobalOwner() { - if (!gac.isGlobalOwner(msg.sender)) { + if (!senderGAC.isGlobalOwner(msg.sender)) { revert Error.CALLER_NOT_OWNER(); } _; @@ -36,13 +36,13 @@ abstract contract BaseSenderAdapter is IMessageSenderAdapter { CONSTRUCTOR ////////////////////////////////////////////////////////////////*/ - /// @param _gac is the global access control contract - constructor(address _gac) { - if (_gac == address(0)) { + /// @param _senderGAC is the global access control contract + constructor(address _senderGAC) { + if (_senderGAC == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - gac = IGAC(_gac); + senderGAC = MessageSenderGAC(_senderGAC); } /*///////////////////////////////////////////////////////////////// @@ -62,8 +62,9 @@ abstract contract BaseSenderAdapter is IMessageSenderAdapter { } for (uint256 i; i < arrLength;) { + address oldReceiver = receiverAdapters[_dstChainIds[i]]; receiverAdapters[_dstChainIds[i]] = _receiverAdapters[i]; - emit ReceiverAdapterUpdated(_dstChainIds[i], _receiverAdapters[i]); + emit ReceiverAdapterUpdated(_dstChainIds[i], oldReceiver, _receiverAdapters[i]); unchecked { ++i; @@ -71,6 +72,11 @@ abstract contract BaseSenderAdapter is IMessageSenderAdapter { } } + /// @inheritdoc IMessageSenderAdapter + function getReceiverAdapter(uint256 _dstChainId) external view override returns (address) { + return receiverAdapters[_dstChainId]; + } + /*///////////////////////////////////////////////////////////////// HELPER FUNCTIONS ////////////////////////////////////////////////////////////////*/ diff --git a/src/adapters/axelar/AxelarReceiverAdapter.sol b/src/adapters/axelar/AxelarReceiverAdapter.sol index ab545f4..c9e4ded 100644 --- a/src/adapters/axelar/AxelarReceiverAdapter.sol +++ b/src/adapters/axelar/AxelarReceiverAdapter.sol @@ -1,12 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.9; -import "forge-std/console.sol"; - /// local imports -import "../../interfaces/IMessageReceiverAdapter.sol"; -import "../../interfaces/IMultiMessageReceiver.sol"; -import "../../interfaces/IGAC.sol"; +import "../../interfaces/adapters/IMessageReceiverAdapter.sol"; +import "../../interfaces/IMultiBridgeMessageReceiver.sol"; import "../../libraries/Error.sol"; import "../../libraries/Types.sol"; import "../../libraries/Message.sol"; @@ -15,42 +12,34 @@ import "./interfaces/IAxelarGateway.sol"; import "./interfaces/IAxelarExecutable.sol"; import "./libraries/StringAddressConversion.sol"; +import "../../controllers/MessageReceiverGAC.sol"; +import "../BaseSenderAdapter.sol"; +import "../BaseReceiverAdapter.sol"; + /// @notice receiver adapter for axelar bridge -contract AxelarReceiverAdapter is IAxelarExecutable, IMessageReceiverAdapter { +contract AxelarReceiverAdapter is BaseReceiverAdapter, IAxelarExecutable { using StringAddressConversion for string; string public constant name = "AXELAR"; IAxelarGateway public immutable gateway; - IGAC public immutable gac; /*///////////////////////////////////////////////////////////////// STATE VARIABLES ////////////////////////////////////////////////////////////////*/ string public senderChain; - address public senderAdapter; mapping(bytes32 => bool) public isMessageExecuted; mapping(bytes32 => bool) public commandIdStatus; - /*///////////////////////////////////////////////////////////////// - MODIFIER - ////////////////////////////////////////////////////////////////*/ - modifier onlyGlobalOwner() { - if (!gac.isGlobalOwner(msg.sender)) { - revert Error.CALLER_NOT_OWNER(); - } - _; - } - /*///////////////////////////////////////////////////////////////// CONSTRUCTOR ////////////////////////////////////////////////////////////////*/ /// @param _gateway is axelar gateway contract address. - /// @param _gac is global access controller. /// @param _senderChain is the chain id of the sender chain. - constructor(address _gateway, address _gac, string memory _senderChain) { - if (_gateway == address(0) || _gac == address(0)) { + /// @param _receiverGAC is global access controller. + constructor(address _gateway, string memory _senderChain, address _receiverGAC) BaseReceiverAdapter(_receiverGAC) { + if (_gateway == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } @@ -59,7 +48,6 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IMessageReceiverAdapter { } gateway = IAxelarGateway(_gateway); - gac = IGAC(_gac); senderChain = _senderChain; } @@ -67,18 +55,6 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IMessageReceiverAdapter { EXTERNAL FUNCTIONS ////////////////////////////////////////////////////////////////*/ - /// @inheritdoc IMessageReceiverAdapter - function updateSenderAdapter(address _senderAdapter) external override onlyGlobalOwner { - if (_senderAdapter == address(0)) { - revert Error.ZERO_ADDRESS_INPUT(); - } - - address oldAdapter = senderAdapter; - senderAdapter = _senderAdapter; - - emit SenderAdapterUpdated(oldAdapter, _senderAdapter); - } - /// @dev accepts new cross-chain messages from axelar gateway /// @inheritdoc IAxelarExecutable function execute( @@ -117,7 +93,7 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IMessageReceiverAdapter { } /// @dev step-6: validate the destination - if (decodedPayload.finalDestination != gac.getMultiMessageReceiver(block.chainid)) { + if (decodedPayload.finalDestination != receiverGAC.getMultiBridgeMessageReceiver()) { revert Error.INVALID_FINAL_DESTINATION(); } @@ -126,7 +102,7 @@ contract AxelarReceiverAdapter is IAxelarExecutable, IMessageReceiverAdapter { MessageLibrary.Message memory _data = abi.decode(decodedPayload.data, (MessageLibrary.Message)); - try IMultiMessageReceiver(decodedPayload.finalDestination).receiveMessage(_data) { + try IMultiBridgeMessageReceiver(decodedPayload.finalDestination).receiveMessage(_data) { emit MessageIdExecuted(_data.srcChainId, msgId); } catch (bytes memory lowLevelData) { revert MessageFailure(msgId, lowLevelData); diff --git a/src/adapters/axelar/AxelarSenderAdapter.sol b/src/adapters/axelar/AxelarSenderAdapter.sol index ef49377..dbe8001 100644 --- a/src/adapters/axelar/AxelarSenderAdapter.sol +++ b/src/adapters/axelar/AxelarSenderAdapter.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.9; -import "forge-std/console.sol"; - /// local imports import "../BaseSenderAdapter.sol"; -import "../../interfaces/IGAC.sol"; +import "../../interfaces/controllers/IGAC.sol"; import "../../libraries/Error.sol"; import "../../libraries/Types.sol"; @@ -44,7 +42,7 @@ contract AxelarSenderAdapter is BaseSenderAdapter { external payable override - onlyMultiMessageSender + onlyMultiBridgeMessageSender returns (bytes32 msgId) { address receiverAdapter = receiverAdapters[_toChainId]; @@ -89,7 +87,7 @@ contract AxelarSenderAdapter is BaseSenderAdapter { ////////////////////////////////////////////////////////////////*/ /// @inheritdoc IMessageSenderAdapter - function getMessageFee(uint256 _toChainId, address, bytes calldata) external view override returns (uint256) { + function getMessageFee(uint256, address, bytes calldata) external view override returns (uint256) { /// FIXME: axelar has no on-chain message fee estimate. should have to overpay and get refund return 1 ether; // return axelarChainRegistry.getFee(_toChainId, uint32(gac.getGlobalMsgDeliveryGasLimit())); diff --git a/src/adapters/wormhole/WormholeReceiverAdapter.sol b/src/adapters/wormhole/WormholeReceiverAdapter.sol index 39fdea4..162a366 100644 --- a/src/adapters/wormhole/WormholeReceiverAdapter.sol +++ b/src/adapters/wormhole/WormholeReceiverAdapter.sol @@ -5,29 +5,27 @@ pragma solidity >=0.8.9; import "wormhole-solidity-sdk/interfaces/IWormholeReceiver.sol"; /// local imports -import "../../interfaces/IMessageReceiverAdapter.sol"; -import "../../interfaces/IMultiMessageReceiver.sol"; -import "../../interfaces/IGAC.sol"; +import "../../interfaces/adapters/IMessageReceiverAdapter.sol"; +import "../../interfaces/IMultiBridgeMessageReceiver.sol"; import "../../libraries/Error.sol"; import "../../libraries/Types.sol"; import "../../libraries/TypeCasts.sol"; import "../../libraries/Message.sol"; +import "../../controllers/MessageReceiverGAC.sol"; +import "../BaseReceiverAdapter.sol"; + /// @notice receiver adapter for wormhole bridge /// @dev allows wormhole relayers to write to receiver adapter which then forwards the message to /// the MMA receiver. -contract WormholeReceiverAdapter is IMessageReceiverAdapter, IWormholeReceiver { +contract WormholeReceiverAdapter is BaseReceiverAdapter, IWormholeReceiver { string public constant name = "WORMHOLE"; address public immutable relayer; - IGAC public immutable gac; uint16 public immutable senderChain; /*///////////////////////////////////////////////////////////////// STATE VARIABLES ////////////////////////////////////////////////////////////////*/ - address public senderAdapter; - - mapping(uint256 => uint16) public chainIdMap; mapping(bytes32 => bool) public isMessageExecuted; mapping(bytes32 => bool) public deliveryHashStatus; @@ -35,12 +33,6 @@ contract WormholeReceiverAdapter is IMessageReceiverAdapter, IWormholeReceiver { /*///////////////////////////////////////////////////////////////// MODIFIER ////////////////////////////////////////////////////////////////*/ - modifier onlyGlobalOwner() { - if (!gac.isGlobalOwner(msg.sender)) { - revert Error.CALLER_NOT_OWNER(); - } - _; - } modifier onlyRelayerContract() { if (msg.sender != relayer) { @@ -54,11 +46,11 @@ contract WormholeReceiverAdapter is IMessageReceiverAdapter, IWormholeReceiver { ////////////////////////////////////////////////////////////////*/ /// @param _relayer is wormhole relayer. - /// @param _gac is global access controller. /// @param _senderChain is the chain id of the sender chain. + /// @param _receiverGAC is global access controller. /// note: https://docs.wormhole.com/wormhole/quick-start/cross-chain-dev/automatic-relayer - constructor(address _relayer, address _gac, uint16 _senderChain) { - if (_relayer == address(0) || _gac == address(0)) { + constructor(address _relayer, uint16 _senderChain, address _receiverGAC) BaseReceiverAdapter(_receiverGAC) { + if (_relayer == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } @@ -67,7 +59,6 @@ contract WormholeReceiverAdapter is IMessageReceiverAdapter, IWormholeReceiver { } relayer = _relayer; - gac = IGAC(_gac); senderChain = _senderChain; } @@ -75,37 +66,6 @@ contract WormholeReceiverAdapter is IMessageReceiverAdapter, IWormholeReceiver { EXTERNAL FUNCTIONS ////////////////////////////////////////////////////////////////*/ - /// @inheritdoc IMessageReceiverAdapter - function updateSenderAdapter(address _senderAdapter) external override onlyGlobalOwner { - if (_senderAdapter == address(0)) { - revert Error.ZERO_ADDRESS_INPUT(); - } - - address oldAdapter = senderAdapter; - senderAdapter = _senderAdapter; - - emit SenderAdapterUpdated(oldAdapter, _senderAdapter); - } - - /// @dev maps the MMA chain id to bridge specific chain id - /// @dev _origIds is the chain's native chain id - /// @dev _whIds are the bridge allocated chain id - function setChainIdMap(uint256[] calldata _origIds, uint16[] calldata _whIds) external onlyGlobalOwner { - uint256 arrLength = _origIds.length; - - if (arrLength != _whIds.length) { - revert Error.ARRAY_LENGTH_MISMATCHED(); - } - - for (uint256 i; i < arrLength;) { - chainIdMap[_origIds[i]] = _whIds[i]; - - unchecked { - ++i; - } - } - } - /// @inheritdoc IWormholeReceiver function receiveWormholeMessages( bytes memory payload, @@ -143,13 +103,13 @@ contract WormholeReceiverAdapter is IMessageReceiverAdapter, IWormholeReceiver { } /// @dev step-5: validate the destination - if (decodedPayload.finalDestination != gac.getMultiMessageReceiver(block.chainid)) { + if (decodedPayload.finalDestination != receiverGAC.getMultiBridgeMessageReceiver()) { revert Error.INVALID_FINAL_DESTINATION(); } MessageLibrary.Message memory _data = abi.decode(decodedPayload.data, (MessageLibrary.Message)); - try IMultiMessageReceiver(decodedPayload.finalDestination).receiveMessage(_data) { + try IMultiBridgeMessageReceiver(decodedPayload.finalDestination).receiveMessage(_data) { emit MessageIdExecuted(_data.srcChainId, msgId); } catch (bytes memory lowLevelData) { revert MessageFailure(msgId, lowLevelData); diff --git a/src/adapters/wormhole/WormholeSenderAdapter.sol b/src/adapters/wormhole/WormholeSenderAdapter.sol index c96cb24..4ec08e0 100644 --- a/src/adapters/wormhole/WormholeSenderAdapter.sol +++ b/src/adapters/wormhole/WormholeSenderAdapter.sol @@ -6,7 +6,7 @@ import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; /// local imports import "../BaseSenderAdapter.sol"; -import "../../interfaces/IGAC.sol"; +import "../../interfaces/controllers/IGAC.sol"; import "../../libraries/Error.sol"; import "../../libraries/Types.sol"; @@ -36,7 +36,7 @@ contract WormholeSenderAdapter is BaseSenderAdapter { external payable override - onlyMultiMessageSender + onlyMultiBridgeMessageSender returns (bytes32 msgId) { address receiverAdapter = receiverAdapters[_toChainId]; @@ -60,7 +60,7 @@ contract WormholeSenderAdapter is BaseSenderAdapter { payload, 0, /// @dev no receiver value since just passing message - gac.getGlobalMsgDeliveryGasLimit() + senderGAC.getGlobalMsgDeliveryGasLimit() ); emit MessageDispatched(msgId, msg.sender, _toChainId, _to, _data); @@ -92,6 +92,6 @@ contract WormholeSenderAdapter is BaseSenderAdapter { /// @inheritdoc IMessageSenderAdapter function getMessageFee(uint256 _toChainId, address, bytes calldata) external view override returns (uint256 fee) { /// note: 50000 GAS is commonly used across the MMA; move to some global contract - (fee,) = relayer.quoteEVMDeliveryPrice(chainIdMap[_toChainId], 0, gac.getGlobalMsgDeliveryGasLimit()); + (fee,) = relayer.quoteEVMDeliveryPrice(chainIdMap[_toChainId], 0, senderGAC.getGlobalMsgDeliveryGasLimit()); } } diff --git a/src/controllers/GAC.sol b/src/controllers/GAC.sol index a6d5998..b16a492 100644 --- a/src/controllers/GAC.sol +++ b/src/controllers/GAC.sol @@ -2,92 +2,19 @@ pragma solidity >=0.8.9; -/// library imports import "openzeppelin-contracts/contracts/access/Ownable.sol"; /// local imports -import {IGAC} from "../interfaces/IGAC.sol"; +import {IGAC} from "../interfaces/controllers/IGAC.sol"; import {Error} from "../libraries/Error.sol"; /// @dev is the global access control contract for bridge adapters contract GAC is IGAC, Ownable { - /*/////////////////////////////////////////////////////////////// - CONSTANTS - //////////////////////////////////////////////////////////////*/ - uint256 public constant MINIMUM_DST_GAS_LIMIT = 50000; - - /*/////////////////////////////////////////////////////////////// - STATE VARIABLES - //////////////////////////////////////////////////////////////*/ - uint256 public dstGasLimit; - - /// @notice is the MMA Core Contracts on the chain - /// @dev leveraged by bridge adapters for authentication - address public multiMessageSender; - - /// @dev is the allowed caller for the multi-message sender - address public allowedCaller; - - mapping(uint256 chainId => address mmaReceiver) public multiMessageReceiver; - /*/////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor() Ownable() {} - /*/////////////////////////////////////////////////////////////// - EXTERNAL FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /// @inheritdoc IGAC - function setMultiMessageSender(address _mmaSender) external override onlyOwner { - if (_mmaSender == address(0)) { - revert Error.ZERO_ADDRESS_INPUT(); - } - - multiMessageSender = _mmaSender; - - emit MultiMessageSenderUpdated(_mmaSender); - } - - /// @inheritdoc IGAC - function setMultiMessageCaller(address _mmaCaller) external override onlyOwner { - if (_mmaCaller == address(0)) { - revert Error.ZERO_ADDRESS_INPUT(); - } - - allowedCaller = _mmaCaller; - - emit MultiMessageCallerUpdated(_mmaCaller); - } - - /// @inheritdoc IGAC - function setMultiMessageReceiver(uint256 _chainId, address _mmaReceiver) external override onlyOwner { - if (_mmaReceiver == address(0)) { - revert Error.ZERO_ADDRESS_INPUT(); - } - - if (_chainId == 0) { - revert Error.ZERO_CHAIN_ID(); - } - - multiMessageReceiver[_chainId] = _mmaReceiver; - - emit MultiMessageReceiverUpdated(_chainId, _mmaReceiver); - } - - /// @inheritdoc IGAC - function setGlobalMsgDeliveryGasLimit(uint256 _gasLimit) external override onlyOwner { - if (_gasLimit < MINIMUM_DST_GAS_LIMIT) { - revert Error.INVALID_DST_GAS_LIMIT_MIN(); - } - - uint256 oldLimit = dstGasLimit; - dstGasLimit = _gasLimit; - - emit DstGasLimitUpdated(oldLimit, _gasLimit); - } - /*/////////////////////////////////////////////////////////////// EXTERNAL VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -105,24 +32,4 @@ contract GAC is IGAC, Ownable { function getGlobalOwner() external view override returns (address _owner) { _owner = owner(); } - - /// @inheritdoc IGAC - function getGlobalMsgDeliveryGasLimit() external view override returns (uint256 _gasLimit) { - _gasLimit = dstGasLimit; - } - - /// @inheritdoc IGAC - function getMultiMessageSender() external view returns (address _mmaSender) { - _mmaSender = multiMessageSender; - } - - /// @inheritdoc IGAC - function getMultiMessageReceiver(uint256 _chainId) external view returns (address _mmaReceiver) { - _mmaReceiver = multiMessageReceiver[_chainId]; - } - - /// @inheritdoc IGAC - function getMultiMessageCaller() external view returns (address _mmaCaller) { - _mmaCaller = allowedCaller; - } } diff --git a/src/controllers/GovernanceTimelock.sol b/src/controllers/GovernanceTimelock.sol index 18c6bc8..b75c007 100644 --- a/src/controllers/GovernanceTimelock.sol +++ b/src/controllers/GovernanceTimelock.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.9; /// interfaces -import "../interfaces/IGovernanceTimelock.sol"; +import "../interfaces/controllers/IGovernanceTimelock.sol"; /// libraries import "../libraries/Error.sol"; diff --git a/src/controllers/MessageReceiverGAC.sol b/src/controllers/MessageReceiverGAC.sol new file mode 100644 index 0000000..99c0349 --- /dev/null +++ b/src/controllers/MessageReceiverGAC.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-only + +pragma solidity >=0.8.9; + +import "./GAC.sol"; +import "../interfaces/IMultiBridgeMessageReceiver.sol"; + +contract MessageReceiverGAC is GAC { + event MultiBridgeMessageReceiverUpdated(address indexed oldMMR, address indexed newMMR); + + address private multiBridgeMsgReceiver; + + function setMultiBridgeMessageReceiver(address _mmaReceiver) external onlyOwner { + if (_mmaReceiver == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + address oldMMR = multiBridgeMsgReceiver; + multiBridgeMsgReceiver = _mmaReceiver; + + emit MultiBridgeMessageReceiverUpdated(oldMMR, _mmaReceiver); + } + + function getMultiBridgeMessageReceiver() external view returns (address) { + return multiBridgeMsgReceiver; + } +} diff --git a/src/controllers/MessageSenderGAC.sol b/src/controllers/MessageSenderGAC.sol new file mode 100644 index 0000000..697d979 --- /dev/null +++ b/src/controllers/MessageSenderGAC.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-only + +pragma solidity >=0.8.9; + +/// library imports +import "openzeppelin-contracts/contracts/access/Ownable.sol"; + +import {Error} from "../libraries/Error.sol"; +import {GAC} from "./GAC.sol"; + +contract MessageSenderGAC is GAC { + /*/////////////////////////////////////////////////////////////// + EVENT + //////////////////////////////////////////////////////////////*/ + event DstGasLimitUpdated(uint256 oldLimit, uint256 newLimit); + + event MultiBridgeMessageCallerUpdated(address indexed mmaCaller); + + event MultiBridgeMessageSenderUpdated(address indexed mmaSender); + + event MultiBridgeMessageReceiverUpdated(uint256 indexed chainId, address indexed oldMMR, address indexed newMMR); + + /*/////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////*/ + uint256 public constant MINIMUM_DST_GAS_LIMIT = 50000; + + /*/////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////*/ + uint256 public dstGasLimit; + + /// @notice is the MMA Core Contracts on the chain + /// @dev leveraged by bridge adapters for authentication + address public multiBridgeMessageSender; + + /// @dev is the authorised caller for the multi-message sender + address public authorisedCaller; + + mapping(uint256 chainId => address mmaReceiver) public remoteMultiBridgeMessageReceiver; + + /*/////////////////////////////////////////////////////////////// + EXTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function setMultiBridgeMessageSender(address _mmaSender) external onlyOwner { + if (_mmaSender == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + + multiBridgeMessageSender = _mmaSender; + + emit MultiBridgeMessageSenderUpdated(_mmaSender); + } + + function setAuthorisedCaller(address newMMSCaller) external onlyOwner { + if (newMMSCaller == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + + authorisedCaller = newMMSCaller; + + emit MultiBridgeMessageCallerUpdated(newMMSCaller); + } + + function setRemoteMultiBridgeMessageReceiver(uint256 _chainId, address _remoteMMR) external onlyOwner { + if (_remoteMMR == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + + if (_chainId == 0) { + revert Error.ZERO_CHAIN_ID(); + } + + address oldRemoteMMR = remoteMultiBridgeMessageReceiver[_chainId]; + remoteMultiBridgeMessageReceiver[_chainId] = _remoteMMR; + + emit MultiBridgeMessageReceiverUpdated(_chainId, oldRemoteMMR, _remoteMMR); + } + + function setGlobalMsgDeliveryGasLimit(uint256 _gasLimit) external onlyOwner { + if (_gasLimit < MINIMUM_DST_GAS_LIMIT) { + revert Error.INVALID_DST_GAS_LIMIT_MIN(); + } + + uint256 oldLimit = dstGasLimit; + dstGasLimit = _gasLimit; + + emit DstGasLimitUpdated(oldLimit, _gasLimit); + } + + /*/////////////////////////////////////////////////////////////// + EXTERNAL VIEW FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function getGlobalMsgDeliveryGasLimit() external view returns (uint256 _gasLimit) { + _gasLimit = dstGasLimit; + } + + function getMultiBridgeMessageSender() external view returns (address _mmaSender) { + _mmaSender = multiBridgeMessageSender; + } + + function getRemoteMultiBridgeMessageReceiver(uint256 _chainId) external view returns (address _mmaReceiver) { + _mmaReceiver = remoteMultiBridgeMessageReceiver[_chainId]; + } + + function getAuthorisedCaller() external view returns (address _mmaCaller) { + _mmaCaller = authorisedCaller; + } +} diff --git a/src/interfaces/IGAC.sol b/src/interfaces/IGAC.sol deleted file mode 100644 index 9ba0d01..0000000 --- a/src/interfaces/IGAC.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -pragma solidity >=0.8.9; - -/// @notice interface for GAC (Global Access Controller) -interface IGAC { - /*/////////////////////////////////////////////////////////////// - EVENT - //////////////////////////////////////////////////////////////*/ - event DstGasLimitUpdated(uint256 oldLimit, uint256 newLimit); - - event MultiMessageCallerUpdated(address indexed mmaCaller); - - event MultiMessageSenderUpdated(address indexed mmaSender); - - event MultiMessageReceiverUpdated(uint256 chainId, address indexed mmaReceiver); - - /*/////////////////////////////////////////////////////////////// - EXTERNAL FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /// @dev sets the multi message sender caller - /// @param _mmaCaller is the multi message caller - function setMultiMessageCaller(address _mmaCaller) external; - - /// @dev sets the multi message sender on same chain - /// @param _mmaSender is the multi message sender contracts - function setMultiMessageSender(address _mmaSender) external; - - /// @dev sets the multi message contracts - /// @param _chainId is the unique chain identifier of the receiver address - /// @param _mmaReceiver is the multi message receiver contracts - function setMultiMessageReceiver(uint256 _chainId, address _mmaReceiver) external; - - /// @dev sets the global message gas limits - /// @param _gasLimit is the limit to be set - function setGlobalMsgDeliveryGasLimit(uint256 _gasLimit) external; - - /*/////////////////////////////////////////////////////////////// - EXTERNAL VIEW FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /// @dev returns `true` if the caller is global access controller - /// @param _caller is the msg.sender to validate - /// @return boolean indicating the validity of the caller - function isGlobalOwner(address _caller) external view returns (bool); - - /// @dev returns the global owner address - /// @return _owner is the global owner address - function getGlobalOwner() external view returns (address _owner); - - /// @dev returns the global message delivery gas limit configured - /// @return _gasLimit is the configured gas limit on dst - function getGlobalMsgDeliveryGasLimit() external view returns (uint256 _gasLimit); - - /// @dev returns the multi message sender on the chain - function getMultiMessageSender() external view returns (address _mmaSender); - - /// @dev returns the multi message caller that can only call the multi message sender contract - function getMultiMessageCaller() external view returns (address _mmaCaller); - - /// @dev returns the multi message receiver on the chain - function getMultiMessageReceiver(uint256 _chainId) external view returns (address _mmaReceiver); -} diff --git a/src/interfaces/IMessageSenderAdapter.sol b/src/interfaces/IMessageSenderAdapter.sol deleted file mode 100644 index 147baa4..0000000 --- a/src/interfaces/IMessageSenderAdapter.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -pragma solidity >=0.8.9; - -import "./EIP5164/SingleMessageDispatcher.sol"; - -/// @dev interface for message sender adapters -interface IMessageSenderAdapter is SingleMessageDispatcher { - /*///////////////////////////////////////////////////////////////// - EVENTS - ////////////////////////////////////////////////////////////////*/ - event ReceiverAdapterUpdated(uint256 indexed dstChainId, address indexed receiverAdapter); - - /*///////////////////////////////////////////////////////////////// - EXTERNAL FUNCTIONS - ////////////////////////////////////////////////////////////////*/ - - /// @dev allows owner to update the receiver adapters on different destination chains - /// @param _dstChainIds are the destination chain identifier - /// @param _receiverAdapters are the corresponding receiver adapter addresses - function updateReceiverAdapter(uint256[] calldata _dstChainIds, address[] calldata _receiverAdapters) external; - - /*///////////////////////////////////////////////////////////////// - EXTERNAL VIEW FUNCTIONS - ////////////////////////////////////////////////////////////////*/ - - /// @dev returns name of the message bridge wrapped by the adapter - function name() external view returns (string memory); - - /// @dev return native token amount in wei required by this message bridge for sending a message - function getMessageFee(uint256 toChainId, address to, bytes calldata data) external view returns (uint256); -} diff --git a/src/interfaces/IMultiBridgeMessageReceiver.sol b/src/interfaces/IMultiBridgeMessageReceiver.sol new file mode 100644 index 0000000..bbff20e --- /dev/null +++ b/src/interfaces/IMultiBridgeMessageReceiver.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.9; + +import "../libraries/Message.sol"; + +/// @dev 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 + ); + + /// @notice emitted when a message has been queued for execution in the destination timelock contract + /// @param msgId is the unique identifier of the message + /// @param target is the address of the final target address that will be called once the timelock matures + /// @param nativeValue is the value that will be passed to the target address through low-level call + /// @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 MessageExecuted( + 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); + + /// @notice emitted when the quorum for message validity is updated + /// @param oldQuorum is the old quorum value + /// @param newQuorum is the new quorum value + event QuorumUpdated(uint64 oldQuorum, uint64 newQuorum); + + /// @notice Receive messages from allowed bridge receiver adapters. + /// @dev Every receiver adapter should call this function with decoded MessageLibrary.Message + /// @param _message is the message to be received + function receiveMessage(MessageLibrary.Message calldata _message) external; + + /// @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 executeMessage(bytes32 _msgId) 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; + + /// @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 + function updateQuorum(uint64 _quorum) external; + + /// @notice updates the the list of receiver adapters and the quorum for message validity + /// @param _newQuorum is the new quorum value + /// @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 updateQuorumAndReceiverAdapter( + uint64 _newQuorum, + address[] calldata _receiverAdapters, + bool[] calldata _operations + ) external; +} diff --git a/src/interfaces/IMultiMessageReceiver.sol b/src/interfaces/IMultiMessageReceiver.sol deleted file mode 100644 index 466522a..0000000 --- a/src/interfaces/IMultiMessageReceiver.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity >=0.8.9; - -import "../libraries/Message.sol"; - -interface IMultiMessageReceiver { - /*///////////////////////////////////////////////////////////////// - STRUCTS - ////////////////////////////////////////////////////////////////*/ - struct ExecutionData { - address target; - bytes callData; - uint256 value; - uint256 nonce; - uint256 expiration; - } - - /*///////////////////////////////////////////////////////////////// - EVENTS - ////////////////////////////////////////////////////////////////*/ - event ReceiverAdapterUpdated(address indexed receiverAdapter, bool add); - event QuorumUpdated(uint64 oldValue, uint64 newValue); - event SingleBridgeMsgReceived( - bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter - ); - event MessageExecuted( - bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData - ); - - /*///////////////////////////////////////////////////////////////// - EXTERNAL FUNCTIONS - ////////////////////////////////////////////////////////////////*/ - - /// @notice Receive messages from allowed bridge receiver adapters. - /// @dev Every receiver adapter should call this function with decoded MessageLibrary.Message - function receiveMessage(MessageLibrary.Message calldata _message) external; -} diff --git a/src/interfaces/IMessageReceiverAdapter.sol b/src/interfaces/adapters/IMessageReceiverAdapter.sol similarity index 96% rename from src/interfaces/IMessageReceiverAdapter.sol rename to src/interfaces/adapters/IMessageReceiverAdapter.sol index 6f7f275..2796faa 100644 --- a/src/interfaces/IMessageReceiverAdapter.sol +++ b/src/interfaces/adapters/IMessageReceiverAdapter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.9; -import "./EIP5164/MessageExecutor.sol"; +import "../EIP5164/MessageExecutor.sol"; //// @dev interface for message receiver adapters interface IMessageReceiverAdapter is MessageExecutor { diff --git a/src/interfaces/adapters/IMessageSenderAdapter.sol b/src/interfaces/adapters/IMessageSenderAdapter.sol new file mode 100644 index 0000000..23d8e27 --- /dev/null +++ b/src/interfaces/adapters/IMessageSenderAdapter.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-3.0-only + +pragma solidity >=0.8.9; + +import "../EIP5164/SingleMessageDispatcher.sol"; + +/// @dev common interface for all message sender adapters of messaging bridges +interface IMessageSenderAdapter is SingleMessageDispatcher { + /// @notice emitted when a the sender's corresponding receiver adapter on a remote chain is changed + /// @param dstChainId is the destination chain for which the receiver adapter is updated + /// @param oldReceiver is the old receiver adapter address + /// @param newReceiver is the new receiver adapter address + event ReceiverAdapterUpdated(uint256 indexed dstChainId, address indexed oldReceiver, address indexed newReceiver); + + /// @notice allows owner to update the receiver adapters on different destination chains + /// @param _dstChainIds are the destination chain IDs for which the receiver adapters are to be updated + /// @param _receiverAdapters receiver adapter addresses for the corresponding destination chain ids in _dstChainIds + function updateReceiverAdapter(uint256[] calldata _dstChainIds, address[] calldata _receiverAdapters) external; + + /// @notice returns name of the message bridge wrapped by the adapter + function name() external view returns (string memory); + + /// @notice return the fee (in native token wei) that would be charged by the bridge for the provided remote call + /// @param _toChainId is the destination chain id + /// @param _to is the destination address on the destination chain + /// @param _data is the data to be sent to the destination chain + function getMessageFee(uint256 _toChainId, address _to, bytes calldata _data) external view returns (uint256); + + /// @notice returns the bridge receiver adapter address for a given destination chain id + /// @param _chainId is the destination chain whose receiver adapter address is to be returned + function getReceiverAdapter(uint256 _chainId) external view returns (address); +} diff --git a/src/interfaces/controllers/IGAC.sol b/src/interfaces/controllers/IGAC.sol new file mode 100644 index 0000000..f25bca7 --- /dev/null +++ b/src/interfaces/controllers/IGAC.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0-only + +pragma solidity >=0.8.9; + +/// @notice interface for GAC (Global Access Controller) +interface IGAC { + /// @dev returns `true` if the caller is global access controller + /// @param _caller is the msg.sender to validate + /// @return boolean indicating the validity of the caller + function isGlobalOwner(address _caller) external view returns (bool); + + /// @dev returns the global owner address + /// @return _owner is the global owner address + function getGlobalOwner() external view returns (address _owner); +} diff --git a/src/interfaces/IGovernanceTimelock.sol b/src/interfaces/controllers/IGovernanceTimelock.sol similarity index 100% rename from src/interfaces/IGovernanceTimelock.sol rename to src/interfaces/controllers/IGovernanceTimelock.sol diff --git a/src/libraries/Message.sol b/src/libraries/Message.sol index f88f198..9b04d9c 100644 --- a/src/libraries/Message.sol +++ b/src/libraries/Message.sol @@ -7,7 +7,7 @@ library MessageLibrary { /// @dev Message indicates a remote call to target contract on destination chain. /// @param srcChainId is the id of chain where this message is sent from /// @param dstChainId is the id of chain where this message is sent to - /// @param nonce is an incrementing number held by MultiMessageSender to ensure msgId uniqueness + /// @param nonce is an incrementing number held by MultiBridgeMessageSender.sol to ensure msgId uniqueness /// @param target is the contract to be called on dst chain /// @param callData is the data to be sent to target by low-level call(eg. address(target).call(callData)) /// @param nativeValue is the native token value to be sent to target in the low-level call(eg. address(target).call{value: nativeValue}(callData)) diff --git a/test/Setup.t.sol b/test/Setup.t.sol index 2050971..8e60dc3 100644 --- a/test/Setup.t.sol +++ b/test/Setup.t.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.9; /// library imports import {Test, Vm} from "forge-std/Test.sol"; -import "forge-std/console.sol"; /// @dev imports from Pigeon Helper (Facilitate State Transfer Mocks) import {WormholeHelper} from "pigeon/wormhole/WormholeHelper.sol"; @@ -17,10 +16,12 @@ import {AxelarSenderAdapter} from "src/adapters/axelar/AxelarSenderAdapter.sol"; import {AxelarReceiverAdapter} from "src/adapters/axelar/AxelarReceiverAdapter.sol"; import {GAC} from "src/controllers/GAC.sol"; +import {MessageSenderGAC} from "src/controllers/MessageSenderGAC.sol"; +import {MessageReceiverGAC} from "src/controllers/MessageReceiverGAC.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; /// @dev can inherit the setup in tests abstract contract Setup is Test { @@ -94,10 +95,10 @@ abstract contract Setup is Test { fork[ETHEREUM_CHAIN_ID] = vm.createSelectFork(vm.envString("ETH_FORK_URL")); vm.deal(caller, 100 ether); - fork[56] = vm.createSelectFork(vm.envString("BSC_FORK_URL")); + fork[BSC_CHAIN_ID] = vm.createSelectFork(vm.envString("BSC_FORK_URL")); vm.deal(caller, 100 ether); - fork[137] = vm.createSelectFork(vm.envString("POLYGON_FORK_URL")); + fork[POLYGON_CHAIN_ID] = vm.createSelectFork(vm.envString("POLYGON_FORK_URL")); vm.deal(caller, 100 ether); /// @dev deploys controller contract to all chains @@ -133,9 +134,15 @@ abstract contract Setup is Test { uint256 chainId = ALL_CHAINS[i]; vm.selectFork(fork[chainId]); - GAC gac = new GAC{salt: _salt}(); - gac.setMultiMessageCaller(caller); - contractAddress[chainId][bytes("GAC")] = address(gac); + address gac; + if (chainId == SRC_CHAIN_ID) { + MessageSenderGAC senderGAC = new MessageSenderGAC{salt: _salt}(); + senderGAC.setAuthorisedCaller(caller); + gac = address(senderGAC); + } else { + gac = address(new MessageReceiverGAC{salt: _salt}()); + } + contractAddress[chainId][bytes("GAC")] = gac; unchecked { ++i; @@ -146,24 +153,23 @@ abstract contract Setup is Test { /// @dev deploys the wormhole adapters to all configured chains function _deployWormholeAdapters() internal { /// @notice deploy source adapter to SRC_CHAIN (ETH) - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); + vm.selectFork(fork[SRC_CHAIN_ID]); - contractAddress[ETHEREUM_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")] = address( - new WormholeSenderAdapter{salt: _salt}(ETH_RELAYER, contractAddress[ETHEREUM_CHAIN_ID][bytes("GAC")]) - ); + contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")] = + address(new WormholeSenderAdapter{salt: _salt}(ETH_RELAYER, contractAddress[SRC_CHAIN_ID][bytes("GAC")])); uint256 len = DST_CHAINS.length; /// @notice deploy receiver adapters to all DST_CHAINS address[] memory _receiverAdapters = new address[](len); - uint16 wEthereumID = _wormholeChainId(ETHEREUM_CHAIN_ID); + uint16 srcChainId = _wormholeChainId(SRC_CHAIN_ID); for (uint256 i; i < len;) { uint256 chainId = DST_CHAINS[i]; vm.selectFork(fork[chainId]); address receiverAdapter = address( - new WormholeReceiverAdapter{salt: _salt}(WORMHOLE_RELAYERS[i], contractAddress[chainId][bytes("GAC")], wEthereumID) + new WormholeReceiverAdapter{salt: _salt}(WORMHOLE_RELAYERS[i], srcChainId, contractAddress[chainId][bytes("GAC")]) ); contractAddress[chainId][bytes("WORMHOLE_RECEIVER_ADAPTER")] = receiverAdapter; _receiverAdapters[i] = receiverAdapter; @@ -174,12 +180,13 @@ abstract contract Setup is Test { } /// @dev sets some configs to sender adapter (ETH_CHAIN_ADAPTER) - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); + vm.selectFork(fork[SRC_CHAIN_ID]); - WormholeSenderAdapter(contractAddress[ETHEREUM_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")]) - .updateReceiverAdapter(DST_CHAINS, _receiverAdapters); + WormholeSenderAdapter(contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")]).updateReceiverAdapter( + DST_CHAINS, _receiverAdapters + ); - WormholeSenderAdapter(contractAddress[ETHEREUM_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")]).setChainIdMap( + WormholeSenderAdapter(contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")]).setChainIdMap( DST_CHAINS, WORMHOLE_CHAIN_IDS ); } @@ -187,9 +194,9 @@ abstract contract Setup is Test { /// @dev deploys the axelar adapters to all configured chains function _deployAxelarAdapters() internal { /// @notice deploy source adapter to Ethereum - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); - contractAddress[1][bytes("AXELAR_SENDER_ADAPTER")] = address( - new AxelarSenderAdapter{salt: _salt}(ETH_GAS_SERVICE, ETH_GATEWAY, contractAddress[1][bytes("GAC")]) + vm.selectFork(fork[SRC_CHAIN_ID]); + contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")] = address( + new AxelarSenderAdapter{salt: _salt}(ETH_GAS_SERVICE, ETH_GATEWAY, contractAddress[SRC_CHAIN_ID][bytes("GAC")]) ); uint256 len = DST_CHAINS.length; @@ -202,7 +209,7 @@ abstract contract Setup is Test { vm.selectFork(fork[chainId]); address receiverAdapter = address( - new AxelarReceiverAdapter{salt: _salt}(AXELAR_GATEWAYS[i], contractAddress[chainId][bytes("GAC")], "ethereum") + new AxelarReceiverAdapter{salt: _salt}(AXELAR_GATEWAYS[i], "ethereum", contractAddress[chainId][bytes("GAC")]) ); contractAddress[chainId][bytes("AXELAR_RECEIVER_ADAPTER")] = receiverAdapter; _receiverAdapters[i] = receiverAdapter; @@ -212,13 +219,13 @@ abstract contract Setup is Test { } } - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); + vm.selectFork(fork[SRC_CHAIN_ID]); - AxelarSenderAdapter(contractAddress[1][bytes("AXELAR_SENDER_ADAPTER")]).updateReceiverAdapter( + AxelarSenderAdapter(contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")]).updateReceiverAdapter( DST_CHAINS, _receiverAdapters ); - AxelarSenderAdapter(contractAddress[1][bytes("AXELAR_SENDER_ADAPTER")]).setChainIdMap( + AxelarSenderAdapter(contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")]).setChainIdMap( DST_CHAINS, AXELAR_CHAIN_IDS ); } @@ -226,12 +233,12 @@ abstract contract Setup is Test { /// @dev deploys the amb helpers to all configured chains function _deployHelpers() internal { /// @notice deploy amb helpers to Ethereum - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); - contractAddress[ETHEREUM_CHAIN_ID][bytes("WORMHOLE_HELPER")] = address(new WormholeHelper()); - contractAddress[ETHEREUM_CHAIN_ID][bytes("AXELAR_HELPER")] = address(new AxelarHelper()); + vm.selectFork(fork[SRC_CHAIN_ID]); + contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_HELPER")] = address(new WormholeHelper()); + contractAddress[SRC_CHAIN_ID][bytes("AXELAR_HELPER")] = address(new AxelarHelper()); - vm.allowCheatcodes(contractAddress[1][bytes("WORMHOLE_HELPER")]); - vm.allowCheatcodes(contractAddress[1][bytes("AXELAR_HELPER")]); + vm.allowCheatcodes(contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_HELPER")]); + vm.allowCheatcodes(contractAddress[SRC_CHAIN_ID][bytes("AXELAR_HELPER")]); /// @notice deploy amb helpers to BSC, POLYGON & ARB for (uint256 i; i < DST_CHAINS.length;) { @@ -253,16 +260,16 @@ abstract contract Setup is Test { /// @dev deploys the mma sender and receiver adapters to all configured chains function _deployCoreContracts() internal { /// @notice deploy mma sender to ETHEREUM - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); - contractAddress[ETHEREUM_CHAIN_ID][bytes("MMA_SENDER")] = - address(new MultiMessageSender{salt: _salt}(contractAddress[ETHEREUM_CHAIN_ID][bytes("GAC")])); + vm.selectFork(fork[SRC_CHAIN_ID]); + contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")] = + address(new MultiBridgeMessageSender{salt: _salt}(contractAddress[SRC_CHAIN_ID][bytes("GAC")])); /// @notice deploy amb helpers to BSC & POLYGON for (uint256 i; i < DST_CHAINS.length; i++) { uint256 chainId = DST_CHAINS[i]; vm.selectFork(fork[chainId]); - address mmaReceiver = address(new MultiMessageReceiver{salt: _salt}()); + address mmaReceiver = address(new MultiBridgeMessageReceiver{salt: _salt}()); contractAddress[chainId][bytes("MMA_RECEIVER")] = mmaReceiver; contractAddress[chainId][bytes("TIMELOCK")] = address(address(new GovernanceTimelock{salt: _salt}(mmaReceiver, 3 days))); @@ -272,20 +279,21 @@ abstract contract Setup is Test { /// @dev setup core contracts function _setupCoreContracts() internal { /// setup mma sender adapters - vm.selectFork(fork[ETHEREUM_CHAIN_ID]); + vm.selectFork(fork[SRC_CHAIN_ID]); vm.startPrank(owner); address[] memory _senderAdapters = new address[](2); - _senderAdapters[0] = contractAddress[1][bytes("WORMHOLE_SENDER_ADAPTER")]; - _senderAdapters[1] = contractAddress[1][bytes("AXELAR_SENDER_ADAPTER")]; + _senderAdapters[0] = contractAddress[SRC_CHAIN_ID][bytes("WORMHOLE_SENDER_ADAPTER")]; + _senderAdapters[1] = contractAddress[SRC_CHAIN_ID][bytes("AXELAR_SENDER_ADAPTER")]; + + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).addSenderAdapters(_senderAdapters); - MultiMessageSender(contractAddress[1][bytes("MMA_SENDER")]).addSenderAdapters(_senderAdapters); + MessageSenderGAC senderGAC = MessageSenderGAC(contractAddress[SRC_CHAIN_ID][bytes("GAC")]); + senderGAC.setMultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]); /// setup mma receiver adapters for (uint256 i; i < DST_CHAINS.length;) { uint256 chainId = DST_CHAINS[i]; - /// setup receiver adapters - vm.selectFork(fork[chainId]); address[] memory _receiverAdapters = new address[](2); _receiverAdapters[0] = contractAddress[chainId][bytes("WORMHOLE_RECEIVER_ADAPTER")]; @@ -295,40 +303,18 @@ abstract contract Setup is Test { _operations[0] = true; _operations[1] = true; - MultiMessageReceiver(contractAddress[DST_CHAINS[i]][bytes("MMA_RECEIVER")]).initialize( - ETHEREUM_CHAIN_ID, _receiverAdapters, _operations, 2, contractAddress[chainId]["TIMELOCK"] + /// setup receiver adapters + vm.selectFork(fork[chainId]); + address dstMMReceiver = contractAddress[chainId][bytes("MMA_RECEIVER")]; + MultiBridgeMessageReceiver(dstMMReceiver).initialize( + SRC_CHAIN_ID, _receiverAdapters, _operations, 2, contractAddress[chainId]["TIMELOCK"] ); - unchecked { - ++i; - } - } - - /// setup the core contracts to GAC - for (uint256 i; i < ALL_CHAINS.length;) { - uint256 chainId = ALL_CHAINS[i]; + MessageReceiverGAC receiverGAC = MessageReceiverGAC(contractAddress[chainId][bytes("GAC")]); + receiverGAC.setMultiBridgeMessageReceiver(dstMMReceiver); - vm.selectFork(fork[chainId]); - vm.startPrank(owner); - - /// @dev mma sender is only available on chain id 1 - if (chainId == 1) { - GAC(contractAddress[chainId][bytes("GAC")]).setMultiMessageSender( - contractAddress[chainId][bytes("MMA_SENDER")] - ); - } - for (uint256 j; j < ALL_CHAINS.length;) { - /// @dev mma receiver is not available on chain id 1 - if (ALL_CHAINS[j] != 1) { - GAC(contractAddress[chainId][bytes("GAC")]).setMultiMessageReceiver( - ALL_CHAINS[j], contractAddress[ALL_CHAINS[j]][bytes("MMA_RECEIVER")] - ); - } - - unchecked { - ++j; - } - } + vm.selectFork(fork[SRC_CHAIN_ID]); + senderGAC.setRemoteMultiBridgeMessageReceiver(chainId, dstMMReceiver); unchecked { ++i; @@ -345,11 +331,11 @@ abstract contract Setup is Test { vm.selectFork(fork[chainId]); WormholeReceiverAdapter(contractAddress[chainId]["WORMHOLE_RECEIVER_ADAPTER"]).updateSenderAdapter( - contractAddress[ETHEREUM_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"] + contractAddress[SRC_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"] ); AxelarReceiverAdapter(contractAddress[chainId]["AXELAR_RECEIVER_ADAPTER"]).updateSenderAdapter( - contractAddress[ETHEREUM_CHAIN_ID]["AXELAR_SENDER_ADAPTER"] + contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"] ); unchecked { @@ -411,15 +397,15 @@ abstract contract Setup is Test { /// @dev returns the relayer of wormhole for chain id function _wormholeRelayer(uint256 _chainId) internal pure returns (address) { - if (_chainId == 1) { + if (_chainId == ETHEREUM_CHAIN_ID) { return ETH_RELAYER; } - if (_chainId == 56) { + if (_chainId == BSC_CHAIN_ID) { return BSC_RELAYER; } - if (_chainId == 137) { + if (_chainId == POLYGON_CHAIN_ID) { return POLYGON_RELAYER; } @@ -446,7 +432,7 @@ abstract contract Setup is Test { /// @dev gets the message id from msg logs function _getMsgId(Vm.Log[] memory logs) internal pure returns (bytes32 msgId) { for (uint256 i; i < logs.length; i++) { - if (logs[i].topics[0] == keccak256("SingleBridgeMsgReceived(bytes32,string,uint256,address)")) { + if (logs[i].topics[0] == keccak256("BridgeMessageReceived(bytes32,string,uint256,address)")) { msgId = logs[i].topics[1]; } } diff --git a/test/contracts-mock/ZeroAddressReceiverGac.sol b/test/contracts-mock/ZeroAddressReceiverGAC.sol similarity index 57% rename from test/contracts-mock/ZeroAddressReceiverGac.sol rename to test/contracts-mock/ZeroAddressReceiverGAC.sol index 3047a84..e08882e 100644 --- a/test/contracts-mock/ZeroAddressReceiverGac.sol +++ b/test/contracts-mock/ZeroAddressReceiverGAC.sol @@ -2,18 +2,18 @@ pragma solidity >=0.8.9; /// @dev A mock GAC with zero address receiver -contract ZeroAddressReceiverGac { +contract ZeroAddressReceiverGAC { address immutable caller; constructor(address _caller) { caller = _caller; } - function getMultiMessageReceiver(uint256) external pure returns (address _mmaReceiver) { + function getRemoteMultiBridgeMessageReceiver(uint256) external pure returns (address _mmaReceiver) { return address(0); } - function getMultiMessageCaller() external view returns (address) { + function getAuthorisedCaller() external view returns (address) { return caller; } } diff --git a/test/integration-tests/GracePeriodExpiry.t.sol b/test/integration-tests/GracePeriodExpiry.t.sol index a457086..0e75ef1 100644 --- a/test/integration-tests/GracePeriodExpiry.t.sol +++ b/test/integration-tests/GracePeriodExpiry.t.sol @@ -8,8 +8,8 @@ import {Vm} from "forge-std/Test.sol"; import "test/Setup.t.sol"; import "test/contracts-mock/MockUniswapReceiver.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -31,7 +31,7 @@ contract GracePeriodExpiryTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( DST_CHAIN_ID, address(target), abi.encode(MockUniswapReceiver.setValue.selector, ""), @@ -51,7 +51,7 @@ contract GracePeriodExpiryTest is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (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 36cc312..e7b9936 100644 --- a/test/integration-tests/MultiMessageAggregation.t.sol +++ b/test/integration-tests/MultiMessageAggregation.t.sol @@ -8,12 +8,12 @@ import {Vm} from "forge-std/Test.sol"; import "test/Setup.t.sol"; import "test/contracts-mock/MockUniswapReceiver.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; -contract MultiMessageAggregationTest is Setup { +contract MultiBridgeMessageAggregationTest is Setup { MockUniswapReceiver target; /// @dev initializes the setup @@ -31,7 +31,7 @@ contract MultiMessageAggregationTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( DST_CHAIN_ID, address(target), abi.encode(MockUniswapReceiver.setValue.selector, ""), @@ -51,7 +51,7 @@ contract MultiMessageAggregationTest is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (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 4a3dad0..ef2cd67 100644 --- a/test/integration-tests/RemoteAdapterAdd.t.sol +++ b/test/integration-tests/RemoteAdapterAdd.t.sol @@ -7,8 +7,8 @@ import {Vm} from "forge-std/Test.sol"; /// local imports import "test/Setup.t.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -56,10 +56,10 @@ contract RemoteAdapterAdd is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( DST_CHAIN_ID, address(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]), - abi.encodeWithSelector(MultiMessageReceiver.updateReceiverAdapters.selector, adaptersToAdd, operation), + abi.encodeWithSelector(MultiBridgeMessageReceiver.updateReceiverAdapters.selector, adaptersToAdd, operation), 0, EXPIRATION_CONSTANT, refundAddress @@ -76,7 +76,7 @@ contract RemoteAdapterAdd is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); @@ -87,7 +87,7 @@ contract RemoteAdapterAdd is Setup { ); for (uint256 j; j < adaptersToAdd.length; ++j) { - bool isTrusted = MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) + 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 b36c3a2..c92a058 100644 --- a/test/integration-tests/RemoteAdapterRemove.t.sol +++ b/test/integration-tests/RemoteAdapterRemove.t.sol @@ -7,8 +7,8 @@ import {Vm} from "forge-std/Test.sol"; /// local imports import "test/Setup.t.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -61,11 +61,14 @@ contract RemoteAdapterRemove is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( DST_CHAIN_ID, address(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]), abi.encodeWithSelector( - MultiMessageReceiver.updateQuorumAndReceiverAdapter.selector, newQuorum, adaptersToRemove, operation + MultiBridgeMessageReceiver.updateQuorumAndReceiverAdapter.selector, + newQuorum, + adaptersToRemove, + operation ), 0, EXPIRATION_CONSTANT, @@ -83,7 +86,7 @@ contract RemoteAdapterRemove is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); @@ -94,12 +97,12 @@ contract RemoteAdapterRemove is Setup { ); /// @dev validates quorum post update - uint256 currQuorum = MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); + 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 = MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) + bool isTrusted = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]) .isTrustedExecutor(adaptersToRemove[j]); assert(!isTrusted); } @@ -115,7 +118,7 @@ contract RemoteAdapterRemove is Setup { operation[0] = true; vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); - MultiMessageReceiver(contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]).updateReceiverAdapters( + 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 930594a..ba092b8 100644 --- a/test/integration-tests/RemoteSetQuorum.t.sol +++ b/test/integration-tests/RemoteSetQuorum.t.sol @@ -7,8 +7,8 @@ import {Vm} from "forge-std/Test.sol"; /// local imports import "test/Setup.t.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -28,10 +28,10 @@ contract RemoteQuorumUpdate is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( DST_CHAIN_ID, address(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]), - abi.encodeWithSelector(MultiMessageReceiver.updateQuorum.selector, newQuorum), + abi.encodeWithSelector(MultiBridgeMessageReceiver.updateQuorum.selector, newQuorum), 0, EXPIRATION_CONSTANT, refundAddress @@ -49,11 +49,11 @@ contract RemoteQuorumUpdate is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); - uint256 oldQuorum = MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); + uint256 oldQuorum = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); assertEq(oldQuorum, 2); /// increment the time by 3 days (delay time) @@ -62,7 +62,7 @@ contract RemoteQuorumUpdate is Setup { txId, finalTarget, value, data, eta ); - uint256 currQuorum = MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).quorum(); + 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 bdd4bb8..ba83fc1 100644 --- a/test/integration-tests/RemoteTimelockUpdate.t.sol +++ b/test/integration-tests/RemoteTimelockUpdate.t.sol @@ -7,8 +7,8 @@ import {Vm} from "forge-std/Test.sol"; /// local imports import "test/Setup.t.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -28,7 +28,7 @@ contract RemoteTimelockUpdate is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( POLYGON_CHAIN_ID, address(contractAddress[POLYGON_CHAIN_ID][bytes("TIMELOCK")]), abi.encodeWithSelector(GovernanceTimelock.setDelay.selector, newDelay), @@ -49,7 +49,7 @@ contract RemoteTimelockUpdate is Setup { vm.selectFork(fork[POLYGON_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[POLYGON_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); diff --git a/test/integration-tests/TimelockCheck.t.sol b/test/integration-tests/TimelockCheck.t.sol index df51a1a..3a731ec 100644 --- a/test/integration-tests/TimelockCheck.t.sol +++ b/test/integration-tests/TimelockCheck.t.sol @@ -8,8 +8,8 @@ import {Vm} from "forge-std/Test.sol"; import "test/Setup.t.sol"; import "test/contracts-mock/MockUniswapReceiver.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; import {Error} from "src/libraries/Error.sol"; import {GovernanceTimelock} from "src/controllers/GovernanceTimelock.sol"; @@ -33,7 +33,7 @@ contract TimelockCheckTest is Setup { /// send cross-chain message using MMA infra vm.recordLogs(); - MultiMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( + MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID][bytes("MMA_SENDER")]).remoteCall{value: 2 ether}( DST_CHAIN_ID, address(target), abi.encode(MockUniswapReceiver.setValue.selector, ""), @@ -53,7 +53,7 @@ contract TimelockCheckTest is Setup { vm.selectFork(fork[DST_CHAIN_ID]); vm.recordLogs(); /// execute the message and move it to governance timelock contract - MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); + MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]).executeMessage(msgId); (uint256 txId, address finalTarget, uint256 value, bytes memory data, uint256 eta) = _getExecParams(vm.getRecordedLogs()); diff --git a/test/unit-tests/MessageReceiverGAC.t.sol b/test/unit-tests/MessageReceiverGAC.t.sol new file mode 100644 index 0000000..271d067 --- /dev/null +++ b/test/unit-tests/MessageReceiverGAC.t.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.9; + +/// library imports +import {Vm} from "forge-std/Test.sol"; + +import "openzeppelin-contracts/contracts/access/Ownable.sol"; + +/// local imports +import "../Setup.t.sol"; +import "../contracts-mock/ZeroAddressReceiverGAC.sol"; +import "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "../../src/interfaces/controllers/IGAC.sol"; +import "src/libraries/Error.sol"; +import "src/libraries/Message.sol"; + +contract MessageReceiverGACTest is Setup { + event MultiBridgeMessageReceiverUpdated(address indexed oldReceiver, address indexed newReceiver); + + MessageReceiverGAC receiverGAC; + + /// @dev initializes the setup + function setUp() public override { + super.setUp(); + vm.selectFork(fork[DST_CHAIN_ID]); + receiverGAC = MessageReceiverGAC(contractAddress[DST_CHAIN_ID]["GAC"]); + } + + /// @dev constructor + function test_constructor() public { + // checks existing setup + assertEq(address(Ownable(address(receiverGAC)).owner()), owner); + } + + /// @dev sets multi message receiver + function test_set_multi_message_receiver() public { + vm.startPrank(owner); + + vm.expectEmit(true, true, true, true, address(receiverGAC)); + emit MultiBridgeMessageReceiverUpdated(address(receiverGAC.getMultiBridgeMessageReceiver()), address(42)); + + receiverGAC.setMultiBridgeMessageReceiver(address(42)); + + assertEq(receiverGAC.getMultiBridgeMessageReceiver(), address(42)); + } + + /// @dev only owner can set multi message receiver + function test_set_multi_message_receiver_only_owner() public { + vm.startPrank(caller); + + vm.expectRevert("Ownable: caller is not the owner"); + receiverGAC.setMultiBridgeMessageReceiver(address(42)); + } + + /// @dev cannot set multi message receiver to zero address + function test_set_multi_message_receiver_zero_address() public { + vm.startPrank(owner); + + vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); + receiverGAC.setMultiBridgeMessageReceiver(address(0)); + } + + /// @dev checks if address is the global owner + function test_is_global_owner() public { + assertTrue(receiverGAC.isGlobalOwner(owner)); + assertFalse(receiverGAC.isGlobalOwner(caller)); + } + + /// @dev gets the global owner + function test_get_global_owner() public { + assertEq(receiverGAC.getGlobalOwner(), owner); + } +} diff --git a/test/unit-tests/GAC.t.sol b/test/unit-tests/MessageSenderGAC.t.sol similarity index 58% rename from test/unit-tests/GAC.t.sol rename to test/unit-tests/MessageSenderGAC.t.sol index 117ba33..2757b65 100644 --- a/test/unit-tests/GAC.t.sol +++ b/test/unit-tests/MessageSenderGAC.t.sol @@ -9,23 +9,23 @@ import "openzeppelin-contracts/contracts/access/Ownable.sol"; /// local imports import "../Setup.t.sol"; import "../contracts-mock/FailingSenderAdapter.sol"; -import "../contracts-mock/ZeroAddressReceiverGac.sol"; -import "src/interfaces/IMessageSenderAdapter.sol"; -import "src/interfaces/IMultiMessageReceiver.sol"; -import "src/interfaces/IGAC.sol"; +import "../contracts-mock/ZeroAddressReceiverGAC.sol"; +import "../../src/interfaces/adapters/IMessageSenderAdapter.sol"; +import "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "../../src/interfaces/controllers/IGAC.sol"; import "src/libraries/Error.sol"; import "src/libraries/Message.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; -contract GACTest is Setup { +contract MessageSenderGACTest is Setup { event DstGasLimitUpdated(uint256 oldLimit, uint256 newLimit); - event MultiMessageCallerUpdated(address indexed mmaCaller); - event MultiMessageSenderUpdated(address indexed mmaSender); - event MultiMessageReceiverUpdated(uint256 chainId, address indexed mmaReceiver); + event MultiBridgeMessageCallerUpdated(address indexed mmaCaller); + event MultiBridgeMessageSenderUpdated(address indexed mmaSender); + event MultiBridgeMessageReceiverUpdated(uint256 indexed chainId, address indexed oldMMR, address indexed newMMR); address senderAddr; address receiverAddr; - IGAC gac; + MessageSenderGAC senderGAC; /// @dev initializes the setup function setUp() public override { @@ -34,25 +34,25 @@ contract GACTest is Setup { vm.selectFork(fork[SRC_CHAIN_ID]); senderAddr = contractAddress[SRC_CHAIN_ID]["MMA_SENDER"]; receiverAddr = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; - gac = IGAC(contractAddress[SRC_CHAIN_ID]["GAC"]); + senderGAC = MessageSenderGAC(contractAddress[SRC_CHAIN_ID]["GAC"]); } /// @dev constructor function test_constructor() public { // checks existing setup - assertEq(address(Ownable(address(gac)).owner()), owner); + assertEq(address(Ownable(address(senderGAC)).owner()), owner); } /// @dev sets multi message sender function test_set_multi_message_sender() public { vm.startPrank(owner); - vm.expectEmit(true, true, true, true, address(gac)); - emit MultiMessageSenderUpdated(address(42)); + vm.expectEmit(true, true, true, true, address(senderGAC)); + emit MultiBridgeMessageSenderUpdated(address(42)); - gac.setMultiMessageSender(address(42)); + senderGAC.setMultiBridgeMessageSender(address(42)); - assertEq(gac.getMultiMessageSender(), address(42)); + assertEq(senderGAC.getMultiBridgeMessageSender(), address(42)); } /// @dev only owner can set multi message sender @@ -60,7 +60,7 @@ contract GACTest is Setup { vm.startPrank(caller); vm.expectRevert("Ownable: caller is not the owner"); - gac.setMultiMessageSender(address(42)); + senderGAC.setMultiBridgeMessageSender(address(42)); } /// @dev cannot set multi message sender to zero address @@ -68,19 +68,19 @@ contract GACTest is Setup { vm.startPrank(owner); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - gac.setMultiMessageSender(address(0)); + senderGAC.setMultiBridgeMessageSender(address(0)); } /// @dev sets multi message caller function test_set_multi_message_caller() public { vm.startPrank(owner); - vm.expectEmit(true, true, true, true, address(gac)); - emit MultiMessageCallerUpdated(address(42)); + vm.expectEmit(true, true, true, true, address(senderGAC)); + emit MultiBridgeMessageCallerUpdated(address(42)); - gac.setMultiMessageCaller(address(42)); + senderGAC.setAuthorisedCaller(address(42)); - assertEq(gac.getMultiMessageCaller(), address(42)); + assertEq(senderGAC.getAuthorisedCaller(), address(42)); } /// @dev only owner can set multi message caller @@ -88,7 +88,7 @@ contract GACTest is Setup { vm.startPrank(caller); vm.expectRevert("Ownable: caller is not the owner"); - gac.setMultiMessageCaller(address(42)); + senderGAC.setAuthorisedCaller(address(42)); } /// @dev cannot set multi message caller to zero address @@ -96,19 +96,21 @@ contract GACTest is Setup { vm.startPrank(owner); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - gac.setMultiMessageCaller(address(0)); + senderGAC.setAuthorisedCaller(address(0)); } /// @dev sets multi message receiver function test_set_multi_message_receiver() public { vm.startPrank(owner); - vm.expectEmit(true, true, true, true, address(gac)); - emit MultiMessageReceiverUpdated(DST_CHAIN_ID, address(42)); + vm.expectEmit(true, true, true, true, address(senderGAC)); + emit MultiBridgeMessageReceiverUpdated( + DST_CHAIN_ID, senderGAC.getRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID), address(42) + ); - gac.setMultiMessageReceiver(DST_CHAIN_ID, address(42)); + senderGAC.setRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID, address(42)); - assertEq(gac.getMultiMessageReceiver(DST_CHAIN_ID), address(42)); + assertEq(senderGAC.getRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID), address(42)); } /// @dev only owner can set multi message receiver @@ -116,7 +118,7 @@ contract GACTest is Setup { vm.startPrank(caller); vm.expectRevert("Ownable: caller is not the owner"); - gac.setMultiMessageReceiver(DST_CHAIN_ID, address(42)); + senderGAC.setRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID, address(42)); } /// @dev cannot set multi message receiver to zero address @@ -124,7 +126,7 @@ contract GACTest is Setup { vm.startPrank(owner); vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - gac.setMultiMessageReceiver(DST_CHAIN_ID, address(0)); + senderGAC.setRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID, address(0)); } /// @dev cannot set multi message receiver on zero chain ID @@ -132,20 +134,20 @@ contract GACTest is Setup { vm.startPrank(owner); vm.expectRevert(Error.ZERO_CHAIN_ID.selector); - gac.setMultiMessageReceiver(0, address(42)); + senderGAC.setRemoteMultiBridgeMessageReceiver(0, address(42)); } /// @dev sets global message delivery gas limit function test_set_global_msg_delivery_gas_limit() public { vm.startPrank(owner); - uint256 oldLimit = gac.getGlobalMsgDeliveryGasLimit(); - vm.expectEmit(true, true, true, true, address(gac)); + uint256 oldLimit = senderGAC.getGlobalMsgDeliveryGasLimit(); + vm.expectEmit(true, true, true, true, address(senderGAC)); emit DstGasLimitUpdated(oldLimit, 420000); - gac.setGlobalMsgDeliveryGasLimit(420000); + senderGAC.setGlobalMsgDeliveryGasLimit(420000); - assertEq(gac.getGlobalMsgDeliveryGasLimit(), 420000); + assertEq(senderGAC.getGlobalMsgDeliveryGasLimit(), 420000); } /// @dev only owner can set global message delivery gas limit @@ -153,7 +155,7 @@ contract GACTest is Setup { vm.startPrank(caller); vm.expectRevert("Ownable: caller is not the owner"); - gac.setGlobalMsgDeliveryGasLimit(420000); + senderGAC.setGlobalMsgDeliveryGasLimit(420000); } /// @dev cannot set a gas limit lower than the minimum @@ -161,17 +163,17 @@ contract GACTest is Setup { vm.startPrank(owner); vm.expectRevert(Error.INVALID_DST_GAS_LIMIT_MIN.selector); - gac.setGlobalMsgDeliveryGasLimit(30000); + senderGAC.setGlobalMsgDeliveryGasLimit(30000); } /// @dev checks if address is the global owner function test_is_global_owner() public { - assertTrue(gac.isGlobalOwner(owner)); - assertFalse(gac.isGlobalOwner(caller)); + assertTrue(senderGAC.isGlobalOwner(owner)); + assertFalse(senderGAC.isGlobalOwner(caller)); } /// @dev gets the global owner function test_get_global_owner() public { - assertEq(gac.getGlobalOwner(), owner); + assertEq(senderGAC.getGlobalOwner(), owner); } } diff --git a/test/unit-tests/MultiMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol similarity index 94% rename from test/unit-tests/MultiMessageReceiver.t.sol rename to test/unit-tests/MultiBridgeMessageReceiver.t.sol index 363b36c..8b6a2a5 100644 --- a/test/unit-tests/MultiMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -9,19 +9,19 @@ import "test/Setup.t.sol"; import "src/adapters/wormhole/WormholeReceiverAdapter.sol"; import "src/libraries/Error.sol"; import "src/libraries/Message.sol"; -import {MultiMessageReceiver} from "src/MultiMessageReceiver.sol"; +import {MultiBridgeMessageReceiver} from "src/MultiBridgeMessageReceiver.sol"; -contract MultiMessageReceiverTest is Setup { - event ReceiverAdapterUpdated(address indexed receiverAdapter, bool add); +contract MultiBridgeMessageReceiverTest is Setup { + event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add); event QuorumUpdated(uint64 oldValue, uint64 newValue); - event SingleBridgeMsgReceived( + event BridgeMessageReceived( bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter ); event MessageExecuted( bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData ); - MultiMessageReceiver receiver; + MultiBridgeMessageReceiver receiver; address wormholeAdapterAddr; address axelarAdapterAddr; address timelockAddr; @@ -31,7 +31,7 @@ contract MultiMessageReceiverTest is Setup { super.setUp(); vm.selectFork(fork[DST_CHAIN_ID]); - receiver = MultiMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]); + receiver = MultiBridgeMessageReceiver(contractAddress[DST_CHAIN_ID][bytes("MMA_RECEIVER")]); wormholeAdapterAddr = contractAddress[DST_CHAIN_ID]["WORMHOLE_RECEIVER_ADAPTER"]; axelarAdapterAddr = contractAddress[DST_CHAIN_ID]["AXELAR_RECEIVER_ADAPTER"]; timelockAddr = contractAddress[DST_CHAIN_ID]["TIMELOCK"]; @@ -47,7 +47,7 @@ contract MultiMessageReceiverTest is Setup { operation[0] = true; operation[1] = true; - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); dummyReceiver.initialize(ETHEREUM_CHAIN_ID, adapters, operation, 2, timelockAddr); assertEq(dummyReceiver.quorum(), 2); @@ -67,7 +67,7 @@ contract MultiMessageReceiverTest is Setup { function test_initialize_zero_receiver_adapter() public { vm.startPrank(caller); - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); vm.expectRevert(Error.ZERO_RECEIVER_ADAPTER.selector); dummyReceiver.initialize(ETHEREUM_CHAIN_ID, new address[](0), new bool[](0), 0, address(42)); @@ -77,7 +77,7 @@ contract MultiMessageReceiverTest is Setup { function test_initialize_zero_address_input() public { vm.startPrank(caller); - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); address[] memory adapters = new address[](1); adapters[0] = address(0); @@ -92,7 +92,7 @@ contract MultiMessageReceiverTest is Setup { function test_initialize_quorum_too_large() public { vm.startPrank(caller); - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); address[] memory adapters = new address[](1); adapters[0] = address(42); @@ -107,7 +107,7 @@ contract MultiMessageReceiverTest is Setup { function test_initialize_quorum_larger_than_num_trusted_executors() public { vm.startPrank(caller); - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); address[] memory adapters = new address[](2); adapters[0] = address(42); adapters[1] = address(42); @@ -124,7 +124,7 @@ contract MultiMessageReceiverTest is Setup { function test_initialize_zero_quorum() public { vm.startPrank(caller); - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); address[] memory adapters = new address[](1); adapters[0] = address(42); @@ -139,7 +139,7 @@ contract MultiMessageReceiverTest is Setup { function test_initialize_zero_governance_timelock() public { vm.startPrank(caller); - MultiMessageReceiver dummyReceiver = new MultiMessageReceiver(); + MultiBridgeMessageReceiver dummyReceiver = new MultiBridgeMessageReceiver(); address[] memory adapters = new address[](1); adapters[0] = address(42); @@ -166,7 +166,7 @@ contract MultiMessageReceiverTest is Setup { bytes32 msgId = MessageLibrary.computeMsgId(message); vm.expectEmit(true, true, true, true, address(receiver)); - emit SingleBridgeMsgReceived(msgId, "WORMHOLE", 42, wormholeAdapterAddr); + emit BridgeMessageReceived(msgId, "WORMHOLE", 42, wormholeAdapterAddr); receiver.receiveMessage(message); @@ -435,7 +435,7 @@ contract MultiMessageReceiverTest is Setup { assertFalse(receiver.isTrustedExecutor(address(42))); vm.expectEmit(true, true, true, true, address(receiver)); - emit ReceiverAdapterUpdated(address(42), true); + emit BridgeReceiverAdapterUpdated(address(42), true); receiver.updateReceiverAdapters(updatedAdapters, operations); assertTrue(receiver.isTrustedExecutor(wormholeAdapterAddr)); @@ -456,7 +456,7 @@ contract MultiMessageReceiverTest is Setup { operations[0] = false; vm.expectEmit(true, true, true, true, address(receiver)); - emit ReceiverAdapterUpdated(wormholeAdapterAddr, false); + emit BridgeReceiverAdapterUpdated(wormholeAdapterAddr, false); receiver.updateReceiverAdapters(updatedAdapters, operations); assertFalse(receiver.isTrustedExecutor(wormholeAdapterAddr)); diff --git a/test/unit-tests/MultiMessageSender.t.sol b/test/unit-tests/MultiBridgeMessageSender.t.sol similarity index 94% rename from test/unit-tests/MultiMessageSender.t.sol rename to test/unit-tests/MultiBridgeMessageSender.t.sol index b31e5f0..fc963d8 100644 --- a/test/unit-tests/MultiMessageSender.t.sol +++ b/test/unit-tests/MultiBridgeMessageSender.t.sol @@ -7,16 +7,16 @@ import {Vm} from "forge-std/Test.sol"; /// local imports import "test/Setup.t.sol"; import "test/contracts-mock/FailingSenderAdapter.sol"; -import "test/contracts-mock/ZeroAddressReceiverGac.sol"; -import "src/interfaces/IMessageSenderAdapter.sol"; -import "src/interfaces/IMultiMessageReceiver.sol"; -import "src/interfaces/IGAC.sol"; +import "test/contracts-mock/ZeroAddressReceiverGAC.sol"; +import "../../src/interfaces/adapters/IMessageSenderAdapter.sol"; +import "src/interfaces/IMultiBridgeMessageReceiver.sol"; +import "../../src/interfaces/controllers/IGAC.sol"; import "src/libraries/Error.sol"; import "src/libraries/Message.sol"; -import {MultiMessageSender} from "src/MultiMessageSender.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; -contract MultiMessageSenderTest is Setup { - event MultiMessageSent( +contract MultiBridgeMessageSenderTest is Setup { + event MultiBridgeMessageSent( bytes32 indexed msgId, uint256 nonce, uint256 indexed dstChainId, @@ -30,7 +30,7 @@ contract MultiMessageSenderTest is Setup { event SenderAdapterUpdated(address indexed senderAdapter, bool add); event MessageSendFailed(address indexed senderAdapter, MessageLibrary.Message message); - MultiMessageSender sender; + MultiBridgeMessageSender sender; address receiver; IGAC gac; address wormholeAdapterAddr; @@ -41,7 +41,7 @@ contract MultiMessageSenderTest is Setup { super.setUp(); vm.selectFork(fork[SRC_CHAIN_ID]); - sender = MultiMessageSender(contractAddress[SRC_CHAIN_ID]["MMA_SENDER"]); + sender = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID]["MMA_SENDER"]); receiver = contractAddress[DST_CHAIN_ID]["MMA_RECEIVER"]; gac = IGAC(contractAddress[SRC_CHAIN_ID]["GAC"]); wormholeAdapterAddr = contractAddress[SRC_CHAIN_ID]["WORMHOLE_SENDER_ADAPTER"]; @@ -51,13 +51,13 @@ contract MultiMessageSenderTest is Setup { /// @dev constructor function test_constructor() public { // checks existing setup - assertEq(address(sender.gac()), contractAddress[SRC_CHAIN_ID]["GAC"]); + assertEq(address(sender.senderGAC()), contractAddress[SRC_CHAIN_ID]["GAC"]); } /// @dev cannot be called with zero address GAC function test_constructor_zero_address_input() public { vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new MultiMessageSender(address(0)); + new MultiBridgeMessageSender(address(0)); } /// @dev perform remote call @@ -88,7 +88,7 @@ contract MultiMessageSenderTest is Setup { uint256 fee = sender.estimateTotalMessageFee(DST_CHAIN_ID, receiver, address(42), bytes("42"), 0); vm.expectEmit(true, true, true, true, address(sender)); - emit MultiMessageSent( + emit MultiBridgeMessageSent( msgId, 1, DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, senderAdapters, adapterSuccess ); @@ -143,7 +143,7 @@ contract MultiMessageSenderTest is Setup { IMessageSenderAdapter(wormholeAdapterAddr).getMessageFee(DST_CHAIN_ID, receiver, abi.encode(message)); vm.expectEmit(true, true, true, true, address(sender)); - emit MultiMessageSent( + emit MultiBridgeMessageSent( msgId, 1, DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, senderAdapters, adapterSuccess ); @@ -262,7 +262,7 @@ contract MultiMessageSenderTest is Setup { function test_remote_call_zero_receiver_address() public { vm.startPrank(caller); - MultiMessageSender dummySender = new MultiMessageSender(address(new ZeroAddressReceiverGac(caller))); + MultiBridgeMessageSender dummySender = new MultiBridgeMessageSender(address(new ZeroAddressReceiverGAC(caller))); vm.expectRevert(Error.ZERO_RECEIVER_ADAPTER.selector); dummySender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress); @@ -326,7 +326,7 @@ contract MultiMessageSenderTest is Setup { emit MessageSendFailed(failingAdapterAddr, message); vm.expectEmit(true, true, true, true, address(sender)); - emit MultiMessageSent( + emit MultiBridgeMessageSent( msgId, 1, DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, senderAdapters, adapterSuccess ); @@ -452,7 +452,7 @@ contract MultiMessageSenderTest is Setup { }); uint256 totalFee = sender.estimateTotalMessageFee(DST_CHAIN_ID, receiver, address(42), bytes("42"), 0); - bytes memory data = abi.encodeWithSelector(IMultiMessageReceiver.receiveMessage.selector, message); + bytes memory data = abi.encodeWithSelector(IMultiBridgeMessageReceiver.receiveMessage.selector, message); uint256 expectedTotalFee; expectedTotalFee += IMessageSenderAdapter(wormholeAdapterAddr).getMessageFee(DST_CHAIN_ID, receiver, data); diff --git a/test/unit-tests/adapters/BaseSenderAdapter.t.sol b/test/unit-tests/adapters/BaseSenderAdapter.t.sol index f157c7e..c977a86 100644 --- a/test/unit-tests/adapters/BaseSenderAdapter.t.sol +++ b/test/unit-tests/adapters/BaseSenderAdapter.t.sol @@ -8,12 +8,13 @@ import {Vm} from "forge-std/Test.sol"; import "../../Setup.t.sol"; import "src/libraries/Error.sol"; import {AxelarSenderAdapter} from "src/adapters/axelar/AxelarSenderAdapter.sol"; +import {BaseSenderAdapter} from "src/adapters/BaseSenderAdapter.sol"; contract AxelarSenderAdapterTest is Setup { - event ReceiverAdapterUpdated(uint256 indexed dstChainId, address indexed receiverAdapter); + event ReceiverAdapterUpdated(uint256 indexed dstChainId, address indexed oldReceiver, address indexed newReceiver); // Test base contract with Axelar adapter - AxelarSenderAdapter adapter; + BaseSenderAdapter adapter; /// @dev initializes the setup function setUp() public override { @@ -32,14 +33,14 @@ contract AxelarSenderAdapterTest is Setup { receiverAdapters[1] = address(43); vm.expectEmit(true, true, true, true, address(adapter)); - emit ReceiverAdapterUpdated(BSC_CHAIN_ID, address(42)); + emit ReceiverAdapterUpdated(BSC_CHAIN_ID, adapter.getReceiverAdapter(BSC_CHAIN_ID), address(42)); vm.expectEmit(true, true, true, true, address(adapter)); - emit ReceiverAdapterUpdated(POLYGON_CHAIN_ID, address(43)); + emit ReceiverAdapterUpdated(POLYGON_CHAIN_ID, adapter.getReceiverAdapter(POLYGON_CHAIN_ID), address(43)); adapter.updateReceiverAdapter(DST_CHAINS, receiverAdapters); - assertEq(adapter.receiverAdapters(BSC_CHAIN_ID), address(42)); - assertEq(adapter.receiverAdapters(POLYGON_CHAIN_ID), address(43)); + assertEq(adapter.getReceiverAdapter(BSC_CHAIN_ID), address(42)); + assertEq(adapter.getReceiverAdapter(POLYGON_CHAIN_ID), address(43)); } /// @dev only global owner can update receiver adapter diff --git a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol index c438964..14d9cd6 100644 --- a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol @@ -8,7 +8,7 @@ import {Vm} from "forge-std/Test.sol"; import "../../../Setup.t.sol"; import "../../../contracts-mock/adapters/axelar/MockAxelarGateway.sol"; import "src/adapters/axelar/libraries/StringAddressConversion.sol"; -import "src/MultiMessageReceiver.sol"; +import "src/MultiBridgeMessageReceiver.sol"; import "src/interfaces/EIP5164/MessageExecutor.sol"; import "src/libraries/Error.sol"; import "src/libraries/Message.sol"; @@ -35,26 +35,26 @@ contract AxelarReceiverAdapterTest is Setup { function test_constructor() public { // checks existing setup assertEq(address(adapter.gateway()), POLYGON_GATEWAY); - assertEq(address(adapter.gac()), contractAddress[DST_CHAIN_ID]["GAC"]); + assertEq(address(adapter.receiverGAC()), contractAddress[DST_CHAIN_ID]["GAC"]); assertEq(adapter.senderChain(), "ethereum"); } /// @dev constructor with invalid parameters should fail function test_constructor_zero_gateway_address() public { vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new AxelarReceiverAdapter(address(0), address(42), ""); + new AxelarReceiverAdapter(address(0), "", address(42)); } /// @dev constructor with invalid parameters should fail function test_constructor_zero_gac_address() public { vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new AxelarReceiverAdapter(address(32), address(0), ""); + new AxelarReceiverAdapter(address(32), "", address(0)); } /// @dev constructor cannot be called with zero chain id function test_constructor_zero_chain_id() public { vm.expectRevert(Error.INVALID_SENDER_CHAIN_ID.selector); - new AxelarReceiverAdapter(address(42), address(42), ""); + new AxelarReceiverAdapter(address(42), "", address(42)); } /// @dev gets the name @@ -325,7 +325,7 @@ contract AxelarReceiverAdapterTest is Setup { senderAdapter = contractAddress[SRC_CHAIN_ID]["AXELAR_SENDER_ADAPTER"]; dummyAdapter = - new AxelarReceiverAdapter(address(new MockAxelarGateway(_validateCall)), contractAddress[DST_CHAIN_ID]["GAC"], "ethereum"); + new AxelarReceiverAdapter(address(new MockAxelarGateway(_validateCall)), "ethereum", contractAddress[DST_CHAIN_ID]["GAC"]); dummyAdapter.updateSenderAdapter(senderAdapter); vm.startPrank(contractAddress[DST_CHAIN_ID]["TIMELOCK"]); @@ -334,7 +334,7 @@ contract AxelarReceiverAdapterTest is Setup { receiverAdapters[0] = address(dummyAdapter); bool[] memory operations = new bool[](1); operations[0] = true; - MultiMessageReceiver(receiverAddr).updateReceiverAdapters(receiverAdapters, operations); + MultiBridgeMessageReceiver(receiverAddr).updateReceiverAdapters(receiverAdapters, operations); vm.startPrank(caller); } diff --git a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol index a3cc6b2..bf8f7fb 100644 --- a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol @@ -31,7 +31,7 @@ contract AxelarSenderAdapterTest is Setup { // checks existing setup assertEq(address(adapter.gasService()), ETH_GAS_SERVICE); assertEq(address(adapter.gateway()), ETH_GATEWAY); - assertEq(address(adapter.gac()), contractAddress[SRC_CHAIN_ID]["GAC"]); + assertEq(address(adapter.senderGAC()), contractAddress[SRC_CHAIN_ID]["GAC"]); } /// @dev dispatches message diff --git a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol index f05386e..d05f69b 100644 --- a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol @@ -6,7 +6,7 @@ import {Vm} from "forge-std/Test.sol"; /// local imports import "../../../Setup.t.sol"; -import "src/MultiMessageReceiver.sol"; +import "src/MultiBridgeMessageReceiver.sol"; import "src/interfaces/EIP5164/MessageExecutor.sol"; import "src/libraries/Error.sol"; import "src/libraries/Message.sol"; @@ -32,25 +32,25 @@ contract WormholeReceiverAdapterTest is Setup { function test_constructor() public { // checks existing setup assertEq(address(adapter.relayer()), POLYGON_RELAYER); - assertEq(address(adapter.gac()), contractAddress[DST_CHAIN_ID]["GAC"]); + assertEq(address(adapter.receiverGAC()), contractAddress[DST_CHAIN_ID]["GAC"]); } /// @dev constructor cannot be called with zero address relayer function test_constructor_zero_address_relayer() public { vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new WormholeReceiverAdapter(address(0), address(42), _wormholeChainId(ETHEREUM_CHAIN_ID)); + new WormholeReceiverAdapter(address(0), _wormholeChainId(ETHEREUM_CHAIN_ID), address(42)); } /// @dev constructor cannot be called with zero address GAC function test_constructor_zero_address_gac() public { vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); - new WormholeReceiverAdapter(address(42), address(0), _wormholeChainId(ETHEREUM_CHAIN_ID)); + new WormholeReceiverAdapter(address(42), _wormholeChainId(ETHEREUM_CHAIN_ID), address(0)); } /// @dev constructor cannot be called with zero sender chain id function test_constructor_zero_chain_id() public { vm.expectRevert(Error.INVALID_SENDER_CHAIN_ID.selector); - new WormholeReceiverAdapter(address(42), address(42), uint16(0)); + new WormholeReceiverAdapter(address(42), uint16(0), address(42)); } /// @dev gets the name @@ -87,35 +87,6 @@ contract WormholeReceiverAdapterTest is Setup { adapter.updateSenderAdapter(address(0)); } - /// @dev sets chain ID map - function test_set_chain_id_map() public { - vm.startPrank(owner); - - uint256[] memory origIds = new uint256[](1); - origIds[0] = 1234; - uint16[] memory whIds = new uint16[](1); - whIds[0] = uint16(5678); - adapter.setChainIdMap(origIds, whIds); - - assertEq(adapter.chainIdMap(1234), uint16(5678)); - } - - /// @dev only global owner can set chain ID map - function test_set_chain_id_map_only_global_owner() public { - vm.startPrank(caller); - - vm.expectRevert(Error.CALLER_NOT_OWNER.selector); - adapter.setChainIdMap(new uint256[](0), new uint16[](0)); - } - - /// @dev cannot set chain ID map with mismatched array lengths - function test_set_chain_id_map_array_length_mismatched() public { - vm.startPrank(owner); - - vm.expectRevert(Error.ARRAY_LENGTH_MISMATCHED.selector); - adapter.setChainIdMap(new uint256[](0), new uint16[](1)); - } - /// @dev receives Wormhole message function test_receive_wormhole_messages() public { vm.startPrank(POLYGON_RELAYER); diff --git a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol index 894f144..03dc4cd 100644 --- a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol @@ -30,7 +30,7 @@ contract WormholeSenderAdapterTest is Setup { /// @dev constructor function test_constructor() public { // checks existing setup - assertEq(address(adapter.gac()), contractAddress[SRC_CHAIN_ID]["GAC"]); + assertEq(address(adapter.senderGAC()), contractAddress[SRC_CHAIN_ID]["GAC"]); } /// @dev dispatches message @@ -114,7 +114,7 @@ contract WormholeSenderAdapterTest is Setup { /// @dev gets message fee function test_get_message_fee() public { (uint256 fee,) = IWormholeRelayer(ETH_RELAYER).quoteEVMDeliveryPrice( - adapter.chainIdMap(DST_CHAIN_ID), 0, adapter.gac().getGlobalMsgDeliveryGasLimit() + adapter.chainIdMap(DST_CHAIN_ID), 0, adapter.senderGAC().getGlobalMsgDeliveryGasLimit() ); assertEq(adapter.getMessageFee(DST_CHAIN_ID, address(42), bytes("42")), fee); }