Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: revert if all message bridges fail #97

Merged
merged 8 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions src/MultiBridgeMessageSender.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ contract MultiBridgeMessageSender {
uint256 expiration;
address refundAddress;
uint256[] fees;
uint256 successThreshold;
address[] excludedAdapters;
}

Expand Down Expand Up @@ -145,6 +146,7 @@ contract MultiBridgeMessageSender {
/// @param _refundAddress refers to the refund address for any extra native tokens paid
/// @param _fees refers to the fees to pay to each sender adapter that is not in the exclusion list specified by _excludedAdapters.
/// The fees are in the same order as the sender adapters in the senderAdapters list, after the exclusion list is applied.
/// @param _successThreshold specifies the minimum number of bridges that must successfully dispatch the message for this call to succeed.
/// @param _excludedAdapters are the sender adapters to be excluded from relaying the message, in ascending order by address
function remoteCall(
uint256 _dstChainId,
Expand All @@ -154,11 +156,20 @@ contract MultiBridgeMessageSender {
uint256 _expiration,
address _refundAddress,
uint256[] calldata _fees,
address[] calldata _excludedAdapters
uint256 _successThreshold,
address[] memory _excludedAdapters
) external payable onlyCaller validateExpiration(_expiration) {
_remoteCall(
RemoteCallArgs(
_dstChainId, _target, _callData, _nativeValue, _expiration, _refundAddress, _fees, _excludedAdapters
_dstChainId,
_target,
_callData,
_nativeValue,
_expiration,
_refundAddress,
_fees,
_successThreshold,
_excludedAdapters
)
);
}
Expand Down Expand Up @@ -237,7 +248,12 @@ contract MultiBridgeMessageSender {

function _remoteCall(RemoteCallArgs memory _args) private {
(address mmaReceiver, address[] memory adapters) = _checkAndProcessArgs(
_args.dstChainId, _args.target, _args.refundAddress, _args.fees, _args.excludedAdapters
_args.dstChainId,
_args.target,
_args.refundAddress,
_args.successThreshold,
_args.fees,
_args.excludedAdapters
);

/// @dev increments nonce
Expand All @@ -253,7 +269,12 @@ contract MultiBridgeMessageSender {
block.timestamp + _args.expiration
);
bytes32 msgId = MessageLibrary.computeMsgId(message);
bool[] memory adapterSuccess = _dispatchMessages(adapters, mmaReceiver, _args.dstChainId, message, _args.fees);
(bool[] memory adapterSuccess, uint256 successCount) =
_dispatchMessages(adapters, mmaReceiver, _args.dstChainId, message, _args.fees);

if (successCount < _args.successThreshold) {
ermyas marked this conversation as resolved.
Show resolved Hide resolved
revert Error.MULTI_MESSAGE_SEND_FAILED();
}

emit MultiBridgeMessageSent(
msgId,
Expand All @@ -277,6 +298,7 @@ contract MultiBridgeMessageSender {
uint256 _dstChainId,
address _target,
address _refundAddress,
uint256 _successThreshold,
uint256[] memory _fees,
address[] memory _excludedAdapters
) private view returns (address mmaReceiver, address[] memory adapters) {
Expand Down Expand Up @@ -307,6 +329,11 @@ contract MultiBridgeMessageSender {
if (adapters.length == 0) {
revert Error.NO_SENDER_ADAPTER_FOUND();
}

if (_successThreshold > adapters.length) {
revert Error.MULTI_MESSAGE_SEND_FAILED();
}

if (adapters.length != _fees.length) {
revert Error.INVALID_SENDER_ADAPTER_FEES();
}
Expand All @@ -328,15 +355,18 @@ contract MultiBridgeMessageSender {
uint256 _dstChainId,
MessageLibrary.Message memory _message,
uint256[] memory _fees
) private returns (bool[] memory) {
) private returns (bool[] memory, uint256) {
uint256 len = _adapters.length;
bool[] memory successes = new bool[](len);
uint256 successCount;

for (uint256 i; i < len;) {
/// @dev if one bridge is paused, the flow shouldn't be broken
try IMessageSenderAdapter(_adapters[i]).dispatchMessage{value: _fees[i]}(
_dstChainId, _mmaReceiver, abi.encode(_message)
) {
successes[i] = true;
++successCount;
} catch {
successes[i] = false;
emit MessageSendFailed(_adapters[i], _message);
Expand All @@ -346,7 +376,7 @@ contract MultiBridgeMessageSender {
++i;
}
}
return successes;
return (successes, successCount);
}

function _filterAdapters(address[] memory _existings, address[] memory _removals)
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/Error.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ library Error {
/// @dev is thrown if contract call is invalid (for axelar)
error NOT_APPROVED_BY_GATEWAY();

/// @dev is thrown if a message could not be sent through a sufficient number of bridges
error MULTI_MESSAGE_SEND_FAILED();

/*/////////////////////////////////////////////////////////////////
TIMELOCK ERRORS
////////////////////////////////////////////////////////////////*/
Expand Down
1 change: 1 addition & 0 deletions test/Setup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ abstract contract Setup is Test {
address constant owner = address(420);
address constant refundAddress = address(420420);
ermyas marked this conversation as resolved.
Show resolved Hide resolved
uint256 constant EXPIRATION_CONSTANT = 5 days;
uint256 constant DEFAULT_SUCCESS_THRESHOLD = 2;

/// @dev constants for axelar
address constant ETH_GATEWAY = 0x4F4495243837681061C4743b74B3eEdf548D56A5;
Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/GracePeriodExpiry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ contract GracePeriodExpiryTest is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/MultiMessageAggregation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ contract MultiBridgeMessageAggregationTest is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/RemoteAdapterAdd.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ contract RemoteAdapterAdd is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/RemoteAdapterRemove.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ contract RemoteAdapterRemove is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/RemoteSetQuorum.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ contract RemoteQuorumUpdate is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/RemoteTimelockUpdate.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ contract RemoteTimelockUpdate is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
1 change: 1 addition & 0 deletions test/integration-tests/TimelockCheck.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ contract TimelockCheckTest is Setup {
EXPIRATION_CONSTANT,
refundAddress,
fees,
DEFAULT_SUCCESS_THRESHOLD,
new address[](0)
);

Expand Down
Loading
Loading