From 16e7dcb64206da2b6463c2002a60ad045bae1ad2 Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 5 Oct 2023 09:50:50 +1100 Subject: [PATCH 1/2] Code cleanup (#96) * Make adapter names consistent across sender and receiver * Fix stale message expiration comment * Remove unnecessary overloaded remoteCall() * User onlyGlobalOwner modifier name consistently * Remove unnecessary getters * Consistently apply underscore for function arg names * Remove unnecessary negative number check * Make wormhole relayer address public * Emit old values when updating authorised caller and sender * Emit missing event in GovernanceTimelock constructor * Move ExecutorAware implementation out of interfaces dir * Improve naming consistency --- src/MultiBridgeMessageReceiver.sol | 34 +++++----- src/MultiBridgeMessageSender.sol | 40 ++---------- src/adapters/BaseSenderAdapter.sol | 13 ++-- src/adapters/axelar/AxelarReceiverAdapter.sol | 34 +++++----- src/adapters/axelar/AxelarSenderAdapter.sol | 44 ++++++------- .../axelar/interfaces/IAxelarExecutable.sol | 16 ++--- .../axelar/interfaces/IAxelarGasService.sol | 10 +-- .../axelar/interfaces/IAxelarGateway.sol | 20 +++--- .../libraries/StringAddressConversion.sol | 8 +-- .../wormhole/WormholeReceiverAdapter.sol | 30 ++++----- .../wormhole/WormholeSenderAdapter.sol | 18 ++--- src/controllers/GAC.sol | 6 +- src/controllers/GovernanceTimelock.sol | 1 + src/controllers/MessageReceiverGAC.sol | 6 +- src/controllers/MessageSenderGAC.sol | 48 +++++--------- src/interfaces/EIP5164/MessageDispatcher.sol | 2 +- .../EIP5164/SingleMessageDispatcher.sol | 6 +- .../adapters/IMessageSenderAdapter.sol | 2 +- .../controllers/IGovernanceTimelock.sol | 2 +- .../EIP5164/ExecutorAware.sol | 0 src/libraries/Message.sol | 2 +- .../contracts-mock/ZeroAddressReceiverGAC.sol | 10 +-- .../integration-tests/GracePeriodExpiry.t.sol | 3 +- .../MultiMessageAggregation.t.sol | 3 +- test/integration-tests/RemoteAdapterAdd.t.sol | 3 +- .../RemoteAdapterRemove.t.sol | 3 +- test/integration-tests/RemoteSetQuorum.t.sol | 3 +- .../RemoteTimelockUpdate.t.sol | 3 +- test/integration-tests/TimelockCheck.t.sol | 3 +- test/unit-tests/GovernanceTimelock.t.sol | 10 +++ test/unit-tests/MessageReceiverGAC.t.sol | 4 +- test/unit-tests/MessageSenderGAC.t.sol | 20 +++--- .../unit-tests/MultiBridgeMessageSender.t.sol | 65 +++++++++++++------ .../adapters/BaseSenderAdapter.t.sol | 8 +-- .../axelar/AxelarReceiverAdapter.t.sol | 2 +- .../adapters/axelar/AxelarSenderAdapter.t.sol | 2 +- .../wormhole/WormholeReceiverAdapter.t.sol | 2 +- .../wormhole/WormholeSenderAdapter.t.sol | 4 +- 38 files changed, 235 insertions(+), 255 deletions(-) rename src/{interfaces => libraries}/EIP5164/ExecutorAware.sol (100%) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 0fbe14d..e9e0843 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -5,7 +5,7 @@ pragma solidity >=0.8.9; import "./interfaces/controllers/IGAC.sol"; import "./interfaces/adapters/IMessageReceiverAdapter.sol"; import "./interfaces/IMultiBridgeMessageReceiver.sol"; -import "./interfaces/EIP5164/ExecutorAware.sol"; +import "./libraries/EIP5164/ExecutorAware.sol"; import "./interfaces/controllers/IGovernanceTimelock.sol"; /// libraries @@ -60,8 +60,8 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar _; } - /// @notice A modifier used for restricting the caller to just the governance timelock contract - modifier onlyOwner() { + /// @notice Restricts the caller to the owner configured in GAC. + modifier onlyGlobalOwner() { if (!gac.isGlobalOwner(msg.sender)) { revert Error.CALLER_NOT_OWNER(); } @@ -129,8 +129,8 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } /// @inheritdoc IMultiBridgeMessageReceiver - function executeMessage(bytes32 msgId) external override { - ExecutionData memory _execData = msgExecData[msgId]; + function executeMessage(bytes32 _msgId) external override { + ExecutionData memory _execData = msgExecData[_msgId]; /// @dev validates if msg execution is not beyond expiration if (block.timestamp > _execData.expiration) { @@ -138,14 +138,14 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } /// @dev validates if msgId is already executed - if (isExecuted[msgId]) { + if (isExecuted[_msgId]) { revert Error.MSG_ID_ALREADY_EXECUTED(); } - isExecuted[msgId] = true; + isExecuted[_msgId] = true; /// @dev validates message quorum - if (msgDeliveryCount[msgId] < quorum) { + if (msgDeliveryCount[_msgId] < quorum) { revert Error.QUORUM_NOT_ACHIEVED(); } @@ -154,12 +154,12 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar _execData.target, _execData.value, _execData.callData ); - emit MessageExecuted(msgId, _execData.target, _execData.value, _execData.nonce, _execData.callData); + emit MessageExecuted(_msgId, _execData.target, _execData.value, _execData.nonce, _execData.callData); } /// @notice update the governance timelock contract. /// @dev called by admin to update the timelock contract - function updateGovernanceTimelock(address _governanceTimelock) external onlyOwner { + function updateGovernanceTimelock(address _governanceTimelock) external onlyGlobalOwner { if (_governanceTimelock == address(0)) { revert Error.ZERO_GOVERNANCE_TIMELOCK(); } @@ -171,7 +171,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) external override - onlyOwner + onlyGlobalOwner { _updateReceiverAdapters(_receiverAdapters, _operations); } @@ -182,7 +182,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar uint64 _newQuorum, address[] calldata _receiverAdapters, bool[] calldata _operations - ) external override onlyOwner { + ) external override onlyGlobalOwner { /// @dev updates quorum here _updateQuorum(_newQuorum); @@ -191,7 +191,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } /// @notice Update power quorum threshold of message execution. - function updateQuorum(uint64 _quorum) external override onlyOwner { + function updateQuorum(uint64 _quorum) external override onlyGlobalOwner { _updateQuorum(_quorum); } @@ -200,15 +200,15 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar ////////////////////////////////////////////////////////////////*/ /// @notice view message info, return (executed, msgPower, delivered adapters) - function getMessageInfo(bytes32 msgId) public view returns (bool, uint256, string[] memory) { - uint256 msgCurrentVotes = msgDeliveryCount[msgId]; + function getMessageInfo(bytes32 _msgId) public view returns (bool, uint256, string[] memory) { + uint256 msgCurrentVotes = msgDeliveryCount[_msgId]; string[] memory successfulBridge = new string[](msgCurrentVotes); if (msgCurrentVotes != 0) { uint256 currIndex; address[] memory executors = getTrustedExecutors(); for (uint256 i; i < executors.length;) { - if (msgDeliveries[msgId][executors[i]]) { + if (msgDeliveries[_msgId][executors[i]]) { successfulBridge[currIndex] = IMessageReceiverAdapter(executors[i]).name(); ++currIndex; } @@ -219,7 +219,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar } } - return (isExecuted[msgId], msgCurrentVotes, successfulBridge); + return (isExecuted[_msgId], msgCurrentVotes, successfulBridge); } /*///////////////////////////////////////////////////////////////// diff --git a/src/MultiBridgeMessageSender.sol b/src/MultiBridgeMessageSender.sol index cfdc9ae..fd69a83 100644 --- a/src/MultiBridgeMessageSender.sol +++ b/src/MultiBridgeMessageSender.sol @@ -95,8 +95,8 @@ contract MultiBridgeMessageSender { MODIFIERS ////////////////////////////////////////////////////////////////*/ - /// @dev checks if msg.sender is the owner configured in GAC - modifier onlyOwner() { + /// @notice Restricts the caller to the owner configured in GAC. + modifier onlyGlobalOwner() { if (msg.sender != senderGAC.getGlobalOwner()) { revert Error.CALLER_NOT_OWNER(); } @@ -105,7 +105,7 @@ contract MultiBridgeMessageSender { /// @dev checks if msg.sender is the authorised caller configured in GAC modifier onlyCaller() { - if (msg.sender != senderGAC.getAuthorisedCaller()) { + if (msg.sender != senderGAC.authorisedCaller()) { revert Error.INVALID_PRIVILEGED_CALLER(); } _; @@ -137,34 +137,6 @@ contract MultiBridgeMessageSender { EXTERNAL FUNCTIONS ////////////////////////////////////////////////////////////////*/ - /// @notice Call a remote function on a destination chain by sending multiple copies of a cross-chain message - /// via all available bridges. This function can only be called by the authorised called configured in the GAC. - /// @dev a fee in native token may be required by each message bridge to send messages. Any native token fee remained - /// will be refunded back to a refund address defined in the _refundAddress parameter. - /// Caller needs to specify fees for each adapter when calling this function. - /// @param _dstChainId is the destination chainId - /// @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 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 - /// @param _fees refers to the fees to pay to each adapter - function remoteCall( - uint256 _dstChainId, - address _target, - bytes calldata _callData, - uint256 _nativeValue, - uint256 _expiration, - address _refundAddress, - uint256[] calldata _fees - ) external payable onlyCaller validateExpiration(_expiration) { - _remoteCall( - RemoteCallArgs( - _dstChainId, _target, _callData, _nativeValue, _expiration, _refundAddress, _fees, new address[](0) - ) - ); - } - /// @param _dstChainId is the destination chainId /// @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)) @@ -193,7 +165,7 @@ contract MultiBridgeMessageSender { /// @notice Add bridge sender adapters /// @param _additions are the adapter address to add, in ascending order with no duplicates - function addSenderAdapters(address[] calldata _additions) external onlyOwner { + function addSenderAdapters(address[] calldata _additions) external onlyGlobalOwner { _checkAdaptersOrder(_additions); address[] memory existings = senderAdapters; @@ -249,7 +221,7 @@ contract MultiBridgeMessageSender { /// @notice Remove bridge sender adapters /// @param _removals are the adapter addresses to remove - function removeSenderAdapters(address[] calldata _removals) external onlyOwner { + function removeSenderAdapters(address[] calldata _removals) external onlyGlobalOwner { _checkAdaptersOrder(_removals); address[] memory existings = senderAdapters; @@ -324,7 +296,7 @@ contract MultiBridgeMessageSender { revert Error.INVALID_REFUND_ADDRESS(); } - mmaReceiver = senderGAC.getRemoteMultiBridgeMessageReceiver(_dstChainId); + mmaReceiver = senderGAC.remoteMultiBridgeMessageReceiver(_dstChainId); if (mmaReceiver == address(0)) { revert Error.ZERO_RECEIVER_ADAPTER(); diff --git a/src/adapters/BaseSenderAdapter.sol b/src/adapters/BaseSenderAdapter.sol index de87fd3..66b26b7 100644 --- a/src/adapters/BaseSenderAdapter.sol +++ b/src/adapters/BaseSenderAdapter.sol @@ -19,7 +19,7 @@ abstract contract BaseSenderAdapter is IMessageSenderAdapter { MODIFIER ////////////////////////////////////////////////////////////////*/ modifier onlyMultiBridgeMessageSender() { - if (msg.sender != senderGAC.getMultiBridgeMessageSender()) { + if (msg.sender != senderGAC.multiBridgeMessageSender()) { revert Error.CALLER_NOT_MULTI_MESSAGE_SENDER(); } _; @@ -72,20 +72,15 @@ abstract contract BaseSenderAdapter is IMessageSenderAdapter { } } - /// @inheritdoc IMessageSenderAdapter - function getReceiverAdapter(uint256 _dstChainId) external view override returns (address) { - return receiverAdapters[_dstChainId]; - } - /*///////////////////////////////////////////////////////////////// HELPER FUNCTIONS ////////////////////////////////////////////////////////////////*/ /// @notice generates a new message id by incrementing nonce - /// @param _toChainId is the destination chainId. + /// @param _receiverChainId is the destination chainId. /// @param _to is the contract address on the destination chain. - function _getNewMessageId(uint256 _toChainId, address _to) internal returns (bytes32 messageId) { - messageId = keccak256(abi.encodePacked(block.chainid, _toChainId, nonce, address(this), _to)); + function _getNewMessageId(uint256 _receiverChainId, address _to) internal returns (bytes32 messageId) { + messageId = keccak256(abi.encodePacked(block.chainid, _receiverChainId, nonce, address(this), _to)); ++nonce; } } diff --git a/src/adapters/axelar/AxelarReceiverAdapter.sol b/src/adapters/axelar/AxelarReceiverAdapter.sol index c9e4ded..3ba60d2 100644 --- a/src/adapters/axelar/AxelarReceiverAdapter.sol +++ b/src/adapters/axelar/AxelarReceiverAdapter.sol @@ -27,7 +27,7 @@ contract AxelarReceiverAdapter is BaseReceiverAdapter, IAxelarExecutable { /*///////////////////////////////////////////////////////////////// STATE VARIABLES ////////////////////////////////////////////////////////////////*/ - string public senderChain; + string public senderChainId; mapping(bytes32 => bool) public isMessageExecuted; mapping(bytes32 => bool) public commandIdStatus; @@ -36,19 +36,21 @@ contract AxelarReceiverAdapter is BaseReceiverAdapter, IAxelarExecutable { CONSTRUCTOR ////////////////////////////////////////////////////////////////*/ /// @param _gateway is axelar gateway contract address. - /// @param _senderChain is the chain id of the sender chain. + /// @param _senderChainId is the chain id of the sender chain. /// @param _receiverGAC is global access controller. - constructor(address _gateway, string memory _senderChain, address _receiverGAC) BaseReceiverAdapter(_receiverGAC) { + constructor(address _gateway, string memory _senderChainId, address _receiverGAC) + BaseReceiverAdapter(_receiverGAC) + { if (_gateway == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - if (bytes(_senderChain).length == 0) { + if (bytes(_senderChainId).length == 0) { revert Error.INVALID_SENDER_CHAIN_ID(); } gateway = IAxelarGateway(_gateway); - senderChain = _senderChain; + senderChainId = _senderChainId; } /*///////////////////////////////////////////////////////////////// @@ -58,32 +60,32 @@ contract AxelarReceiverAdapter is BaseReceiverAdapter, IAxelarExecutable { /// @dev accepts new cross-chain messages from axelar gateway /// @inheritdoc IAxelarExecutable function execute( - bytes32 commandId, - string calldata sourceChain, - string calldata sourceAddress, - bytes calldata payload + bytes32 _commandId, + string calldata _sourceChainId, + string calldata _sourceAddress, + bytes calldata _payload ) external override { /// @dev step-1: validate incoming chain id - if (keccak256(bytes(sourceChain)) != keccak256(bytes(senderChain))) { + if (keccak256(bytes(_sourceChainId)) != keccak256(bytes(senderChainId))) { revert Error.INVALID_SENDER_CHAIN_ID(); } /// @dev step-2: validate the source address - if (sourceAddress.toAddress() != senderAdapter) { + if (_sourceAddress.toAddress() != senderAdapter) { revert Error.INVALID_SENDER_ADAPTER(); } /// @dev step-3: validate the contract call - if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, keccak256(payload))) { + if (!gateway.validateContractCall(_commandId, _sourceChainId, _sourceAddress, keccak256(_payload))) { revert Error.NOT_APPROVED_BY_GATEWAY(); } /// decode the cross-chain payload - AdapterPayload memory decodedPayload = abi.decode(payload, (AdapterPayload)); + AdapterPayload memory decodedPayload = abi.decode(_payload, (AdapterPayload)); bytes32 msgId = decodedPayload.msgId; /// @dev step-4: check for duplicate message - if (commandIdStatus[commandId] || isMessageExecuted[msgId]) { + if (commandIdStatus[_commandId] || isMessageExecuted[msgId]) { revert MessageIdAlreadyExecuted(msgId); } @@ -93,12 +95,12 @@ contract AxelarReceiverAdapter is BaseReceiverAdapter, IAxelarExecutable { } /// @dev step-6: validate the destination - if (decodedPayload.finalDestination != receiverGAC.getMultiBridgeMessageReceiver()) { + if (decodedPayload.finalDestination != receiverGAC.multiBridgeMsgReceiver()) { revert Error.INVALID_FINAL_DESTINATION(); } isMessageExecuted[msgId] = true; - commandIdStatus[commandId] = true; + commandIdStatus[_commandId] = true; MessageLibrary.Message memory _data = abi.decode(decodedPayload.data, (MessageLibrary.Message)); diff --git a/src/adapters/axelar/AxelarSenderAdapter.sol b/src/adapters/axelar/AxelarSenderAdapter.sol index 2633532..b383abb 100644 --- a/src/adapters/axelar/AxelarSenderAdapter.sol +++ b/src/adapters/axelar/AxelarSenderAdapter.sol @@ -12,7 +12,7 @@ import "./interfaces/IAxelarGasService.sol"; import "./libraries/StringAddressConversion.sol"; contract AxelarSenderAdapter is BaseSenderAdapter { - string public constant name = "axelar"; + string public constant name = "AXELAR"; IAxelarGateway public immutable gateway; @@ -35,32 +35,32 @@ contract AxelarSenderAdapter is BaseSenderAdapter { ////////////////////////////////////////////////////////////////*/ /// @dev sendMessage sends a message to Axelar. - /// @param _toChainId The ID of the destination chain. + /// @param _receiverChainId The ID of the destination chain. /// @param _to The address of the contract on the destination chain that will receive the message. /// @param _data The data to be included in the message. - function dispatchMessage(uint256 _toChainId, address _to, bytes calldata _data) + function dispatchMessage(uint256 _receiverChainId, address _to, bytes calldata _data) external payable override onlyMultiBridgeMessageSender returns (bytes32 msgId) { - address receiverAdapter = receiverAdapters[_toChainId]; + address receiverAdapter = receiverAdapters[_receiverChainId]; if (receiverAdapter == address(0)) { revert Error.ZERO_RECEIVER_ADAPTER(); } - string memory destinationChain = chainIdMap[_toChainId]; + string memory destinationChain = chainIdMap[_receiverChainId]; - if (bytes(destinationChain).length <= 0) { + if (bytes(destinationChain).length == 0) { revert Error.INVALID_DST_CHAIN(); } - msgId = _getNewMessageId(_toChainId, _to); + msgId = _getNewMessageId(_receiverChainId, _to); _callContract(destinationChain, receiverAdapter, msgId, _to, _data); - emit MessageDispatched(msgId, msg.sender, _toChainId, _to, _data); + emit MessageDispatched(msgId, msg.sender, _receiverChainId, _to, _data); } /// @dev maps the MMA chain id to bridge specific chain id @@ -87,26 +87,26 @@ contract AxelarSenderAdapter is BaseSenderAdapter { ////////////////////////////////////////////////////////////////*/ /// @dev Sends a message to the IAxelarRelayer contract for relaying to the Axelar Network. - /// @param destinationChain The name of the destination chain. - /// @param receiverAdapter The address of the adapter on the destination chain that will receive the message. - /// @param msgId The ID of the message to be relayed. - /// @param multibridgeReceiver The address of the MultibridgeReceiver contract on the destination chain that will receive the message. - /// @param data The bytes data to pass to the contract on the destination chain. + /// @param _destinationChain The name of the destination chain. + /// @param _receiverAdapter The address of the adapter on the destination chain that will receive the message. + /// @param _msgId The ID of the message to be relayed. + /// @param _multibridgeReceiver The address of the MultibridgeReceiver contract on the destination chain that will receive the message. + /// @param _data The bytes data to pass to the contract on the destination chain. function _callContract( - string memory destinationChain, - address receiverAdapter, - bytes32 msgId, - address multibridgeReceiver, - bytes calldata data + string memory _destinationChain, + address _receiverAdapter, + bytes32 _msgId, + address _multibridgeReceiver, + bytes calldata _data ) internal { - string memory receiverAdapterInString = StringAddressConversion.toString(receiverAdapter); + string memory receiverAdapterInString = StringAddressConversion.toString(_receiverAdapter); bytes memory payload = - abi.encode(AdapterPayload(msgId, address(msg.sender), receiverAdapter, multibridgeReceiver, data)); + abi.encode(AdapterPayload(_msgId, address(msg.sender), _receiverAdapter, _multibridgeReceiver, _data)); gasService.payNativeGasForContractCall{value: msg.value}( - msg.sender, destinationChain, receiverAdapterInString, payload, msg.sender + msg.sender, _destinationChain, receiverAdapterInString, payload, msg.sender ); - gateway.callContract(destinationChain, receiverAdapterInString, payload); + gateway.callContract(_destinationChain, receiverAdapterInString, payload); } } diff --git a/src/adapters/axelar/interfaces/IAxelarExecutable.sol b/src/adapters/axelar/interfaces/IAxelarExecutable.sol index d7e2499..a73743d 100644 --- a/src/adapters/axelar/interfaces/IAxelarExecutable.sol +++ b/src/adapters/axelar/interfaces/IAxelarExecutable.sol @@ -2,14 +2,14 @@ pragma solidity >=0.8.9; interface IAxelarExecutable { - /// @param commandId is axelar specific message identifier - /// @param sourceChain is the identifier for source chain - /// @param sourceAddress is the message sender address on source chain - /// @param payload is the cross-chain message sent + /// @param _commandId is axelar specific message identifier + /// @param _sourceChainId is the identifier for source chain + /// @param _sourceAddress is the message sender address on source chain + /// @param _payload is the cross-chain message sent function execute( - bytes32 commandId, - string calldata sourceChain, - string calldata sourceAddress, - bytes calldata payload + bytes32 _commandId, + string calldata _sourceChainId, + string calldata _sourceAddress, + bytes calldata _payload ) external; } diff --git a/src/adapters/axelar/interfaces/IAxelarGasService.sol b/src/adapters/axelar/interfaces/IAxelarGasService.sol index f3b1142..c440c3a 100644 --- a/src/adapters/axelar/interfaces/IAxelarGasService.sol +++ b/src/adapters/axelar/interfaces/IAxelarGasService.sol @@ -5,10 +5,10 @@ pragma solidity >=0.8.9; interface IAxelarGasService { // This is called on the source chain before calling the gateway to execute a remote contract. function payNativeGasForContractCall( - address sender, - string calldata destinationChain, - string calldata destinationAddress, - bytes calldata payload, - address refundAddress + address _sender, + string calldata _destinationChain, + string calldata _destinationAddress, + bytes calldata _payload, + address _refundAddress ) external payable; } diff --git a/src/adapters/axelar/interfaces/IAxelarGateway.sol b/src/adapters/axelar/interfaces/IAxelarGateway.sol index d395f09..02e5bd0 100644 --- a/src/adapters/axelar/interfaces/IAxelarGateway.sol +++ b/src/adapters/axelar/interfaces/IAxelarGateway.sol @@ -2,21 +2,21 @@ pragma solidity >=0.8.9; interface IAxelarGateway { - function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload) + function callContract(string calldata _destinationChain, string calldata _contractAddress, bytes calldata _payload) external; function isContractCallApproved( - bytes32 commandId, - string calldata sourceChain, - string calldata sourceAddress, - address contractAddress, - bytes32 payloadHash + bytes32 _commandId, + string calldata _sourceChain, + string calldata _sourceAddress, + address _contractAddress, + bytes32 _payloadHash ) external view returns (bool); function validateContractCall( - bytes32 commandId, - string calldata sourceChain, - string calldata sourceAddress, - bytes32 payloadHash + bytes32 _commandId, + string calldata _sourceChain, + string calldata _sourceAddress, + bytes32 _payloadHash ) external returns (bool); } diff --git a/src/adapters/axelar/libraries/StringAddressConversion.sol b/src/adapters/axelar/libraries/StringAddressConversion.sol index 3e4bb58..a3cdc79 100644 --- a/src/adapters/axelar/libraries/StringAddressConversion.sol +++ b/src/adapters/axelar/libraries/StringAddressConversion.sol @@ -4,8 +4,8 @@ pragma solidity >=0.8.9; library StringAddressConversion { error InvalidAddressString(); - function toString(address addr) internal pure returns (string memory) { - bytes memory addressBytes = abi.encodePacked(addr); + function toString(address _addr) internal pure returns (string memory) { + bytes memory addressBytes = abi.encodePacked(_addr); uint256 length = addressBytes.length; bytes memory characters = "0123456789abcdef"; bytes memory stringBytes = new bytes(2 + addressBytes.length * 2); @@ -20,8 +20,8 @@ library StringAddressConversion { return string(stringBytes); } - function toAddress(string memory addressString) internal pure returns (address) { - bytes memory stringBytes = bytes(addressString); + function toAddress(string memory _addressString) internal pure returns (address) { + bytes memory stringBytes = bytes(_addressString); uint160 addressNumber = 0; uint8 stringByte; diff --git a/src/adapters/wormhole/WormholeReceiverAdapter.sol b/src/adapters/wormhole/WormholeReceiverAdapter.sol index 162a366..309ded3 100644 --- a/src/adapters/wormhole/WormholeReceiverAdapter.sol +++ b/src/adapters/wormhole/WormholeReceiverAdapter.sol @@ -21,7 +21,7 @@ import "../BaseReceiverAdapter.sol"; contract WormholeReceiverAdapter is BaseReceiverAdapter, IWormholeReceiver { string public constant name = "WORMHOLE"; address public immutable relayer; - uint16 public immutable senderChain; + uint16 public immutable senderChainId; /*///////////////////////////////////////////////////////////////// STATE VARIABLES @@ -46,20 +46,20 @@ contract WormholeReceiverAdapter is BaseReceiverAdapter, IWormholeReceiver { ////////////////////////////////////////////////////////////////*/ /// @param _relayer is wormhole relayer. - /// @param _senderChain is the chain id of the sender chain. + /// @param _senderChainId 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, uint16 _senderChain, address _receiverGAC) BaseReceiverAdapter(_receiverGAC) { + constructor(address _relayer, uint16 _senderChainId, address _receiverGAC) BaseReceiverAdapter(_receiverGAC) { if (_relayer == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - if (_senderChain == uint16(0)) { + if (_senderChainId == uint16(0)) { revert Error.INVALID_SENDER_CHAIN_ID(); } relayer = _relayer; - senderChain = _senderChain; + senderChainId = _senderChainId; } /*///////////////////////////////////////////////////////////////// @@ -68,34 +68,34 @@ contract WormholeReceiverAdapter is BaseReceiverAdapter, IWormholeReceiver { /// @inheritdoc IWormholeReceiver function receiveWormholeMessages( - bytes memory payload, + bytes memory _payload, bytes[] memory, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash + bytes32 _sourceAddress, + uint16 _sourceChainId, + bytes32 _deliveryHash ) public payable override onlyRelayerContract { /// @dev validate the caller (done in modifier) /// @dev step-1: validate incoming chain id - if (sourceChain != senderChain) { + if (_sourceChainId != senderChainId) { revert Error.INVALID_SENDER_CHAIN_ID(); } /// @dev step-2: validate the source address - if (TypeCasts.bytes32ToAddress(sourceAddress) != senderAdapter) { + if (TypeCasts.bytes32ToAddress(_sourceAddress) != senderAdapter) { revert Error.INVALID_SENDER_ADAPTER(); } /// decode the cross-chain payload - AdapterPayload memory decodedPayload = abi.decode(payload, (AdapterPayload)); + AdapterPayload memory decodedPayload = abi.decode(_payload, (AdapterPayload)); bytes32 msgId = decodedPayload.msgId; /// @dev step-3: check for duplicate message - if (isMessageExecuted[msgId] || deliveryHashStatus[deliveryHash]) { + if (isMessageExecuted[msgId] || deliveryHashStatus[_deliveryHash]) { revert MessageIdAlreadyExecuted(msgId); } isMessageExecuted[decodedPayload.msgId] = true; - deliveryHashStatus[deliveryHash] = true; + deliveryHashStatus[_deliveryHash] = true; /// @dev step-4: validate the receive adapter if (decodedPayload.receiverAdapter != address(this)) { @@ -103,7 +103,7 @@ contract WormholeReceiverAdapter is BaseReceiverAdapter, IWormholeReceiver { } /// @dev step-5: validate the destination - if (decodedPayload.finalDestination != receiverGAC.getMultiBridgeMessageReceiver()) { + if (decodedPayload.finalDestination != receiverGAC.multiBridgeMsgReceiver()) { revert Error.INVALID_FINAL_DESTINATION(); } diff --git a/src/adapters/wormhole/WormholeSenderAdapter.sol b/src/adapters/wormhole/WormholeSenderAdapter.sol index aaf9e58..38504cf 100644 --- a/src/adapters/wormhole/WormholeSenderAdapter.sol +++ b/src/adapters/wormhole/WormholeSenderAdapter.sol @@ -12,8 +12,8 @@ import "../../libraries/Types.sol"; /// @notice sender adapter for wormhole bridge contract WormholeSenderAdapter is BaseSenderAdapter { - string public constant name = "wormhole"; - IWormholeRelayer private immutable relayer; + string public constant name = "WORMHOLE"; + IWormholeRelayer public immutable relayer; /*///////////////////////////////////////////////////////////////// STATE VARIABLES @@ -32,38 +32,38 @@ contract WormholeSenderAdapter is BaseSenderAdapter { ////////////////////////////////////////////////////////////////*/ /// @notice sends a message via wormhole relayer - function dispatchMessage(uint256 _toChainId, address _to, bytes calldata _data) + function dispatchMessage(uint256 _receiverChainId, address _to, bytes calldata _data) external payable override onlyMultiBridgeMessageSender returns (bytes32 msgId) { - address receiverAdapter = receiverAdapters[_toChainId]; + address receiverAdapter = receiverAdapters[_receiverChainId]; if (receiverAdapter == address(0)) { revert Error.ZERO_RECEIVER_ADAPTER(); } - uint16 wormChainId = chainIdMap[_toChainId]; + uint16 wormChainId = chainIdMap[_receiverChainId]; if (wormChainId == 0) { revert Error.INVALID_DST_CHAIN(); } - msgId = _getNewMessageId(_toChainId, _to); + msgId = _getNewMessageId(_receiverChainId, _to); bytes memory payload = abi.encode(AdapterPayload(msgId, msg.sender, receiverAdapter, _to, _data)); relayer.sendPayloadToEvm{value: msg.value}( wormChainId, receiverAdapter, payload, - 0, /// @dev no receiver value since just passing message - senderGAC.getGlobalMsgDeliveryGasLimit() + 0, + senderGAC.msgDeliveryGasLimit() ); - emit MessageDispatched(msgId, msg.sender, _toChainId, _to, _data); + emit MessageDispatched(msgId, msg.sender, _receiverChainId, _to, _data); } /// @dev maps the MMA chain id to bridge specific chain id diff --git a/src/controllers/GAC.sol b/src/controllers/GAC.sol index b16a492..86c6343 100644 --- a/src/controllers/GAC.sol +++ b/src/controllers/GAC.sol @@ -21,11 +21,7 @@ contract GAC is IGAC, Ownable { /// @inheritdoc IGAC function isGlobalOwner(address _caller) external view override returns (bool) { - if (_caller == owner()) { - return true; - } - - return false; + return _caller == owner(); } /// @inheritdoc IGAC diff --git a/src/controllers/GovernanceTimelock.sol b/src/controllers/GovernanceTimelock.sol index e7ce856..0176068 100644 --- a/src/controllers/GovernanceTimelock.sol +++ b/src/controllers/GovernanceTimelock.sol @@ -65,6 +65,7 @@ contract GovernanceTimelock is IGovernanceTimelock { emit AdminUpdated(address(0), _admin); delay = _delay; + emit DelayUpdated(0, _delay); } /*///////////////////////////////////////////////////////////////// diff --git a/src/controllers/MessageReceiverGAC.sol b/src/controllers/MessageReceiverGAC.sol index 99c0349..4f77e26 100644 --- a/src/controllers/MessageReceiverGAC.sol +++ b/src/controllers/MessageReceiverGAC.sol @@ -8,7 +8,7 @@ import "../interfaces/IMultiBridgeMessageReceiver.sol"; contract MessageReceiverGAC is GAC { event MultiBridgeMessageReceiverUpdated(address indexed oldMMR, address indexed newMMR); - address private multiBridgeMsgReceiver; + address public multiBridgeMsgReceiver; function setMultiBridgeMessageReceiver(address _mmaReceiver) external onlyOwner { if (_mmaReceiver == address(0)) { @@ -19,8 +19,4 @@ contract MessageReceiverGAC is GAC { emit MultiBridgeMessageReceiverUpdated(oldMMR, _mmaReceiver); } - - function getMultiBridgeMessageReceiver() external view returns (address) { - return multiBridgeMsgReceiver; - } } diff --git a/src/controllers/MessageSenderGAC.sol b/src/controllers/MessageSenderGAC.sol index 697d979..e14e7a0 100644 --- a/src/controllers/MessageSenderGAC.sol +++ b/src/controllers/MessageSenderGAC.sol @@ -14,9 +14,9 @@ contract MessageSenderGAC is GAC { //////////////////////////////////////////////////////////////*/ event DstGasLimitUpdated(uint256 oldLimit, uint256 newLimit); - event MultiBridgeMessageCallerUpdated(address indexed mmaCaller); + event MultiBridgeMessageCallerUpdated(address indexed oldAuthCaller, address indexed newAuthCaller); - event MultiBridgeMessageSenderUpdated(address indexed mmaSender); + event MultiBridgeMessageSenderUpdated(address indexed oldMMS, address indexed newMMS); event MultiBridgeMessageReceiverUpdated(uint256 indexed chainId, address indexed oldMMR, address indexed newMMR); @@ -28,7 +28,7 @@ contract MessageSenderGAC is GAC { /*/////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ - uint256 public dstGasLimit; + uint256 public msgDeliveryGasLimit; /// @notice is the MMA Core Contracts on the chain /// @dev leveraged by bridge adapters for authentication @@ -43,24 +43,26 @@ contract MessageSenderGAC is GAC { EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ - function setMultiBridgeMessageSender(address _mmaSender) external onlyOwner { - if (_mmaSender == address(0)) { + function setMultiBridgeMessageSender(address _newMMS) external onlyOwner { + if (_newMMS == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - multiBridgeMessageSender = _mmaSender; + address oldMMS = multiBridgeMessageSender; + multiBridgeMessageSender = _newMMS; - emit MultiBridgeMessageSenderUpdated(_mmaSender); + emit MultiBridgeMessageSenderUpdated(oldMMS, _newMMS); } - function setAuthorisedCaller(address newMMSCaller) external onlyOwner { - if (newMMSCaller == address(0)) { + function setAuthorisedCaller(address _newAuthCaller) external onlyOwner { + if (_newAuthCaller == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - authorisedCaller = newMMSCaller; + address oldAuthCaller = authorisedCaller; + authorisedCaller = _newAuthCaller; - emit MultiBridgeMessageCallerUpdated(newMMSCaller); + emit MultiBridgeMessageCallerUpdated(oldAuthCaller, _newAuthCaller); } function setRemoteMultiBridgeMessageReceiver(uint256 _chainId, address _remoteMMR) external onlyOwner { @@ -83,29 +85,9 @@ contract MessageSenderGAC is GAC { revert Error.INVALID_DST_GAS_LIMIT_MIN(); } - uint256 oldLimit = dstGasLimit; - dstGasLimit = _gasLimit; + uint256 oldLimit = msgDeliveryGasLimit; + msgDeliveryGasLimit = _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/EIP5164/MessageDispatcher.sol b/src/interfaces/EIP5164/MessageDispatcher.sol index fce2a26..5e2c15b 100644 --- a/src/interfaces/EIP5164/MessageDispatcher.sol +++ b/src/interfaces/EIP5164/MessageDispatcher.sol @@ -11,6 +11,6 @@ interface MessageDispatcher { * @dev The MessageDispatched event MUST be emitted by the MessageDispatcher when an individual message is dispatched. */ event MessageDispatched( - bytes32 indexed messageId, address indexed from, uint256 indexed toChainId, address to, bytes data + bytes32 indexed messageId, address indexed from, uint256 indexed receiverChainId, address to, bytes data ); } diff --git a/src/interfaces/EIP5164/SingleMessageDispatcher.sol b/src/interfaces/EIP5164/SingleMessageDispatcher.sol index f910b79..22deabd 100644 --- a/src/interfaces/EIP5164/SingleMessageDispatcher.sol +++ b/src/interfaces/EIP5164/SingleMessageDispatcher.sol @@ -6,14 +6,14 @@ import "./MessageDispatcher.sol"; /** * @dev The SingleMessageDispatcher is an extension of MessageDispatcher that defines a method, dispatchMessage, - * for dispatching an individual message to be executed on the toChainId. + * for dispatching an individual message to be executed on the receiverChainId. * More about SingleMessageDispatcher of EIP5164, see https://eips.ethereum.org/EIPS/eip-5164#singlemessagedispatcher. */ interface SingleMessageDispatcher is MessageDispatcher { /** - * @dev A method for dispatching an individual message to be executed on the toChainId. + * @dev A method for dispatching an individual message to be executed on the receiver chain. */ - function dispatchMessage(uint256 toChainId, address to, bytes calldata data) + function dispatchMessage(uint256 _receiverChainId, address _to, bytes calldata _data) external payable returns (bytes32 messageId); diff --git a/src/interfaces/adapters/IMessageSenderAdapter.sol b/src/interfaces/adapters/IMessageSenderAdapter.sol index 2dcd692..ba9e17b 100644 --- a/src/interfaces/adapters/IMessageSenderAdapter.sol +++ b/src/interfaces/adapters/IMessageSenderAdapter.sol @@ -27,5 +27,5 @@ interface IMessageSenderAdapter is SingleMessageDispatcher { /// @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); + function receiverAdapters(uint256 _chainId) external view returns (address); } diff --git a/src/interfaces/controllers/IGovernanceTimelock.sol b/src/interfaces/controllers/IGovernanceTimelock.sol index 93972f4..eaf3a77 100644 --- a/src/interfaces/controllers/IGovernanceTimelock.sol +++ b/src/interfaces/controllers/IGovernanceTimelock.sol @@ -61,5 +61,5 @@ interface IGovernanceTimelock { /// @notice Changes the admin. /// This function can only be invoked by the timelock contract itself, thus requiring that this change go /// through the process and time delays as other governance actions. - function setAdmin(address newAdmin) external; + function setAdmin(address _newAdmin) external; } diff --git a/src/interfaces/EIP5164/ExecutorAware.sol b/src/libraries/EIP5164/ExecutorAware.sol similarity index 100% rename from src/interfaces/EIP5164/ExecutorAware.sol rename to src/libraries/EIP5164/ExecutorAware.sol diff --git a/src/libraries/Message.sol b/src/libraries/Message.sol index 726a36c..8131726 100644 --- a/src/libraries/Message.sol +++ b/src/libraries/Message.sol @@ -11,7 +11,7 @@ library MessageLibrary { /// @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)) - /// @param expiration is the unix time when the message expires, zero means never expire + /// @param expiration is the unix time when the message expires. struct Message { uint256 srcChainId; uint256 dstChainId; diff --git a/test/contracts-mock/ZeroAddressReceiverGAC.sol b/test/contracts-mock/ZeroAddressReceiverGAC.sol index e08882e..963e683 100644 --- a/test/contracts-mock/ZeroAddressReceiverGAC.sol +++ b/test/contracts-mock/ZeroAddressReceiverGAC.sol @@ -3,17 +3,13 @@ pragma solidity >=0.8.9; /// @dev A mock GAC with zero address receiver contract ZeroAddressReceiverGAC { - address immutable caller; + address public immutable authorisedCaller; constructor(address _caller) { - caller = _caller; + authorisedCaller = _caller; } - function getRemoteMultiBridgeMessageReceiver(uint256) external pure returns (address _mmaReceiver) { + function remoteMultiBridgeMessageReceiver(uint256) external pure returns (address _mmaReceiver) { return address(0); } - - 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 be2df83..87b86d6 100644 --- a/test/integration-tests/GracePeriodExpiry.t.sol +++ b/test/integration-tests/GracePeriodExpiry.t.sol @@ -47,7 +47,8 @@ contract GracePeriodExpiryTest is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/integration-tests/MultiMessageAggregation.t.sol b/test/integration-tests/MultiMessageAggregation.t.sol index fdd0d1e..b718ba6 100644 --- a/test/integration-tests/MultiMessageAggregation.t.sol +++ b/test/integration-tests/MultiMessageAggregation.t.sol @@ -47,7 +47,8 @@ contract MultiBridgeMessageAggregationTest is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/integration-tests/RemoteAdapterAdd.t.sol b/test/integration-tests/RemoteAdapterAdd.t.sol index 7315f95..8ae9d04 100644 --- a/test/integration-tests/RemoteAdapterAdd.t.sol +++ b/test/integration-tests/RemoteAdapterAdd.t.sol @@ -72,7 +72,8 @@ contract RemoteAdapterAdd is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/integration-tests/RemoteAdapterRemove.t.sol b/test/integration-tests/RemoteAdapterRemove.t.sol index 1ae0c7e..ee08c72 100644 --- a/test/integration-tests/RemoteAdapterRemove.t.sol +++ b/test/integration-tests/RemoteAdapterRemove.t.sol @@ -82,7 +82,8 @@ contract RemoteAdapterRemove is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/integration-tests/RemoteSetQuorum.t.sol b/test/integration-tests/RemoteSetQuorum.t.sol index 028252c..d002073 100644 --- a/test/integration-tests/RemoteSetQuorum.t.sol +++ b/test/integration-tests/RemoteSetQuorum.t.sol @@ -44,7 +44,8 @@ contract RemoteQuorumUpdate is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/integration-tests/RemoteTimelockUpdate.t.sol b/test/integration-tests/RemoteTimelockUpdate.t.sol index 3ede00f..18f5370 100644 --- a/test/integration-tests/RemoteTimelockUpdate.t.sol +++ b/test/integration-tests/RemoteTimelockUpdate.t.sol @@ -44,7 +44,8 @@ contract RemoteTimelockUpdate is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/integration-tests/TimelockCheck.t.sol b/test/integration-tests/TimelockCheck.t.sol index 8b481bc..062bc4c 100644 --- a/test/integration-tests/TimelockCheck.t.sol +++ b/test/integration-tests/TimelockCheck.t.sol @@ -49,7 +49,8 @@ contract TimelockCheckTest is Setup { 0, EXPIRATION_CONSTANT, refundAddress, - fees + fees, + new address[](0) ); Vm.Log[] memory logs = vm.getRecordedLogs(); diff --git a/test/unit-tests/GovernanceTimelock.t.sol b/test/unit-tests/GovernanceTimelock.t.sol index 774ab22..e0160c5 100644 --- a/test/unit-tests/GovernanceTimelock.t.sol +++ b/test/unit-tests/GovernanceTimelock.t.sol @@ -37,6 +37,16 @@ contract GovernanceTimelockTest is Setup { assertEq(timelock.txCounter(), 0); } + /// @dev constructor emits events for updating admin and delay period + function test_constructor_emits_events() public { + vm.expectEmit(true, true, true, true); + emit AdminUpdated(address(0), address(42)); + vm.expectEmit(true, true, true, true); + emit DelayUpdated(0, 3 days); + + new GovernanceTimelock(address(42), 3 days); + } + /// @dev cannot be called with zero address admin function test_constructor_zero_address_input() public { vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); diff --git a/test/unit-tests/MessageReceiverGAC.t.sol b/test/unit-tests/MessageReceiverGAC.t.sol index 6fe87cf..d045559 100644 --- a/test/unit-tests/MessageReceiverGAC.t.sol +++ b/test/unit-tests/MessageReceiverGAC.t.sol @@ -39,11 +39,11 @@ contract MessageReceiverGACTest is Setup { vm.startPrank(gacOwner); vm.expectEmit(true, true, true, true, address(receiverGAC)); - emit MultiBridgeMessageReceiverUpdated(address(receiverGAC.getMultiBridgeMessageReceiver()), address(42)); + emit MultiBridgeMessageReceiverUpdated(address(receiverGAC.multiBridgeMsgReceiver()), address(42)); receiverGAC.setMultiBridgeMessageReceiver(address(42)); - assertEq(receiverGAC.getMultiBridgeMessageReceiver(), address(42)); + assertEq(receiverGAC.multiBridgeMsgReceiver(), address(42)); } /// @dev only owner can set multi message receiver diff --git a/test/unit-tests/MessageSenderGAC.t.sol b/test/unit-tests/MessageSenderGAC.t.sol index 2757b65..6490a98 100644 --- a/test/unit-tests/MessageSenderGAC.t.sol +++ b/test/unit-tests/MessageSenderGAC.t.sol @@ -19,8 +19,8 @@ import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; contract MessageSenderGACTest is Setup { event DstGasLimitUpdated(uint256 oldLimit, uint256 newLimit); - event MultiBridgeMessageCallerUpdated(address indexed mmaCaller); - event MultiBridgeMessageSenderUpdated(address indexed mmaSender); + event MultiBridgeMessageCallerUpdated(address indexed oldAuthCaller, address indexed newAuthCaller); + event MultiBridgeMessageSenderUpdated(address indexed oldMMS, address indexed newMMS); event MultiBridgeMessageReceiverUpdated(uint256 indexed chainId, address indexed oldMMR, address indexed newMMR); address senderAddr; @@ -48,11 +48,11 @@ contract MessageSenderGACTest is Setup { vm.startPrank(owner); vm.expectEmit(true, true, true, true, address(senderGAC)); - emit MultiBridgeMessageSenderUpdated(address(42)); + emit MultiBridgeMessageSenderUpdated(senderGAC.multiBridgeMessageSender(), address(42)); senderGAC.setMultiBridgeMessageSender(address(42)); - assertEq(senderGAC.getMultiBridgeMessageSender(), address(42)); + assertEq(senderGAC.multiBridgeMessageSender(), address(42)); } /// @dev only owner can set multi message sender @@ -76,11 +76,11 @@ contract MessageSenderGACTest is Setup { vm.startPrank(owner); vm.expectEmit(true, true, true, true, address(senderGAC)); - emit MultiBridgeMessageCallerUpdated(address(42)); + emit MultiBridgeMessageCallerUpdated(senderGAC.authorisedCaller(), address(42)); senderGAC.setAuthorisedCaller(address(42)); - assertEq(senderGAC.getAuthorisedCaller(), address(42)); + assertEq(senderGAC.authorisedCaller(), address(42)); } /// @dev only owner can set multi message caller @@ -105,12 +105,12 @@ contract MessageSenderGACTest is Setup { vm.expectEmit(true, true, true, true, address(senderGAC)); emit MultiBridgeMessageReceiverUpdated( - DST_CHAIN_ID, senderGAC.getRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID), address(42) + DST_CHAIN_ID, senderGAC.remoteMultiBridgeMessageReceiver(DST_CHAIN_ID), address(42) ); senderGAC.setRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID, address(42)); - assertEq(senderGAC.getRemoteMultiBridgeMessageReceiver(DST_CHAIN_ID), address(42)); + assertEq(senderGAC.remoteMultiBridgeMessageReceiver(DST_CHAIN_ID), address(42)); } /// @dev only owner can set multi message receiver @@ -141,13 +141,13 @@ contract MessageSenderGACTest is Setup { function test_set_global_msg_delivery_gas_limit() public { vm.startPrank(owner); - uint256 oldLimit = senderGAC.getGlobalMsgDeliveryGasLimit(); + uint256 oldLimit = senderGAC.msgDeliveryGasLimit(); vm.expectEmit(true, true, true, true, address(senderGAC)); emit DstGasLimitUpdated(oldLimit, 420000); senderGAC.setGlobalMsgDeliveryGasLimit(420000); - assertEq(senderGAC.getGlobalMsgDeliveryGasLimit(), 420000); + assertEq(senderGAC.msgDeliveryGasLimit(), 420000); } /// @dev only owner can set global message delivery gas limit diff --git a/test/unit-tests/MultiBridgeMessageSender.t.sol b/test/unit-tests/MultiBridgeMessageSender.t.sol index bf890b5..b76da8b 100644 --- a/test/unit-tests/MultiBridgeMessageSender.t.sol +++ b/test/unit-tests/MultiBridgeMessageSender.t.sol @@ -67,7 +67,7 @@ contract MultiBridgeMessageSenderTest is Setup { // Wormhole requires exact fees to be passed in (uint256 wormholeFee,) = IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice( - _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.getGlobalMsgDeliveryGasLimit() + _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.msgDeliveryGasLimit() ); (address[] memory senderAdapters, uint256[] memory fees) = _sortTwoAdaptersWithFees(axelarAdapterAddr, wormholeAdapterAddr, 0.01 ether, wormholeFee); @@ -94,7 +94,7 @@ contract MultiBridgeMessageSenderTest is Setup { ); sender.remoteCall{value: fees[0] + fees[1]}( - DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, refundAddress, fees + DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, refundAddress, fees, new address[](0) ); assertEq(sender.nonce(), 1); @@ -111,12 +111,12 @@ contract MultiBridgeMessageSenderTest is Setup { uint256 balanceBefore = refundAddress.balance; (uint256 wormholeFee,) = IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice( - _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.getGlobalMsgDeliveryGasLimit() + _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.msgDeliveryGasLimit() ); (, uint256[] memory fees) = _sortTwoAdaptersWithFees(axelarAdapterAddr, wormholeAdapterAddr, 0.01 ether, wormholeFee); sender.remoteCall{value: nativeValue}( - DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, refundAddress, fees + DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, refundAddress, fees, new address[](0) ); uint256 balanceAfter = refundAddress.balance; @@ -151,7 +151,7 @@ contract MultiBridgeMessageSenderTest is Setup { uint256[] memory fees = new uint256[](1); (uint256 wormholeFee,) = IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice( - _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.getGlobalMsgDeliveryGasLimit() + _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.msgDeliveryGasLimit() ); fees[0] = wormholeFee; @@ -198,11 +198,14 @@ contract MultiBridgeMessageSenderTest is Setup { fees[1] = 0.01 ether; vm.expectRevert(Error.INVALID_PRIVILEGED_CALLER.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev message expiration has to be within allowed range function test_remote_call_invalid_expiration() public { + address[] memory excludedAdapters = new address[](0); uint256 invalidExpMin = sender.MIN_MESSAGE_EXPIRATION() - 1 days; uint256 invalidExpMax = sender.MAX_MESSAGE_EXPIRATION() + 1 days; @@ -213,13 +216,16 @@ contract MultiBridgeMessageSenderTest is Setup { // test expiration validation in remoteCall() which does not accept excluded adapters vm.startPrank(caller); vm.expectRevert(Error.INVALID_EXPIRATION_DURATION.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, invalidExpMin, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, invalidExpMin, refundAddress, fees, excludedAdapters + ); vm.expectRevert(Error.INVALID_EXPIRATION_DURATION.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, invalidExpMax, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, invalidExpMax, refundAddress, fees, excludedAdapters + ); // test expiration validation in remoteCall() which accepts excluded adapters - address[] memory excludedAdapters = new address[](0); vm.startPrank(caller); vm.expectRevert(Error.INVALID_EXPIRATION_DURATION.selector); sender.remoteCall( @@ -236,12 +242,15 @@ contract MultiBridgeMessageSenderTest is Setup { function test_remote_call_invalid_refundAddress() public { // test refund address validation in remoteCall() which does not accept excluded adapters vm.startPrank(caller); + address[] memory excludedAdapters = new address[](0); uint256[] memory fees = new uint256[](2); fees[0] = 0.01 ether; fees[1] = 0.01 ether; vm.expectRevert(Error.INVALID_REFUND_ADDRESS.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, address(0), fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, address(0), fees, excludedAdapters + ); vm.expectRevert(Error.INVALID_REFUND_ADDRESS.selector); sender.remoteCall( @@ -251,11 +260,11 @@ contract MultiBridgeMessageSenderTest is Setup { 0, EXPIRATION_CONSTANT, contractAddress[SRC_CHAIN_ID]["MMA_SENDER"], - fees + fees, + excludedAdapters ); // test refund address validation in remoteCall() which accepts excluded adapters - address[] memory excludedAdapters = new address[](0); vm.startPrank(caller); vm.expectRevert(Error.INVALID_REFUND_ADDRESS.selector); sender.remoteCall( @@ -284,7 +293,9 @@ contract MultiBridgeMessageSenderTest is Setup { fees[1] = 0.01 ether; vm.expectRevert(Error.INVALID_DST_CHAIN.selector); - sender.remoteCall(block.chainid, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall( + block.chainid, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev cannot call with dst chain ID of 0 @@ -296,7 +307,7 @@ contract MultiBridgeMessageSenderTest is Setup { fees[1] = 0.01 ether; vm.expectRevert(Error.ZERO_CHAIN_ID.selector); - sender.remoteCall(0, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall(0, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0)); } /// @dev cannot call with target address of 0 @@ -308,7 +319,9 @@ contract MultiBridgeMessageSenderTest is Setup { fees[1] = 0.01 ether; vm.expectRevert(Error.INVALID_TARGET.selector); - sender.remoteCall(DST_CHAIN_ID, address(0), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(0), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev cannot call with receiver address of 0 @@ -322,7 +335,9 @@ contract MultiBridgeMessageSenderTest is Setup { 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, fees); + dummySender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev cannot call with no sender adapter @@ -341,7 +356,9 @@ contract MultiBridgeMessageSenderTest is Setup { vm.startPrank(caller); vm.expectRevert(Error.NO_SENDER_ADAPTER_FOUND.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev should proceed with the call despite one failing adapter, emitting an error message @@ -360,7 +377,7 @@ contract MultiBridgeMessageSenderTest is Setup { uint256[] memory fees = new uint256[](3); bool[] memory adapterSuccess = new bool[](3); (uint256 wormholeFee,) = IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice( - _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.getGlobalMsgDeliveryGasLimit() + _wormholeChainId(DST_CHAIN_ID), 0, senderGAC.msgDeliveryGasLimit() ); senderAdapters[0] = axelarAdapterAddr; senderAdapters[1] = wormholeAdapterAddr; @@ -394,7 +411,9 @@ contract MultiBridgeMessageSenderTest is Setup { msgId, 1, DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, senderAdapters, adapterSuccess ); - sender.remoteCall{value: 0.1 ether}(DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, refundAddress, fees); + sender.remoteCall{value: 0.1 ether}( + DST_CHAIN_ID, address(42), bytes("42"), 0, expiration, refundAddress, fees, new address[](0) + ); } /// @dev cannot call with invalid fee array @@ -405,7 +424,9 @@ contract MultiBridgeMessageSenderTest is Setup { fees[0] = 0.01 ether; vm.expectRevert(Error.INVALID_SENDER_ADAPTER_FEES.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev cannot call with msg.value less than total fees @@ -417,7 +438,9 @@ contract MultiBridgeMessageSenderTest is Setup { fees[1] = 0.01 ether; vm.expectRevert(Error.INVALID_MSG_VALUE.selector); - sender.remoteCall(DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees); + sender.remoteCall( + DST_CHAIN_ID, address(42), bytes("42"), 0, EXPIRATION_CONSTANT, refundAddress, fees, new address[](0) + ); } /// @dev adds two sender adapters diff --git a/test/unit-tests/adapters/BaseSenderAdapter.t.sol b/test/unit-tests/adapters/BaseSenderAdapter.t.sol index 132910b..803887b 100644 --- a/test/unit-tests/adapters/BaseSenderAdapter.t.sol +++ b/test/unit-tests/adapters/BaseSenderAdapter.t.sol @@ -33,14 +33,14 @@ contract AxelarSenderAdapterTest is Setup { receiverAdapters[1] = address(43); vm.expectEmit(true, true, true, true, address(adapter)); - emit ReceiverAdapterUpdated(BSC_CHAIN_ID, adapter.getReceiverAdapter(BSC_CHAIN_ID), address(42)); + emit ReceiverAdapterUpdated(BSC_CHAIN_ID, adapter.receiverAdapters(BSC_CHAIN_ID), address(42)); vm.expectEmit(true, true, true, true, address(adapter)); - emit ReceiverAdapterUpdated(POLYGON_CHAIN_ID, adapter.getReceiverAdapter(POLYGON_CHAIN_ID), address(43)); + emit ReceiverAdapterUpdated(POLYGON_CHAIN_ID, adapter.receiverAdapters(POLYGON_CHAIN_ID), address(43)); adapter.updateReceiverAdapter(DST_CHAINS, receiverAdapters); - assertEq(adapter.getReceiverAdapter(BSC_CHAIN_ID), address(42)); - assertEq(adapter.getReceiverAdapter(POLYGON_CHAIN_ID), address(43)); + assertEq(adapter.receiverAdapters(BSC_CHAIN_ID), address(42)); + assertEq(adapter.receiverAdapters(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 d9dd95c..96e6d35 100644 --- a/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarReceiverAdapter.t.sol @@ -38,7 +38,7 @@ contract AxelarReceiverAdapterTest is Setup { // checks existing setup assertEq(address(adapter.gateway()), POLYGON_GATEWAY); assertEq(address(adapter.receiverGAC()), contractAddress[DST_CHAIN_ID]["GAC"]); - assertEq(adapter.senderChain(), "ethereum"); + assertEq(adapter.senderChainId(), "ethereum"); } /// @dev constructor with invalid parameters should fail diff --git a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol index 07bbb7f..7e817ac 100644 --- a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol @@ -11,7 +11,7 @@ import {AxelarSenderAdapter} from "src/adapters/axelar/AxelarSenderAdapter.sol"; contract AxelarSenderAdapterTest is Setup { event MessageDispatched( - bytes32 indexed messageId, address indexed from, uint256 indexed toChainId, address to, bytes data + bytes32 indexed messageId, address indexed from, uint256 indexed receiverChainId, address to, bytes data ); address senderAddr; diff --git a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol index f9175e5..6ac06b8 100644 --- a/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeReceiverAdapter.t.sol @@ -70,7 +70,7 @@ contract WormholeReceiverAdapterTest is Setup { adapter.updateSenderAdapter(address(42)); assertEq(adapter.senderAdapter(), address(42)); - assertEq(adapter.senderChain(), uint16(2)); + assertEq(adapter.senderChainId(), uint16(2)); } /// @dev only global owner can update sender adapter diff --git a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol index bfb6c98..58ad9b5 100644 --- a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol @@ -12,7 +12,7 @@ import {IWormholeRelayer} from "lib/wormhole-solidity-sdk/src/interfaces/IWormho contract WormholeSenderAdapterTest is Setup { event MessageDispatched( - bytes32 indexed messageId, address indexed from, uint256 indexed toChainId, address to, bytes data + bytes32 indexed messageId, address indexed from, uint256 indexed receiverChainId, address to, bytes data ); address senderAddr; @@ -41,7 +41,7 @@ contract WormholeSenderAdapterTest is Setup { bytes32 msgId = keccak256(abi.encodePacked(SRC_CHAIN_ID, DST_CHAIN_ID, uint256(0), address(adapter), address(42))); (uint256 fee,) = IWormholeRelayer(POLYGON_RELAYER).quoteEVMDeliveryPrice( - _wormholeChainId(DST_CHAIN_ID), 0, adapter.senderGAC().getGlobalMsgDeliveryGasLimit() + _wormholeChainId(DST_CHAIN_ID), 0, adapter.senderGAC().msgDeliveryGasLimit() ); vm.expectEmit(true, true, true, true, address(adapter)); From e614b4c1766adf69a243cc50afa3f2b0f211dd7b Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 5 Oct 2023 14:17:15 +1100 Subject: [PATCH 2/2] Fix missing validations (#98) * Add zero parameter value checks for MMR constructor * Add missing validations for sender adapter constructors --- src/MultiBridgeMessageReceiver.sol | 10 +++++++++- src/adapters/axelar/AxelarSenderAdapter.sol | 4 ++++ .../wormhole/WormholeSenderAdapter.sol | 3 +++ .../MultiBridgeMessageReceiver.t.sol | 12 ++++++++++++ .../adapters/axelar/AxelarSenderAdapter.t.sol | 18 ++++++++++++++++++ .../wormhole/WormholeSenderAdapter.t.sol | 12 ++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index e9e0843..960b5ce 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -74,8 +74,16 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar /// @notice sets the initial parameters constructor(uint256 _srcChainId, address _gac) { - srcChainId = _srcChainId; + if (_gac == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + + if (_srcChainId == 0) { + revert Error.INVALID_SENDER_CHAIN_ID(); + } + gac = IGAC(_gac); + srcChainId = _srcChainId; } /*///////////////////////////////////////////////////////////////// diff --git a/src/adapters/axelar/AxelarSenderAdapter.sol b/src/adapters/axelar/AxelarSenderAdapter.sol index b383abb..91889c6 100644 --- a/src/adapters/axelar/AxelarSenderAdapter.sol +++ b/src/adapters/axelar/AxelarSenderAdapter.sol @@ -26,6 +26,10 @@ contract AxelarSenderAdapter is BaseSenderAdapter { CONSTRUCTOR ////////////////////////////////////////////////////////////////*/ constructor(address _gasService, address _gateway, address _gac) BaseSenderAdapter(_gac) { + if (_gasService == address(0) || _gateway == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } + gasService = IAxelarGasService(_gasService); gateway = IAxelarGateway(_gateway); } diff --git a/src/adapters/wormhole/WormholeSenderAdapter.sol b/src/adapters/wormhole/WormholeSenderAdapter.sol index 38504cf..f1277d1 100644 --- a/src/adapters/wormhole/WormholeSenderAdapter.sol +++ b/src/adapters/wormhole/WormholeSenderAdapter.sol @@ -24,6 +24,9 @@ contract WormholeSenderAdapter is BaseSenderAdapter { CONSTRUCTOR ////////////////////////////////////////////////////////////////*/ constructor(address _wormholeRelayer, address _gac) BaseSenderAdapter(_gac) { + if (_wormholeRelayer == address(0)) { + revert Error.ZERO_ADDRESS_INPUT(); + } relayer = IWormholeRelayer(_wormholeRelayer); } diff --git a/test/unit-tests/MultiBridgeMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol index ea2db45..f1b7e32 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -37,6 +37,18 @@ contract MultiBridgeMessageReceiverTest is Setup { timelockAddr = contractAddress[DST_CHAIN_ID]["TIMELOCK"]; } + /// @dev cannot be called with zero source chain id + function test_constructor_zero_chain_id_input() public { + vm.expectRevert(Error.INVALID_SENDER_CHAIN_ID.selector); + new MultiBridgeMessageReceiver(0, address(42)); + } + + /// @dev cannot be called with zero address GAC + function test_constructor_zero_gac_address_input() public { + vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); + new MultiBridgeMessageReceiver(1, address(0)); + } + /// @dev receives message from one adapter function test_receive_message() public { vm.startPrank(wormholeAdapterAddr); diff --git a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol index 7e817ac..3f83b87 100644 --- a/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol +++ b/test/unit-tests/adapters/axelar/AxelarSenderAdapter.t.sol @@ -34,6 +34,24 @@ contract AxelarSenderAdapterTest is Setup { assertEq(address(adapter.senderGAC()), contractAddress[SRC_CHAIN_ID]["GAC"]); } + /// @dev constructor cannot be called with zero address gas service + function test_constructor_zero_address_relayer() public { + vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); + new AxelarSenderAdapter(address(0), address(42), address(42)); + } + + /// @dev constructor cannot be called with zero address gateway + function test_constructor_zero_address_gateway() public { + vm.expectRevert(Error.ZERO_ADDRESS_INPUT.selector); + new AxelarSenderAdapter(address(42), address(0), 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 AxelarSenderAdapter(address(42), address(42), address(0)); + } + /// @dev dispatches message function test_dispatch_message() public { vm.startPrank(senderAddr); diff --git a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol index 58ad9b5..672c52d 100644 --- a/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol +++ b/test/unit-tests/adapters/wormhole/WormholeSenderAdapter.t.sol @@ -33,6 +33,18 @@ contract WormholeSenderAdapterTest is Setup { assertEq(address(adapter.senderGAC()), contractAddress[SRC_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 WormholeSenderAdapter(address(0), 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 WormholeSenderAdapter(address(42), address(0)); + } + /// @dev dispatches message function test_dispatch_message() public { vm.startPrank(senderAddr);