Skip to content

Commit

Permalink
Rename and refactor to address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominator008 committed Oct 10, 2023
1 parent d22798f commit bbcc51b
Show file tree
Hide file tree
Showing 12 changed files with 533 additions and 297 deletions.
129 changes: 86 additions & 43 deletions src/MultiBridgeMessageReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import "./libraries/Message.sol";
/// governance timelock contract.
/// @dev The contract only accepts messages from trusted bridge receiver adapters, each of which implements the
/// IMessageReceiverAdapter interface.
contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAware {
contract MultiBridgeMessageReceiver is
IMultiBridgeMessageReceiver,
ExecutorAware
{
/// @notice the id of the source chain that this contract can receive messages from
uint256 public immutable srcChainId;
/// @notice the global access control contract
Expand All @@ -37,13 +40,14 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
address public governanceTimelock;

/// @notice maintains which bridge adapters have delivered each message
mapping(bytes32 msgId => mapping(address receiverAdapter => bool delivered)) public msgDeliveries;
mapping(bytes32 msgId => mapping(address receiverAdapter => bool delivered))
public msgDeliveries;

/// @notice count of bridge adapters that have delivered each message
mapping(bytes32 msgId => uint256 deliveryCount) public msgDeliveryCount;

/// @notice the hash of the data required for executing a message
mapping(bytes32 msgId => bytes32 execDataHash) public msgExecDataHash;
/// @notice the hash of the params required for executing a message
mapping(bytes32 msgId => bytes32 execParamsHash) public msgExecParamsHash;

/// @notice whether a message has been sent to the governance timelock for execution
mapping(bytes32 msgId => bool scheduled) public isExecutionScheduled;
Expand Down Expand Up @@ -73,7 +77,12 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
////////////////////////////////////////////////////////////////*/

/// @notice sets the initial parameters
constructor(uint256 _srcChainId, address _gac, address[] memory _receiverAdapters, uint64 _quorum) {
constructor(
uint256 _srcChainId,
address _gac,
address[] memory _receiverAdapters,
uint64 _quorum
) {
if (_srcChainId == 0) {
revert Error.INVALID_SENDER_CHAIN_ID();
}
Expand All @@ -84,7 +93,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
srcChainId = _srcChainId;
gac = IGAC(_gac);

for (uint256 i; i < _receiverAdapters.length;) {
for (uint256 i; i < _receiverAdapters.length; ) {
_updateReceiverAdapter(_receiverAdapters[i], true);
unchecked {
++i;
Expand All @@ -99,7 +108,9 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar

/// @notice receive messages from allowed bridge receiver adapters
/// @param _message is the crosschain message sent by the mma sender
function receiveMessage(MessageLibrary.Message calldata _message) external override onlyReceiverAdapter {
function receiveMessage(
MessageLibrary.Message calldata _message
) external override onlyReceiverAdapter {
if (_message.dstChainId != block.chainid) {
revert Error.INVALID_DST_CHAIN();
}
Expand Down Expand Up @@ -127,40 +138,42 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar

msgDeliveries[msgId][msg.sender] = true;

/// increment quorum
/// increment vote count for a message
++msgDeliveryCount[msgId];

/// stores the hash of the execution data required
bytes32 prevStoredHash = msgExecDataHash[msgId];
/// stores the hash of the execution params required
bytes32 prevStoredHash = msgExecParamsHash[msgId];

/// stores the message if the amb is the first one delivering the message
if (prevStoredHash == bytes32(0)) {
msgExecDataHash[msgId] = keccak256(
abi.encodePacked(
_message.target, _message.callData, _message.nativeValue, _message.nonce, _message.expiration
)
);
msgExecParamsHash[msgId] = MessageLibrary
.computeExecutionParamsHash(_message);
}

string memory bridgeName = IMessageReceiverAdapter(msg.sender).name();
emit BridgeMessageReceived(msgId, bridgeName, _message.nonce, msg.sender);
emit BridgeMessageReceived(
msgId,
bridgeName,
_message.nonce,
msg.sender
);
}

/// @inheritdoc IMultiBridgeMessageReceiver
function scheduleMessageExecution(bytes32 _msgId, ExecutionData calldata _execData) external override {
bytes32 execDataHash = msgExecDataHash[_msgId];
function scheduleMessageExecution(
bytes32 _msgId,
MessageLibrary.MessageExecutionParams calldata _execParams
) external override {
bytes32 execParamsHash = msgExecParamsHash[_msgId];
if (
keccak256(
abi.encodePacked(
_execData.target, _execData.callData, _execData.value, _execData.nonce, _execData.expiration
)
) != execDataHash
MessageLibrary.computeExecutionParamsHash(_execParams) !=
execParamsHash
) {
revert Error.EXEC_DATA_HASH_MISMATCH();
revert Error.EXEC_PARAMS_HASH_MISMATCH();
}

/// @dev validates if msg execution is not beyond expiration
if (block.timestamp > _execData.expiration) {
if (block.timestamp > _execParams.expiration) {
revert Error.MSG_EXECUTION_PASSED_DEADLINE();
}

Expand All @@ -178,30 +191,42 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar

/// @dev queues the action on timelock for execution
IGovernanceTimelock(governanceTimelock).scheduleTransaction(
_execData.target, _execData.value, _execData.callData
_execParams.target,
_execParams.value,
_execParams.callData
);

emit MessageExecutionScheduled(_msgId, _execData.target, _execData.value, _execData.nonce, _execData.callData);
emit MessageExecutionScheduled(
_msgId,
_execParams.target,
_execParams.value,
_execParams.nonce,
_execParams.callData
);
}

/// @notice update the governance timelock contract.
/// @dev called by admin to update the timelock contract
function updateGovernanceTimelock(address _governanceTimelock) external onlyGlobalOwner {
function updateGovernanceTimelock(
address _governanceTimelock
) external onlyGlobalOwner {
if (_governanceTimelock == address(0)) {
revert Error.ZERO_GOVERNANCE_TIMELOCK();
}
address oldGovernanceTimelock = governanceTimelock;
governanceTimelock = _governanceTimelock;
emit GovernanceTimelockUpdated(oldGovernanceTimelock, _governanceTimelock);
emit GovernanceTimelockUpdated(
oldGovernanceTimelock,
_governanceTimelock
);
}

/// @notice Update bridge receiver adapters.
/// @dev called by admin to update receiver bridge adapters on all other chains
function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations)
external
override
onlyGlobalOwner
{
function updateReceiverAdapters(
address[] calldata _receiverAdapters,
bool[] calldata _operations
) external override onlyGlobalOwner {
_updateReceiverAdapters(_receiverAdapters, _operations);
_validateQuorum(quorum);
}
Expand Down Expand Up @@ -230,16 +255,20 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
/// @return isExecutionScheduled is true if the message has been sent to the timelock for execution
/// @return msgCurrentVotes is the number of bridges that have delivered the message
/// @return successfulBridge is the list of bridges that have delivered the message
function getMessageInfo(bytes32 _msgId) public view returns (bool, uint256, string[] memory) {
function getMessageInfo(
bytes32 _msgId
) public view returns (bool, uint256, string[] memory) {
uint256 msgCurrentVotes = msgDeliveryCount[_msgId];
string[] memory successfulBridge = new string[](msgCurrentVotes);

if (msgCurrentVotes != 0) {
uint256 currIndex;
address[] memory executors = getTrustedExecutors();
for (uint256 i; i < executors.length;) {
for (uint256 i; i < executors.length; ) {
if (msgDeliveries[_msgId][executors[i]]) {
successfulBridge[currIndex] = IMessageReceiverAdapter(executors[i]).name();
successfulBridge[currIndex] = IMessageReceiverAdapter(
executors[i]
).name();
++currIndex;
}

Expand All @@ -249,7 +278,11 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
}
}

return (isExecutionScheduled[_msgId], msgCurrentVotes, successfulBridge);
return (
isExecutionScheduled[_msgId],
msgCurrentVotes,
successfulBridge
);
}

/*/////////////////////////////////////////////////////////////////
Expand All @@ -265,7 +298,10 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
emit QuorumUpdated(oldValue, _quorum);
}

function _updateReceiverAdapters(address[] memory _receiverAdapters, bool[] memory _operations) private {
function _updateReceiverAdapters(
address[] memory _receiverAdapters,
bool[] memory _operations
) private {
uint256 len = _receiverAdapters.length;

if (len == 0) {
Expand All @@ -276,7 +312,7 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
revert Error.ARRAY_LENGTH_MISMATCHED();
}

for (uint256 i; i < len;) {
for (uint256 i; i < len; ) {
_updateReceiverAdapter(_receiverAdapters[i], _operations[i]);

unchecked {
Expand All @@ -285,15 +321,22 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar
}
}

function _updateReceiverAdapter(address _receiverAdapter, bool _add) private {
function _updateReceiverAdapter(
address _receiverAdapter,
bool _add
) private {
if (_receiverAdapter == address(0)) {
revert Error.ZERO_ADDRESS_INPUT();
}
bool success = _add ? _addTrustedExecutor(_receiverAdapter) : _removeTrustedExecutor(_receiverAdapter);
bool success = _add
? _addTrustedExecutor(_receiverAdapter)
: _removeTrustedExecutor(_receiverAdapter);

if (!success) {
// only fails because we are either attempting to add an existing adapter, or remove a non-existing adapter
revert Error.UPDATE_RECEIVER_ADAPTER_FAILED(_add ? "adapter already added" : "adapter not found");
revert Error.UPDATE_RECEIVER_ADAPTER_FAILED(
_add ? "adapter already added" : "adapter not found"
);
}

emit BridgeReceiverAdapterUpdated(_receiverAdapter, _add);
Expand Down
41 changes: 22 additions & 19 deletions src/interfaces/IMultiBridgeMessageReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,16 @@ import "../libraries/Message.sol";

/// @notice interface for the multi-bridge message receiver
interface IMultiBridgeMessageReceiver {
/// @notice encapsulates data that is relevant to a message's intended transaction execution.
struct ExecutionData {
// target contract address on the destination chain
address target;
// data to pass to target by low-level call
bytes callData;
// value to pass to target by low-level call
uint256 value;
// nonce of the message
uint256 nonce;
// expiration timestamp for the message beyond which it cannot be executed
uint256 expiration;
}

/// @notice emitted when a message has been received from a single bridge.
/// @param msgId is the unique identifier of the message
/// @param bridgeName is the name of the bridge from which the message was received
/// @param nonce is the nonce of the message
/// @param receiverAdapter is the address of the receiver adapter that received the message
event BridgeMessageReceived(
bytes32 indexed msgId, string indexed bridgeName, uint256 nonce, address receiverAdapter
bytes32 indexed msgId,
string indexed bridgeName,
uint256 nonce,
address receiverAdapter
);

/// @notice emitted when a message has been queued for execution in the destination timelock contract.
Expand All @@ -35,13 +24,20 @@ interface IMultiBridgeMessageReceiver {
/// @param nonce is the nonce of the message
/// @param callData is the data that will be passed to the target address through low-level call
event MessageExecutionScheduled(
bytes32 indexed msgId, address indexed target, uint256 nativeValue, uint256 nonce, bytes callData
bytes32 indexed msgId,
address indexed target,
uint256 nativeValue,
uint256 nonce,
bytes callData
);

/// @notice emitted when receiver adapter of a specific bridge is updated.
/// @param receiverAdapter is the new receiver adapter address
/// @param add is true if the receiver adapter was added, false if removed
event BridgeReceiverAdapterUpdated(address indexed receiverAdapter, bool add);
event BridgeReceiverAdapterUpdated(
address indexed receiverAdapter,
bool add
);

/// @notice emitted when the quorum for message validity is updated.
/// @param oldQuorum is the old quorum value
Expand All @@ -60,12 +56,19 @@ interface IMultiBridgeMessageReceiver {

/// @notice Sends a message, that has achieved quorum and has not yet expired, to the governance timelock for eventual execution.
/// @param _msgId is the unique identifier of the message
function scheduleMessageExecution(bytes32 _msgId, ExecutionData calldata _execData) external;
/// @param _execParams are the params for message execution
function scheduleMessageExecution(
bytes32 _msgId,
MessageLibrary.MessageExecutionParams calldata _execParams
) external;

/// @notice adds or removes bridge receiver adapters.
/// @param _receiverAdapters the list of receiver adapters to add or remove
/// @param _operations the list of operations to perform for corresponding receiver adapters, true for add, false for remove
function updateReceiverAdapters(address[] calldata _receiverAdapters, bool[] calldata _operations) external;
function updateReceiverAdapters(
address[] calldata _receiverAdapters,
bool[] calldata _operations
) external;

/// @notice updates the quorum for message validity, which is the number of bridges that must deliver the message for it to be considered valid.
/// @param _quorum is the new quorum value
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/Error.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ library Error {
/// @dev is thrown if refund address is zero (or) invalid
error INVALID_REFUND_ADDRESS();

/// @dev is thrown if execution data does not match the stored hash
error EXEC_DATA_HASH_MISMATCH();
/// @dev is thrown if execution params do not match the stored hash
error EXEC_PARAMS_HASH_MISMATCH();

/*/////////////////////////////////////////////////////////////////
ADAPTER ERRORS
Expand Down
Loading

0 comments on commit bbcc51b

Please sign in to comment.