From b83212f8ae02115b938da800415da5d51d0efeeb Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 17 Oct 2023 20:59:29 -0400 Subject: [PATCH] feat: add access control invariants --- .../AccessControl.Invariant.sol | 40 +++++++++++++ .../invariant-tests/AdapterList.Invariant.sol | 8 +-- .../handlers/AccessControlSender.Handler.sol | 58 +++++++++++++++++++ .../handlers/AdapterList.Handler.sol | 2 +- 4 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 test/invariant-tests/AccessControl.Invariant.sol create mode 100644 test/invariant-tests/handlers/AccessControlSender.Handler.sol diff --git a/test/invariant-tests/AccessControl.Invariant.sol b/test/invariant-tests/AccessControl.Invariant.sol new file mode 100644 index 0000000..ea0fd13 --- /dev/null +++ b/test/invariant-tests/AccessControl.Invariant.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.9; + +/// library imports +import {Vm, Test} from "forge-std/Test.sol"; + +/// local imports +import "test/Setup.t.sol"; + +/// handler import +import {AccessControlSenderHandler} from "test/invariant-tests/handlers/AccessControlSender.handler.sol"; + +contract AccessControlHandlerInvariant is Setup { + AccessControlSenderHandler public handler; + + /// @notice nonce snapshot for assertions + uint256 public localNonceState; + + function setUp() public override { + /// @dev calls setup to spin up test contracts + super.setUp(); + + /// @dev selects fork and deploy the handlers + vm.selectFork(fork[SRC_CHAIN_ID]); + handler = new AccessControlSenderHandler( + contractAddress[SRC_CHAIN_ID]["GAC"], + contractAddress[SRC_CHAIN_ID]["MMA_SENDER"] + ); + + /// @dev bind the handler as target for invariant + targetContract(address(handler)); + } + + function invariant_test_acess_control_src() public { + if (handler.lastCaller() == MessageSenderGAC(contractAddress[SRC_CHAIN_ID]["GAC"]).authorisedCaller()) { + ++localNonceState; + } + assertEq(MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID]["MMA_SENDER"]).nonce(), localNonceState); + } +} diff --git a/test/invariant-tests/AdapterList.Invariant.sol b/test/invariant-tests/AdapterList.Invariant.sol index 9b17a18..5c73430 100644 --- a/test/invariant-tests/AdapterList.Invariant.sol +++ b/test/invariant-tests/AdapterList.Invariant.sol @@ -6,7 +6,6 @@ import {Vm, Test} from "forge-std/Test.sol"; /// local imports import "test/Setup.t.sol"; -import "test/contracts-mock/MockUniswapReceiver.sol"; /// handler import import {AdapterListHandler} from "test/invariant-tests/handlers/AdapterList.handler.sol"; @@ -40,7 +39,7 @@ contract AdapterListInvariant is Setup { /// @notice invariant-6: once a trusted executor is removed, it should not persist in the adapter list function invariant_test_adapter_additions() public { MultiBridgeMessageSender targetContract = MultiBridgeMessageSender(contractAddress[SRC_CHAIN_ID]["MMA_SENDER"]); - + if (handler.success()) { uint256 currAdds = handler.currAdds(); @@ -56,10 +55,7 @@ contract AdapterListInvariant is Setup { /// @dev assertions for invariant-3, invariant-4, invariant-5, invariant-6 if (currAdds > 1) { for (uint256 i = currAdds; i > 0; i--) { - assertTrue( - targetContract.senderAdapters(i) - > targetContract.senderAdapters(i - 1) - ); + assertTrue(targetContract.senderAdapters(i) > targetContract.senderAdapters(i - 1)); } } } diff --git a/test/invariant-tests/handlers/AccessControlSender.Handler.sol b/test/invariant-tests/handlers/AccessControlSender.Handler.sol new file mode 100644 index 0000000..834a796 --- /dev/null +++ b/test/invariant-tests/handlers/AccessControlSender.Handler.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.9; + +/// library imports +import "forge-std/Test.sol"; + +/// local imports +import {MessageSenderGAC} from "src/controllers/MessageSenderGAC.sol"; +import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol"; + +/// @notice handler for testing access control invariants +contract AccessControlSenderHandler is Test { + /// @notice local state + MultiBridgeMessageSender public multiBridgeMessageSender; + MessageSenderGAC public gac; + + /// @notice logs last caller for validations + address public lastCaller; + + /// @notice modifier to prank caller + modifier prank(address _prankster) { + vm.startPrank(_prankster); + _; + vm.stopPrank(); + } + + /// @notice initial setup contracts + constructor(address _gac, address _multiBridge) { + gac = MessageSenderGAC(_gac); + multiBridgeMessageSender = MultiBridgeMessageSender(_multiBridge); + } + + /// @notice helper for remote call + function remoteCall( + address simulatedCaller, + uint256 _dstChainId, + address _target, + bytes memory _callData, + uint256 _nativeValue, + uint256 _expiration, + address _refundAddress, + uint256[] memory _fees, + uint256 _successThreshold, + address[] memory _excludedAdapters + ) external prank(simulatedCaller) { + multiBridgeMessageSender.remoteCall( + _dstChainId, + _target, + _callData, + _nativeValue, + _expiration, + _refundAddress, + _fees, + _successThreshold, + _excludedAdapters + ); + } +} diff --git a/test/invariant-tests/handlers/AdapterList.Handler.sol b/test/invariant-tests/handlers/AdapterList.Handler.sol index 3cf6746..cde92f9 100644 --- a/test/invariant-tests/handlers/AdapterList.Handler.sol +++ b/test/invariant-tests/handlers/AdapterList.Handler.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.9; /// library imports import "forge-std/Test.sol"; -/// library imports +/// local imports import {MessageSenderGAC} from "src/controllers/MessageSenderGAC.sol"; import {MultiBridgeMessageSender} from "src/MultiBridgeMessageSender.sol";