From d9ce30aa0ad57c55f43945f4c4f84580df84a4fe Mon Sep 17 00:00:00 2001 From: Ashitaka Date: Thu, 24 Oct 2024 16:29:26 -0300 Subject: [PATCH] feat: modifier and tests --- solidity/contracts/Oracle.sol | 61 ++++++--- solidity/contracts/utils/OracleTypehash.sol | 2 - solidity/interfaces/IOracle.sol | 29 +++- .../test/integration/EscalateDispute.t.sol | 15 +- solidity/test/integration/IntegrationBase.sol | 16 ++- .../test/integration/ResponseDispute.t.sol | 11 +- .../test/integration/ResponseProposal.t.sol | 36 ++++- .../mocks/contracts/MockAtomicArbitrator.sol | 2 +- solidity/test/unit/Oracle.t.sol | 128 ++++++++++++++---- 9 files changed, 234 insertions(+), 66 deletions(-) diff --git a/solidity/contracts/Oracle.sol b/solidity/contracts/Oracle.sol index dbc19a5..62931ce 100644 --- a/solidity/contracts/Oracle.sol +++ b/solidity/contracts/Oracle.sol @@ -18,7 +18,6 @@ import { _ESCALATE_TYPEHASH, _FINALIZE_TYPEHASH, _PROPOSE_TYPEHASH, - _RESOLVE_TYPEHASH, _UPDATE_TYPEHASH } from './utils/OracleTypehash.sol'; @@ -66,6 +65,18 @@ contract Oracle is IOracle, AccessController { */ mapping(bytes32 _requestId => bytes _responseIds) internal _responseIds; + /** + * @notice Modifier to check if the user approved to the access control module + * @param _user The address of the user + * @param _accessControlModule The access control module to check if approved + */ + modifier isApproved(address _user, address _accessControlModule) { + if (_accessControlModule != address(0) && !isAccessControlApproved[_user][_accessControlModule]) { + revert Oracle_AccessControlModuleNotApproved(); + } + _; + } + /// @inheritdoc IOracle function getResponseIds(bytes32 _requestId) public view returns (bytes32[] memory _ids) { bytes memory _responses = _responseIds[_requestId]; @@ -107,6 +118,13 @@ contract Oracle is IOracle, AccessController { } } + /// @inheritdoc IOracle + function setAccessControlModule(address _accessControlModule, bool _approved) external { + isAccessControlApproved[msg.sender][_accessControlModule] = _approved; + + emit AccessControlModuleSet(msg.sender, _accessControlModule, _approved); + } + /// @inheritdoc IOracle function createRequest( Request calldata _request, @@ -125,7 +143,7 @@ contract Oracle is IOracle, AccessController { uint256 _requestsAmount = _requestsData.length; _batchRequestsIds = new bytes32[](_requestsAmount); - for (uint256 _i = 0; _i < _requestsAmount;) { + for (uint256 _i; _i < _requestsAmount;) { _batchRequestsIds[_i] = _createRequest(_requestsData[_i], _ipfsHashes[_i], _accessControl[_i]); unchecked { ++_i; @@ -140,6 +158,7 @@ contract Oracle is IOracle, AccessController { AccessControl calldata _accessControl ) external + isApproved(_accessControl.user, _request.accessControlModule) hasAccess(_request.accessControlModule, _PROPOSE_TYPEHASH, abi.encode(_request, _response), _accessControl) returns (bytes32 _responseId) { @@ -180,6 +199,7 @@ contract Oracle is IOracle, AccessController { AccessControl calldata _accessControl ) external + isApproved(_accessControl.user, _request.accessControlModule) hasAccess(_request.accessControlModule, _DISPUTE_TYPEHASH, abi.encode(_request, _response, _dispute), _accessControl) returns (bytes32 _disputeId) { @@ -225,6 +245,7 @@ contract Oracle is IOracle, AccessController { AccessControl calldata _accessControl ) external + isApproved(_accessControl.user, _request.accessControlModule) hasAccess(_request.accessControlModule, _ESCALATE_TYPEHASH, abi.encode(_request, _response, _dispute), _accessControl) { (bytes32 _responseId, bytes32 _disputeId) = ValidatorLib._validateResponseAndDispute(_request, _response, _dispute); @@ -256,15 +277,7 @@ contract Oracle is IOracle, AccessController { } /// @inheritdoc IOracle - function resolveDispute( - Request calldata _request, - Response calldata _response, - Dispute calldata _dispute, - AccessControl calldata _accessControl - ) - external - hasAccess(_request.accessControlModule, _RESOLVE_TYPEHASH, abi.encode(_request, _response, _dispute), _accessControl) - { + function resolveDispute(Request calldata _request, Response calldata _response, Dispute calldata _dispute) external { (bytes32 _responseId, bytes32 _disputeId) = ValidatorLib._validateResponseAndDispute(_request, _response, _dispute); if (disputeCreatedAt[_disputeId] == 0) { @@ -292,13 +305,14 @@ contract Oracle is IOracle, AccessController { /// @inheritdoc IOracle function updateDisputeStatus( - Request calldata _request, - Response calldata _response, - Dispute calldata _dispute, + Request memory _request, + Response memory _response, + Dispute memory _dispute, DisputeStatus _status, AccessControl calldata _accessControl ) external + isApproved(_accessControl.user, _request.accessControlModule) hasAccess( _request.accessControlModule, _UPDATE_TYPEHASH, @@ -316,16 +330,24 @@ contract Oracle is IOracle, AccessController { revert Oracle_InvalidDisputeId(_disputeId); } + // Needed to avoid stack too deep when try to compile + Request memory _currentRequest = _request; + Response memory _currentResponse = _response; + Dispute memory _currentDispute = _dispute; + DisputeStatus _currentStatus = _status; + if ( - _accessControl.user != address(_request.disputeModule) - && _accessControl.user != address(_request.resolutionModule) + _accessControl.user != address(_currentRequest.disputeModule) + && _accessControl.user != address(_currentRequest.resolutionModule) ) { revert Oracle_NotDisputeOrResolutionModule(_accessControl.user); } - disputeStatus[_disputeId] = _status; - IDisputeModule(_request.disputeModule).onDisputeStatusChange(_disputeId, _request, _response, _dispute); + disputeStatus[_disputeId] = _currentStatus; + IDisputeModule(_currentRequest.disputeModule).onDisputeStatusChange( + _disputeId, _currentRequest, _currentResponse, _currentDispute + ); - emit DisputeStatusUpdated(_disputeId, _dispute, _status); + emit DisputeStatusUpdated(_disputeId, _currentDispute, _currentStatus); } /// @inheritdoc IOracle @@ -445,6 +467,7 @@ contract Oracle is IOracle, AccessController { AccessControl calldata _accessControl ) internal + isApproved(_accessControl.user, _request.accessControlModule) hasAccess(_request.accessControlModule, _CREATE_TYPEHASH, abi.encode(_request), _accessControl) returns (bytes32 _requestId) { diff --git a/solidity/contracts/utils/OracleTypehash.sol b/solidity/contracts/utils/OracleTypehash.sol index 2a7029e..dea1760 100644 --- a/solidity/contracts/utils/OracleTypehash.sol +++ b/solidity/contracts/utils/OracleTypehash.sol @@ -10,8 +10,6 @@ bytes32 constant _DISPUTE_TYPEHASH = keccak256('DisputeResponse(Request _request bytes32 constant _ESCALATE_TYPEHASH = keccak256('EscalateDispute(Request _request,Response _response,Dispute _dispute)'); -bytes32 constant _RESOLVE_TYPEHASH = keccak256('ResolveDispute(Request _request,Response _response,Dispute _dispute)'); - bytes32 constant _UPDATE_TYPEHASH = keccak256('UpdateDisputeStatus(Request _request,Response _response,Dispute _dispute,DisputeStatus _status)'); diff --git a/solidity/interfaces/IOracle.sol b/solidity/interfaces/IOracle.sol index 0f4672f..9d47fad 100644 --- a/solidity/interfaces/IOracle.sol +++ b/solidity/interfaces/IOracle.sol @@ -12,6 +12,14 @@ interface IOracle is IAccessController { EVENTS //////////////////////////////////////////////////////////////*/ + /** + * @notice Emitted when the access control module is set + * @param _user The address of the user + * @param _accessControlModule The address of the access control module + * @param _approved If the module is approved + */ + event AccessControlModuleSet(address indexed _user, address indexed _accessControlModule, bool _approved); + /** * @notice Emitted when a request is created * @param _requestId The id of the created request @@ -70,6 +78,11 @@ interface IOracle is IAccessController { ERRORS //////////////////////////////////////////////////////////////*/ + /** + * @notice Thrown when user didn't approve the access control module + */ + error Oracle_AccessControlModuleNotApproved(); + /** * @notice Thrown when an unauthorized caller is trying to change a dispute's status * @param _caller The caller of the function @@ -370,6 +383,14 @@ interface IOracle is IAccessController { LOGIC //////////////////////////////////////////////////////////////*/ + /** + * @notice Sets the address of the access control module + * + * @param _accessControlModule The address of the access control module + * @param _approved If the module is approved + */ + function setAccessControlModule(address _accessControlModule, bool _approved) external; + /** * @notice Generates the request ID and initializes the modules for the request * @@ -450,14 +471,8 @@ interface IOracle is IAccessController { * @param _request The request * @param _response The disputed response * @param _dispute The dispute that is being resolved - * @param _accessControl The access control data */ - function resolveDispute( - Request calldata _request, - Response calldata _response, - Dispute calldata _dispute, - AccessControl calldata _accessControl - ) external; + function resolveDispute(Request calldata _request, Response calldata _response, Dispute calldata _dispute) external; /** * @notice Updates the status of a dispute diff --git a/solidity/test/integration/EscalateDispute.t.sol b/solidity/test/integration/EscalateDispute.t.sol index 83d317f..62e3ecb 100644 --- a/solidity/test/integration/EscalateDispute.t.sol +++ b/solidity/test/integration/EscalateDispute.t.sol @@ -14,12 +14,19 @@ contract Integration_EscalateDispute is IntegrationBase { oracle.proposeResponse(mockRequest, mockResponse, mockAccessControl); vm.stopPrank(); - // Dispute reverts if caller is not authorized - vm.startPrank(badCaller); - vm.expectRevert(abi.encodeWithSelector(IAccessController.AccessControlData_NoAccess.selector)); + // Revert if not approved to dispute + address _badDisputer = makeAddr('badDisputer'); + mockAccessControl.user = _badDisputer; + + // Reverts because caller is not approved to dispute + vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_AccessControlModuleNotApproved.selector)); + oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); + + // Dispute reverts if caller is not approved mockAccessControl.user = disputer; + vm.expectRevert(abi.encodeWithSelector(IAccessController.AccessControlData_NoAccess.selector)); + vm.prank(badCaller); oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); - vm.stopPrank(); // Dispute the response vm.startPrank(caller); diff --git a/solidity/test/integration/IntegrationBase.sol b/solidity/test/integration/IntegrationBase.sol index f15ccfe..4aedb45 100644 --- a/solidity/test/integration/IntegrationBase.sol +++ b/solidity/test/integration/IntegrationBase.sol @@ -149,9 +149,10 @@ contract IntegrationBase is TestConstants, Helpers { mockDispute.responseId = _getId(mockResponse); // Add the allowed callers to the access control module - address[] memory _allowedCallers = new address[](1); - _allowedCallers[0] = caller; - _accessControlModule.setHasAccess(_allowedCallers); + _setAccessControlForACaller(requester, caller); + _setAccessControlForACaller(proposer, caller); + _setAccessControlForACaller(disputer, caller); + _setAccessControlForACaller(finalizer, caller); vm.startPrank(caller); } @@ -164,4 +165,13 @@ contract IntegrationBase is TestConstants, Helpers { vm.warp(block.timestamp + _blocks * BLOCK_TIME); vm.roll(block.number + _blocks); } + + function _setAccessControlForACaller(address _delegator, address _caller) internal { + vm.startPrank(_delegator); + address[] memory _allowedCallers = new address[](1); + _allowedCallers[0] = _caller; + _accessControlModule.setHasAccess(_allowedCallers); + oracle.setAccessControlModule(address(_accessControlModule), true); + vm.stopPrank(); + } } diff --git a/solidity/test/integration/ResponseDispute.t.sol b/solidity/test/integration/ResponseDispute.t.sol index 3b815d7..c2cab00 100644 --- a/solidity/test/integration/ResponseDispute.t.sol +++ b/solidity/test/integration/ResponseDispute.t.sol @@ -30,19 +30,28 @@ contract Integration_ResponseDispute is IntegrationBase { mockAccessControl.user = finalizer; oracle.finalize(mockRequest, mockResponse, mockAccessControl); + // Revert if the dispute is already finalized mockAccessControl.user = disputer; vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_AlreadyFinalized.selector, _requestId)); oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); } function test_disputeResponse_alreadyDisputed() public { + // Dispute the response mockAccessControl.user = disputer; oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); address _anotherDisputer = makeAddr('anotherDisputer'); mockDispute.disputer = _anotherDisputer; - mockAccessControl.user = _anotherDisputer; + + // Revert if the response is access control is not approved + vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_AccessControlModuleNotApproved.selector)); + oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); + + // Revert if the response is already disputed + mockAccessControl.user = disputer; + mockDispute.disputer = disputer; vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_ResponseAlreadyDisputed.selector, _responseId)); oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); } diff --git a/solidity/test/integration/ResponseProposal.t.sol b/solidity/test/integration/ResponseProposal.t.sol index 0467de9..e9d1b43 100644 --- a/solidity/test/integration/ResponseProposal.t.sol +++ b/solidity/test/integration/ResponseProposal.t.sol @@ -8,16 +8,25 @@ contract Integration_ResponseProposal is IntegrationBase { function setUp() public override { super.setUp(); - vm.stopPrank(); mockRequest.nonce = uint96(oracle.totalRequestCount()); - mockAccessControl.user = requester; - vm.startPrank(badCaller); - vm.expectRevert(abi.encodeWithSelector(IAccessController.AccessControlData_NoAccess.selector)); + address _badRequester = makeAddr('badRequester'); + mockAccessControl.user = _badRequester; + + // Revert if not approved to create request + vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_AccessControlModuleNotApproved.selector)); oracle.createRequest(mockRequest, _ipfsHash, mockAccessControl); + vm.stopPrank(); + // Revert if has no access to create request + mockAccessControl.user = requester; + vm.expectRevert(abi.encodeWithSelector(IAccessController.AccessControlData_NoAccess.selector)); + vm.prank(badCaller); + oracle.createRequest(mockRequest, _ipfsHash, mockAccessControl); + + // Create request vm.startPrank(caller); _requestId = oracle.createRequest(mockRequest, _ipfsHash, mockAccessControl); } @@ -25,6 +34,22 @@ contract Integration_ResponseProposal is IntegrationBase { function test_proposeResponse_validResponse(bytes memory _response) public { mockResponse.response = _response; + // Revert if not approved to create request + vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_AccessControlModuleNotApproved.selector)); + address _badProposer = makeAddr('badProposer'); + mockAccessControl.user = _badProposer; + oracle.proposeResponse(mockRequest, mockResponse, mockAccessControl); + + vm.stopPrank(); + + // Revert if has no access to create request + mockAccessControl.user = proposer; + vm.expectRevert(abi.encodeWithSelector(IAccessController.AccessControlData_NoAccess.selector)); + vm.prank(badCaller); + oracle.proposeResponse(mockRequest, mockResponse, mockAccessControl); + + vm.startPrank(caller); + // Propose response mockAccessControl.user = proposer; oracle.proposeResponse(mockRequest, mockResponse, mockAccessControl); @@ -38,13 +63,16 @@ contract Integration_ResponseProposal is IntegrationBase { function test_proposeResponse_finalizedRequest(uint256 _timestamp) public { _timestamp = bound(_timestamp, _expectedDeadline + _baseDisputeWindow, type(uint128).max); + // Propose response mockAccessControl.user = proposer; oracle.proposeResponse(mockRequest, mockResponse, mockAccessControl); + // Finalize request vm.warp(_timestamp); mockAccessControl.user = finalizer; oracle.finalize(mockRequest, mockResponse, mockAccessControl); + // Revert if the request is already finalized mockAccessControl.user = proposer; mockResponse.response = abi.encode(_timestamp); vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_AlreadyFinalized.selector, _requestId)); diff --git a/solidity/test/mocks/contracts/MockAtomicArbitrator.sol b/solidity/test/mocks/contracts/MockAtomicArbitrator.sol index b7af1a2..a807c10 100644 --- a/solidity/test/mocks/contracts/MockAtomicArbitrator.sol +++ b/solidity/test/mocks/contracts/MockAtomicArbitrator.sol @@ -18,7 +18,7 @@ contract MockAtomicArbitrator { ) external returns (bytes memory _result) { _result = new bytes(0); answer = IOracle.DisputeStatus.Won; - // oracle.resolveDispute(_request, _response, _dispute); + oracle.resolveDispute(_request, _response, _dispute); } function getAnswer(bytes32 /* _dispute */ ) external view returns (IOracle.DisputeStatus _answer) { diff --git a/solidity/test/unit/Oracle.t.sol b/solidity/test/unit/Oracle.t.sol index 2d37deb..e3ddee4 100644 --- a/solidity/test/unit/Oracle.t.sol +++ b/solidity/test/unit/Oracle.t.sol @@ -73,6 +73,10 @@ contract MockOracle is Oracle { function mock_addResponseId(bytes32 _requestId, bytes32 _responseId) external { _responseIds[_requestId] = abi.encodePacked(_responseIds[_requestId], _responseId); } + + function mock_setAccessControlApproved(address _user, address _accessControlModule, bool _approved) external { + isAccessControlApproved[_user][_accessControlModule] = _approved; + } } /** @@ -101,6 +105,7 @@ contract BaseTest is Test, Helpers { event DisputeEscalated(address indexed _caller, bytes32 indexed _disputeId, IOracle.Dispute _dispute); event DisputeStatusUpdated(bytes32 indexed _disputeId, IOracle.Dispute _dispute, IOracle.DisputeStatus _status); event DisputeResolved(bytes32 indexed _disputeId, IOracle.Dispute _dispute); + event AccessControlModuleSet(address indexed _user, address indexed _accessControlModule, bool _approved); function setUp() public virtual { oracle = new MockOracle(); @@ -129,10 +134,28 @@ contract BaseTest is Test, Helpers { } } +contract Oracle_Unit_SetAccessControlModule is BaseTest { + /** + * @notice Test the access control module setter + */ + function test_setAccessControlModuleTrue(bool _approved) public { + // Check: emits AccessControlModuleSet event? + _expectEmit(address(oracle)); + emit AccessControlModuleSet(address(this), address(accessControlModule), _approved); + + // Test: set the access control module + oracle.setAccessControlModule(address(accessControlModule), _approved); + + // Check: correct access control module set? + assertEq(oracle.isAccessControlApproved(address(this), address(accessControlModule)), _approved); + } +} + contract Oracle_Unit_CreateRequest is BaseTest { modifier happyPath() { mockAccessControl.user = requester; vm.startPrank(requester); + oracle.mock_setAccessControlApproved(requester, address(accessControlModule), true); _; } /** @@ -195,6 +218,34 @@ contract Oracle_Unit_CreateRequest is BaseTest { assertEq(oracle.totalRequestCount(), _initialNonce + 1); } + /** + * @notice Check that creating a request with a non-approved access control module reverts + */ + function test_createRequest_revertsIfNotApproved() public { + // Check: revert? + vm.expectRevert(IOracle.Oracle_AccessControlModuleNotApproved.selector); + + // Test: try to create the request + oracle.createRequest(mockRequest, _ipfsHash, mockAccessControl); + } + + /** + * @notice Check that reverts if the access control module returns false + */ + function test_createRequest_revertsIfInvalidAccessControlData(address _caller) public { + vm.assume(_caller != requester); + + mockRequest.accessControlModule = address(0); + mockAccessControl.user = requester; + + // Check: revert? + vm.expectRevert(IAccessController.AccessControlData_NoAccess.selector); + + // Test: try to create the request + vm.prank(_caller); + oracle.createRequest(mockRequest, _ipfsHash, mockAccessControl); + } + /** * @notice Check that creating a request with a nonce that already exists reverts */ @@ -245,6 +296,9 @@ contract Oracle_Unit_CreateRequests is BaseTest { bytes32[] memory _ipfsHashes = new bytes32[](_requestsAmount); IAccessController.AccessControl[] memory _accessControls = new IAccessController.AccessControl[](_requestsAmount); + vm.startPrank(requester); + oracle.mock_setAccessControlApproved(requester, address(accessControlModule), true); + // Generate requests batch for (uint256 _i = 0; _i < _requestsAmount; _i++) { mockRequest.requestModuleData = _requestData; @@ -265,7 +319,6 @@ contract Oracle_Unit_CreateRequests is BaseTest { emit RequestCreated(_theoreticalRequestId, mockRequest, _ipfsHashes[_i]); } - vm.prank(requester); bytes32[] memory _requestsIds = oracle.createRequests(_requests, _ipfsHashes, _accessControls); for (uint256 _i = 0; _i < _requestsIds.length; _i++) { @@ -327,7 +380,8 @@ contract Oracle_Unit_CreateRequests is BaseTest { _accessControls[_i].user = requester; } - vm.prank(requester); + vm.startPrank(requester); + oracle.mock_setAccessControlApproved(requester, address(accessControlModule), true); oracle.createRequests(_requests, _ipfsHashes, _accessControls); uint256 _newNonce = oracle.totalRequestCount(); @@ -416,6 +470,7 @@ contract Oracle_Unit_ProposeResponse is BaseTest { modifier happyPath() { mockAccessControl.user = proposer; vm.startPrank(proposer); + oracle.mock_setAccessControlApproved(proposer, address(accessControlModule), true); _; } /** @@ -469,6 +524,17 @@ contract Oracle_Unit_ProposeResponse is BaseTest { assertEq(_responseIds[1], _secondResponseId); } + /** + * @notice Check that proposing a response with a non-approved access control module reverts + */ + function test_proposeResponse_revertsIfNotApproved() public { + // Check: revert? + vm.expectRevert(IOracle.Oracle_AccessControlModuleNotApproved.selector); + + // Test: try to create the request + oracle.proposeResponse(mockRequest, mockResponse, mockAccessControl); + } + function test_proposeResponse_revertsIfInvalidRequest() public happyPath { // Check: revert? vm.expectRevert(IOracle.Oracle_InvalidRequest.selector); @@ -502,6 +568,7 @@ contract Oracle_Unit_ProposeResponse is BaseTest { oracle.mock_setRequestCreatedAt(_getId(mockRequest), block.timestamp); + oracle.mock_setAccessControlApproved(_caller, address(accessControlModule), true); mockAccessControl.user = _caller; // Check: revert? @@ -562,6 +629,7 @@ contract Oracle_Unit_DisputeResponse is BaseTest { modifier happyPath() { mockAccessControl.user = disputer; vm.startPrank(disputer); + oracle.mock_setAccessControlApproved(disputer, address(accessControlModule), true); _; } @@ -594,6 +662,17 @@ contract Oracle_Unit_DisputeResponse is BaseTest { } } + /** + * @notice Check that dispute a response with a non-approved access control module reverts + */ + function test_disputeResponse_revertsIfNotApproved() public { + // Check: revert? + vm.expectRevert(IOracle.Oracle_AccessControlModuleNotApproved.selector); + + // Test: try to create the request + oracle.disputeResponse(mockRequest, mockResponse, mockDispute, mockAccessControl); + } + /** * @notice Reverts if the dispute proposer and response proposer are not same */ @@ -645,6 +724,7 @@ contract Oracle_Unit_DisputeResponse is BaseTest { function test_disputeResponse_revertIfWrongDisputer(address _caller) public { vm.assume(_caller != disputer); + oracle.mock_setAccessControlApproved(_caller, address(accessControlModule), true); mockAccessControl.user = _caller; // Check: revert? @@ -672,6 +752,7 @@ contract Oracle_Unit_UpdateDisputeStatus is BaseTest { modifier happyPath() { mockAccessControl.user = address(disputeModule); vm.startPrank(address(disputeModule)); + oracle.mock_setAccessControlApproved(address(disputeModule), address(accessControlModule), true); _; } /** @@ -716,6 +797,17 @@ contract Oracle_Unit_UpdateDisputeStatus is BaseTest { } } + /** + * @notice Check that update dispute status with a non-approved access control module reverts + */ + function test_updateDisputeStatus_revertsIfNotApproved() public { + // Check: revert? + vm.expectRevert(IOracle.Oracle_AccessControlModuleNotApproved.selector); + + // Test: try to create the request + oracle.updateDisputeStatus(mockRequest, mockResponse, mockDispute, IOracle.DisputeStatus.Active, mockAccessControl); + } + /** * @notice Providing a dispute that does not match the response should revert */ @@ -746,6 +838,7 @@ contract Oracle_Unit_UpdateDisputeStatus is BaseTest { mockRequest.accessControlModule = address(0); mockAccessControl.user = address(disputeModule); + oracle.mock_setAccessControlApproved(_caller, address(accessControlModule), true); // Check: revert? vm.expectRevert(IAccessController.AccessControlData_NoAccess.selector); @@ -768,6 +861,7 @@ contract Oracle_Unit_UpdateDisputeStatus is BaseTest { // Mock the dispute oracle.mock_setDisputeOf(_responseId, _disputeId); oracle.mock_setDisputeCreatedAt(_disputeId, block.timestamp); + oracle.mock_setAccessControlApproved(proposer, address(accessControlModule), true); mockAccessControl.user = proposer; vm.mockCall( @@ -793,6 +887,7 @@ contract Oracle_Unit_UpdateDisputeStatus is BaseTest { mockAccessControl.user = address(resolutionModule); oracle.mock_setDisputeCreatedAt(_disputeId, 0); + oracle.mock_setAccessControlApproved(address(resolutionModule), address(accessControlModule), true); // Check: revert? vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_InvalidDispute.selector)); @@ -805,7 +900,6 @@ contract Oracle_Unit_UpdateDisputeStatus is BaseTest { contract Oracle_Unit_ResolveDispute is BaseTest { modifier happyPath() { - mockAccessControl.user = address(resolutionModule); vm.startPrank(address(resolutionModule)); _; } @@ -835,24 +929,7 @@ contract Oracle_Unit_ResolveDispute is BaseTest { emit DisputeResolved(_disputeId, mockDispute); // Test: resolve the dispute - oracle.resolveDispute(mockRequest, mockResponse, mockDispute, mockAccessControl); - } - - /** - * @notice Revert if the access control module returns false - */ - function test_resolveDispute_revertsIfInvalidAccessControlData(address _caller) public { - vm.assume(_caller != address(resolutionModule)); - - mockRequest.accessControlModule = address(0); - mockAccessControl.user = address(resolutionModule); - - // Check: revert? - vm.expectRevert(IAccessController.AccessControlData_NoAccess.selector); - - // Test: try to propose a response from a random address - vm.prank(_caller); - oracle.resolveDispute(mockRequest, mockResponse, mockDispute, mockAccessControl); + oracle.resolveDispute(mockRequest, mockResponse, mockDispute); } /** @@ -865,7 +942,7 @@ contract Oracle_Unit_ResolveDispute is BaseTest { vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_InvalidDisputeId.selector, _getId(mockDispute))); // Test: try to resolve the dispute - oracle.resolveDispute(mockRequest, mockResponse, mockDispute, mockAccessControl); + oracle.resolveDispute(mockRequest, mockResponse, mockDispute); } /** @@ -878,7 +955,7 @@ contract Oracle_Unit_ResolveDispute is BaseTest { vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_InvalidDispute.selector)); // Test: try to resolve the dispute - oracle.resolveDispute(mockRequest, mockResponse, mockDispute, mockAccessControl); + oracle.resolveDispute(mockRequest, mockResponse, mockDispute); } /** @@ -905,7 +982,7 @@ contract Oracle_Unit_ResolveDispute is BaseTest { vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_CannotResolve.selector, _disputeId)); // Test: try to resolve the dispute - oracle.resolveDispute(mockRequest, mockResponse, mockDispute, mockAccessControl); + oracle.resolveDispute(mockRequest, mockResponse, mockDispute); } } @@ -935,7 +1012,7 @@ contract Oracle_Unit_ResolveDispute is BaseTest { vm.expectRevert(abi.encodeWithSelector(IOracle.Oracle_NoResolutionModule.selector, _disputeId)); // Test: try to resolve the dispute - oracle.resolveDispute(mockRequest, mockResponse, mockDispute, mockAccessControl); + oracle.resolveDispute(mockRequest, mockResponse, mockDispute); } } @@ -1276,6 +1353,7 @@ contract Oracle_Unit_EscalateDispute is BaseTest { modifier happyPath(address _caller) { mockAccessControl.user = _caller; vm.startPrank(_caller); + oracle.mock_setAccessControlApproved(_caller, address(accessControlModule), true); _; } /**