diff --git a/src/MultiBridgeMessageReceiver.sol b/src/MultiBridgeMessageReceiver.sol index 0edee6b..5df92c0 100644 --- a/src/MultiBridgeMessageReceiver.sol +++ b/src/MultiBridgeMessageReceiver.sol @@ -278,11 +278,13 @@ contract MultiBridgeMessageReceiver is IMultiBridgeMessageReceiver, ExecutorAwar if (_receiverAdapter == address(0)) { revert Error.ZERO_ADDRESS_INPUT(); } - if (_add) { - _addTrustedExecutor(_receiverAdapter); - } else { - _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"); } + emit BridgeReceiverAdapterUpdated(_receiverAdapter, _add); } diff --git a/src/libraries/Error.sol b/src/libraries/Error.sol index abc6ab2..0cdbbdc 100644 --- a/src/libraries/Error.sol +++ b/src/libraries/Error.sol @@ -20,6 +20,10 @@ library Error { /// @dev is thrown if caller is invalid receiver adapter error INVALID_RECEIVER_ADAPTER(); + /// @dev is thrown if updating a receiver adapter fails + /// @param reason is the reason for failure + error UPDATE_RECEIVER_ADAPTER_FAILED(string reason); + /// @dev is thrown if caller is not self error INVALID_SELF_CALLER(); diff --git a/test/unit-tests/MultiBridgeMessageReceiver.t.sol b/test/unit-tests/MultiBridgeMessageReceiver.t.sol index e1e1188..2572d85 100644 --- a/test/unit-tests/MultiBridgeMessageReceiver.t.sol +++ b/test/unit-tests/MultiBridgeMessageReceiver.t.sol @@ -404,6 +404,19 @@ contract MultiBridgeMessageReceiverTest is Setup { assertTrue(receiver.isTrustedExecutor(address(42))); } + /// @dev adding a receiver adapter that already exists should fail + function test_update_receiver_adapter_add_existing() public { + vm.startPrank(timelockAddr); + + address[] memory updatedAdapters = new address[](1); + updatedAdapters[0] = wormholeAdapterAddr; + bool[] memory operations = new bool[](1); + operations[0] = true; + + vm.expectRevert(abi.encodeWithSelector(Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, "adapter already added")); + receiver.updateReceiverAdapters(updatedAdapters, operations); + } + /// @dev removes one receiver adapter function test_update_receiver_adapter_remove() public { vm.startPrank(timelockAddr); @@ -424,6 +437,21 @@ contract MultiBridgeMessageReceiverTest is Setup { assertTrue(receiver.isTrustedExecutor(axelarAdapterAddr)); } + /// @dev removing a receiver adapter that does not exist should fail + function test_update_receiver_adapter_remove_non_existing() public { + vm.startPrank(timelockAddr); + + address[] memory updatedAdapters = new address[](1); + updatedAdapters[0] = address(42); + bool[] memory operations = new bool[](1); + operations[0] = false; + + assertFalse(receiver.isTrustedExecutor(address(42))); + + vm.expectRevert(abi.encodeWithSelector(Error.UPDATE_RECEIVER_ADAPTER_FAILED.selector, "adapter not found")); + receiver.updateReceiverAdapters(updatedAdapters, operations); + } + /// @dev only governance timelock can call function test_update_receiver_adapter_only_governance_timelock() public { vm.startPrank(caller);