diff --git a/package.json b/package.json index 314c053..0441263 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "scripts": { "build": "forge build", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", - "coverage": "forge coverage --report summary --report lcov --match-path 'test/unit/*'", + "coverage": "forge coverage --ir-minimum --report summary --report lcov --match-path 'test/unit/*'", "deploy:arbitrum": "bash -c 'source .env && forge script Deploy --rpc-url arbitrum --account $ARBITRUM_DEPLOYER_NAME --broadcast --verify --chain arbitrum -vvvvv'", "lint:check": "yarn lint:sol-tests && yarn lint:sol-logic && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol-tests --fix && yarn lint:sol-logic --fix", @@ -34,8 +34,8 @@ "package.json": "sort-package-json" }, "dependencies": { - "@defi-wonderland/prophet-core": "0.0.0-8bb062e0", - "@defi-wonderland/prophet-modules": "0.0.0-86078350" + "@defi-wonderland/prophet-core": "0.0.0-819e5fe9", + "@defi-wonderland/prophet-modules": "0.0.0-022dfec8" }, "devDependencies": { "@commitlint/cli": "19.3.0", diff --git a/src/contracts/CouncilArbitrator.sol b/src/contracts/CouncilArbitrator.sol index de15186..550fc12 100644 --- a/src/contracts/CouncilArbitrator.sol +++ b/src/contracts/CouncilArbitrator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.26; -import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/IAccessController.sol'; +import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/access/IAccessController.sol'; import {ValidatorLib} from '@defi-wonderland/prophet-core/solidity/libraries/ValidatorLib.sol'; import {IArbitrator} from '@defi-wonderland/prophet-modules/solidity/interfaces/IArbitrator.sol'; @@ -49,8 +49,7 @@ contract CouncilArbitrator is ICouncilArbitrator { function resolve( IOracle.Request calldata _request, IOracle.Response calldata _response, - IOracle.Dispute calldata _dispute, - IAccessController.AccessControl calldata _accessControl + IOracle.Dispute calldata _dispute ) external onlyArbitratorModule returns (bytes memory /* _data */ ) { bytes32 _disputeId = _dispute._getId(); diff --git a/src/contracts/EBOAccessModule.sol b/src/contracts/EBOAccessModule.sol new file mode 100644 index 0000000..fe11717 --- /dev/null +++ b/src/contracts/EBOAccessModule.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.26; + +import { + IAccessModule, + IArbitrable, + IEBOAccessModule, + IHorizonAccountingExtension, + IHorizonStaking, + IOracle +} from 'interfaces/IEBOAccessModule.sol'; + +import {IModule, Module} from '@defi-wonderland/prophet-core/solidity/contracts/Module.sol'; + +contract EBOAccessModule is IEBOAccessModule, Module { + /// @inheritdoc IEBOAccessModule + IArbitrable public immutable ARBITRABLE; + /// @inheritdoc IEBOAccessModule + IHorizonStaking public horizonStaking; + /// @inheritdoc IEBOAccessModule + IHorizonAccountingExtension public horizonAccountingExtension; + + /** + * @notice Constructor + * @param _oracle The address of the Oracle + * @param _arbitrable The address of the Arbitrable contract + * @param _horizonAccountingExtension The address of the Horizon Accounting Extension contract + */ + constructor( + IOracle _oracle, + IArbitrable _arbitrable, + IHorizonAccountingExtension _horizonAccountingExtension + ) Module(_oracle) { + ARBITRABLE = _arbitrable; + _setHorizonAccountingExtension(_horizonAccountingExtension); + } + + /// @inheritdoc IAccessModule + function decodeAccessControlParameters(bytes calldata _data) + public + pure + returns (IAccessModule.AccessControlParameters memory _params) + { + _params = abi.decode(_data, (IAccessModule.AccessControlParameters)); + } + + /// @inheritdoc IAccessModule + function hasAccess(bytes calldata _data) external view returns (bool _hasAccess) { + IAccessModule.AccessControlParameters memory _params = decodeAccessControlParameters(_data); + _hasAccess = + horizonStaking.isAuthorized(_params.accessControl.user, address(horizonAccountingExtension), _params.sender); + } + + /// @inheritdoc IEBOAccessModule + function setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) external { + ARBITRABLE.validateArbitrator(msg.sender); + + _setHorizonAccountingExtension(_horizonAccountingExtension); + } + + /// @inheritdoc IModule + function moduleName() external pure returns (string memory _moduleName) { + _moduleName = 'EBOAccessModule'; + } + + /** + * @notice Internal function to set the horizon accounting extension contract. + * @dev It also updates the `horizonStaking` address. + * @param _horizonAccountingExtension The new horizon accounting extension contract. + */ + function _setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) internal { + horizonAccountingExtension = _horizonAccountingExtension; + + // also update horizon staking address using the accounting extension view function + horizonStaking = _horizonAccountingExtension.HORIZON_STAKING(); + + emit HorizonAccountingExtensionSet(_horizonAccountingExtension); + } +} diff --git a/src/contracts/EBORequestCreator.sol b/src/contracts/EBORequestCreator.sol index edd42bf..ef40f89 100644 --- a/src/contracts/EBORequestCreator.sol +++ b/src/contracts/EBORequestCreator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.26; -import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/IAccessController.sol'; +import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/access/IAccessController.sol'; import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; import { @@ -84,7 +84,6 @@ contract EBORequestCreator is IEBORequestCreator { _requestModuleData.chainId = _chainId; _requestData.requestModuleData = abi.encode(_requestModuleData); - // default access control IAccessController.AccessControl memory _accessControl = IAccessController.AccessControl({user: address(this), data: bytes('')}); _requestId = ORACLE.createRequest(_requestData, bytes32(0), _accessControl); diff --git a/src/interfaces/IEBOAccessModule.sol b/src/interfaces/IEBOAccessModule.sol new file mode 100644 index 0000000..c6d6798 --- /dev/null +++ b/src/interfaces/IEBOAccessModule.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.26; + +import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol'; +import {IAccessModule} from '@defi-wonderland/prophet-core/solidity/interfaces/modules/access/IAccessModule.sol'; + +import {IHorizonAccountingExtension} from 'interfaces/IHorizonAccountingExtension.sol'; + +import {IHorizonStaking} from 'interfaces/external/IHorizonStaking.sol'; + +import {IArbitrable} from 'interfaces/IArbitrable.sol'; + +interface IEBOAccessModule is IAccessModule { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Emitted when the Horizon Accounting Extension contract is set + * @param _horizonAccountingExtension The new Horizon Accounting Extension contract + */ + event HorizonAccountingExtensionSet(IHorizonAccountingExtension indexed _horizonAccountingExtension); + + /*/////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////*/ + + /** + * @notice The Arbitrable contract + * @return _arbitrable The Arbitrable contract + */ + function ARBITRABLE() external view returns (IArbitrable _arbitrable); + + /** + * @notice The Horizon Accounting Extension contract + * @return _horizonAccountingExtension The Horizon Accounting Extension contract + */ + function horizonAccountingExtension() external view returns (IHorizonAccountingExtension _horizonAccountingExtension); + + /** + * @notice The Horizon Staking contract + * @return _horizonStaking The Horizon Staking contract + */ + function horizonStaking() external view returns (IHorizonStaking _horizonStaking); + + /*/////////////////////////////////////////////////////////////// + LOGIC + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Sets the Horizon Accounting Extension contract + * @param _horizonAccountingExtension The new Horizon Accounting Extension contract + */ + function setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) external; +} diff --git a/src/interfaces/external/IHorizonStaking.sol b/src/interfaces/external/IHorizonStaking.sol index 4df32ff..d351a11 100644 --- a/src/interfaces/external/IHorizonStaking.sol +++ b/src/interfaces/external/IHorizonStaking.sol @@ -132,4 +132,13 @@ interface IHorizonStaking { * @param verifierDestination The address to transfer the verifier cut to */ function slash(address serviceProvider, uint256 tokens, uint256 tokensVerifier, address verifierDestination) external; + + /** + * @notice Check if an operator is authorized for the caller on a specific verifier / data service. + * @param serviceProvider The service provider on behalf of whom they're claiming to act + * @param verifier The verifier / data service on which they're claiming to act + * @param operator The address to check for auth + * @return Whether the operator is authorized or not + */ + function isAuthorized(address serviceProvider, address verifier, address operator) external view returns (bool); } diff --git a/test/integration/arbitrum/BondEscalation.t.sol b/test/integration/arbitrum/BondEscalation.t.sol index 6b805d4..3de635e 100644 --- a/test/integration/arbitrum/BondEscalation.t.sol +++ b/test/integration/arbitrum/BondEscalation.t.sol @@ -54,7 +54,7 @@ contract IntegrationBondEscalation is IntegrationBase { _pledgeForDispute(_requestId, _disputeId); // Do not pass the dispute deadline nor the tying buffer - vm.warp(_disputeCreatedAt + disputeDeadline); + vm.warp(_disputeCreatedAt + disputeDeadline - 1); // Thaw some tokens uint256 _tokensToThaw = disputeBondSize * (maxNumberOfEscalations - 1) + 1; @@ -101,7 +101,7 @@ contract IntegrationBondEscalation is IntegrationBase { _pledgeAgainstDispute(_requestId, _disputeId); // Do not pass the dispute deadline nor the tying buffer - vm.warp(_disputeCreatedAt + disputeDeadline); + vm.warp(_disputeCreatedAt + disputeDeadline - 1); // Thaw some tokens uint256 _tokensToThaw = disputeBondSize * (maxNumberOfEscalations - 1) + 1; @@ -226,7 +226,7 @@ contract IntegrationBondEscalation is IntegrationBase { _settleBondEscalation(_requestId, _responseId, _disputeId); // Do not pass the dispute deadline nor the tying buffer - vm.warp(_disputeCreatedAt + disputeDeadline); + vm.warp(_disputeCreatedAt + disputeDeadline - 1); // Pledge against the dispute _pledgeAgainstDispute(_requestId, _disputeId); @@ -291,7 +291,7 @@ contract IntegrationBondEscalation is IntegrationBase { _settleBondEscalation(_requestId, _responseId, _disputeId); // Do not pass the dispute deadline nor the tying buffer - vm.warp(_disputeCreatedAt + disputeDeadline); + vm.warp(_disputeCreatedAt + disputeDeadline - 1); // Pledge for the dispute _pledgeForDispute(_requestId, _disputeId); diff --git a/test/integration/arbitrum/DisputeResponse.t.sol b/test/integration/arbitrum/DisputeResponse.t.sol index a1d5b93..9f50508 100644 --- a/test/integration/arbitrum/DisputeResponse.t.sol +++ b/test/integration/arbitrum/DisputeResponse.t.sol @@ -40,7 +40,7 @@ contract IntegrationDisputeResponse is IntegrationBase { _disputeResponse(_requestId, _responseId); // Do not pass the dispute window - vm.warp(_responseCreation + disputeDisputeWindow); + vm.warp(_responseCreation + disputeDisputeWindow - 1); // Thaw some tokens _thaw(_disputer, 1); diff --git a/test/integration/arbitrum/IntegrationBase.t.sol b/test/integration/arbitrum/IntegrationBase.t.sol index 41d6243..a651f95 100644 --- a/test/integration/arbitrum/IntegrationBase.t.sol +++ b/test/integration/arbitrum/IntegrationBase.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.26; -import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/IAccessController.sol'; +import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/access/IAccessController.sol'; import {ValidatorLib} from '@defi-wonderland/prophet-core/solidity/libraries/ValidatorLib.sol'; import {_ARBITRUM_SEPOLIA_GOVERNOR} from 'script/Constants.sol'; diff --git a/test/unit/CouncilArbitrator.t.sol b/test/unit/CouncilArbitrator.t.sol index 1657815..8246d68 100644 --- a/test/unit/CouncilArbitrator.t.sol +++ b/test/unit/CouncilArbitrator.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.26; -import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/IAccessController.sol'; import {IValidator} from '@defi-wonderland/prophet-core/solidity/interfaces/IValidator.sol'; +import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/access/IAccessController.sol'; import {Helpers} from 'test/utils/Helpers.sol'; @@ -116,11 +116,11 @@ contract CouncilArbitrator_Unit_Resolve is CouncilArbitrator_Unit_BaseTest { changePrank(_caller); vm.expectRevert(ICouncilArbitrator.CouncilArbitrator_OnlyArbitratorModule.selector); - councilArbitrator.resolve(_params.request, _params.response, _params.dispute, _createAccessControl()); + councilArbitrator.resolve(_params.request, _params.response, _params.dispute); } function test_setResolutions(ICouncilArbitrator.ResolutionParameters calldata _params) public happyPath { - councilArbitrator.resolve(_params.request, _params.response, _params.dispute, _createAccessControl()); + councilArbitrator.resolve(_params.request, _params.response, _params.dispute); bytes32 _disputeId = _params.dispute._getId(); (IOracle.Request memory _request, IOracle.Response memory _response, IOracle.Dispute memory _dispute) = @@ -136,7 +136,7 @@ contract CouncilArbitrator_Unit_Resolve is CouncilArbitrator_Unit_BaseTest { vm.expectEmit(); emit ResolutionStarted(_disputeId, _params.request, _params.response, _params.dispute); - councilArbitrator.resolve(_params.request, _params.response, _params.dispute, _createAccessControl()); + councilArbitrator.resolve(_params.request, _params.response, _params.dispute); } } diff --git a/test/unit/EBOAccessModule.t.sol b/test/unit/EBOAccessModule.t.sol new file mode 100644 index 0000000..2364b41 --- /dev/null +++ b/test/unit/EBOAccessModule.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.26; + +import '../utils/Helpers.sol'; +import { + EBOAccessModule, + IAccessModule, + IArbitrable, + IEBOAccessModule, + IHorizonAccountingExtension, + IHorizonStaking, + IOracle +} from 'contracts/EBOAccessModule.sol'; + +contract EBOAccessModuleForTest is EBOAccessModule { + constructor( + IOracle _oracle, + IArbitrable _arbitrable, + IHorizonAccountingExtension _horizonAccountingExtension + ) EBOAccessModule(_oracle, _arbitrable, _horizonAccountingExtension) {} + + function setHorizonAccountingExtensionForTest(IHorizonAccountingExtension _horizonAccountingExtension) external { + horizonAccountingExtension = _horizonAccountingExtension; + horizonStaking = _horizonAccountingExtension.HORIZON_STAKING(); + } +} + +contract EBOAccessModule_Unit_BaseTest is Helpers { + // Contracts + EBOAccessModuleForTest public eboAccessModule; + IOracle public oracle; + IArbitrable public arbitrable; + IHorizonAccountingExtension public horizonAccountingExtension; + IHorizonStaking internal horizonStaking = IHorizonStaking(makeAddr('horizonStaking')); + + function setUp() public { + oracle = IOracle(makeAddr('oracle')); + arbitrable = IArbitrable(makeAddr('arbitrable')); + horizonAccountingExtension = IHorizonAccountingExtension(makeAddr('horizonAccountingExtension')); + + _mockHorizonStakingCall(horizonAccountingExtension, horizonStaking); + + eboAccessModule = new EBOAccessModuleForTest(oracle, arbitrable, horizonAccountingExtension); + } + + function _mockHorizonStakingCall( + IHorizonAccountingExtension _horizonAccountingExtension, + IHorizonStaking _horizonStaking + ) internal { + vm.mockCall( + address(_horizonAccountingExtension), + abi.encodeCall(IHorizonAccountingExtension.HORIZON_STAKING, ()), + abi.encode(address(_horizonStaking)) + ); + } +} + +contract EBOAccessModule_Unit_Constructor is EBOAccessModule_Unit_BaseTest { + struct ConstructorParams { + IOracle oracle; + IArbitrable arbitrable; + IHorizonAccountingExtension horizonAccountingExtension; + } + + function test_setOracle(ConstructorParams calldata _params) public { + _assumeFuzzable(address(_params.horizonAccountingExtension)); + _mockHorizonStakingCall(_params.horizonAccountingExtension, horizonStaking); + + eboAccessModule = new EBOAccessModuleForTest(_params.oracle, _params.arbitrable, _params.horizonAccountingExtension); + + assertEq(address(eboAccessModule.ORACLE()), address(_params.oracle)); + } + + function test_setArbitrable(ConstructorParams calldata _params) public { + _assumeFuzzable(address(_params.horizonAccountingExtension)); + _mockHorizonStakingCall(_params.horizonAccountingExtension, horizonStaking); + + eboAccessModule = new EBOAccessModuleForTest(_params.oracle, _params.arbitrable, _params.horizonAccountingExtension); + + assertEq(address(eboAccessModule.ARBITRABLE()), address(_params.arbitrable)); + } + + function test_setHorizonAccountingExtension(ConstructorParams calldata _params) public { + _assumeFuzzable(address(_params.horizonAccountingExtension)); + _mockHorizonStakingCall(_params.horizonAccountingExtension, horizonStaking); + + vm.expectEmit(); + emit IEBOAccessModule.HorizonAccountingExtensionSet(_params.horizonAccountingExtension); + + eboAccessModule = new EBOAccessModuleForTest(_params.oracle, _params.arbitrable, _params.horizonAccountingExtension); + + assertEq(address(eboAccessModule.horizonAccountingExtension()), address(_params.horizonAccountingExtension)); + } +} + +contract EBOAccessModule_Unit_ModuleName is EBOAccessModule_Unit_BaseTest { + function test_returnModuleName() public view { + assertEq(eboAccessModule.moduleName(), 'EBOAccessModule'); + } +} + +contract EBOAccessModule_Unit_DecodeAccessControlParameters is EBOAccessModule_Unit_BaseTest { + function test_decodeAccessControlParameters(IAccessModule.AccessControlParameters calldata _params) public view { + bytes memory _data = abi.encode(_params); + + IAccessModule.AccessControlParameters memory _decodedParams = eboAccessModule.decodeAccessControlParameters(_data); + + assertEq(_decodedParams.accessControl.user, _params.accessControl.user); + assertEq(address(_decodedParams.sender), address(_params.sender)); + assertEq(_decodedParams.typehash, _params.typehash); + } +} + +contract EBOAccessModule_Unit_HasAccess is EBOAccessModule_Unit_BaseTest { + function test_hasAccess(IAccessModule.AccessControlParameters calldata _params) public { + bytes memory _data = abi.encode(_params); + + vm.mockCall( + address(horizonStaking), + abi.encodeWithSelector( + IHorizonStaking.isAuthorized.selector, + _params.accessControl.user, + address(horizonAccountingExtension), + _params.sender + ), + abi.encode(true) + ); + + eboAccessModule.hasAccess(_data); + } +} + +contract EBOAccessModule_Unit_SetHorizonAccountingExtension is EBOAccessModule_Unit_BaseTest { + function test_setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) public { + _assumeFuzzable(address(_horizonAccountingExtension)); + _mockHorizonStakingCall(_horizonAccountingExtension, horizonStaking); + vm.mockCall( + address(arbitrable), abi.encodeWithSelector(arbitrable.validateArbitrator.selector, msg.sender), abi.encode(true) + ); + + vm.expectEmit(); + emit IEBOAccessModule.HorizonAccountingExtensionSet(_horizonAccountingExtension); + + eboAccessModule.setHorizonAccountingExtension(_horizonAccountingExtension); + + assertEq(address(eboAccessModule.horizonAccountingExtension()), address(_horizonAccountingExtension)); + } +} diff --git a/test/unit/EBORequestCreator.t.sol b/test/unit/EBORequestCreator.t.sol index 565956b..9b21a1e 100644 --- a/test/unit/EBORequestCreator.t.sol +++ b/test/unit/EBORequestCreator.t.sol @@ -44,7 +44,7 @@ contract EBORequestCreatorForTest is EBORequestCreator { } } -abstract contract EBORequestCreator_Unit_BaseTest is Test { +contract EBORequestCreator_Unit_BaseTest is Test { /// Events event RequestCreated( bytes32 indexed _requestId, IOracle.Request _request, uint256 indexed _epoch, string indexed _chainId diff --git a/test/unit/HorizonAccountingExtension.t.sol b/test/unit/HorizonAccountingExtension.t.sol index 28aa0d8..020e96c 100644 --- a/test/unit/HorizonAccountingExtension.t.sol +++ b/test/unit/HorizonAccountingExtension.t.sol @@ -564,11 +564,16 @@ contract HorizonAccountingExtension_Unit_OnSettleBondEscalation is HorizonAccoun contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccountingExtension_Unit_BaseTest { modifier happyPath(uint256 _pledgesForDispute, uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount) { - vm.assume(_pledgesForDispute > 0 && _pledgesForDispute < type(uint64).max); - vm.assume(_pledgesAgainstDispute > 0 && _pledgesAgainstDispute < type(uint64).max); - vm.assume(_amount > type(uint16).max && _amount < type(uint64).max); - vm.assume(_bondSize > 0 && _bondSize < type(uint16).max); + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + _; + } + function _setUpHappyPath( + uint256 _pledgesForDispute, + uint256 _pledgesAgainstDispute, + uint256 _bondSize, + uint256 _amount + ) internal { horizonAccountingExtension.setDisputeBalanceForTest( _mockDisputeId, _amount * (_pledgesForDispute + _pledgesAgainstDispute) ); @@ -576,8 +581,6 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount horizonAccountingExtension.setEscalationResultForTest( _mockDisputeId, _mockRequestId, _amount, _bondSize, bondEscalationModule ); - - _; } function test_revertIfNoEscalationResult(address _pledger) public { @@ -591,7 +594,15 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _amount = bound(_amount, type(uint16).max, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + horizonAccountingExtension.setPledgerClaimedForTest(_mockRequestId, _pledger, true); vm.expectRevert(IHorizonAccountingExtension.HorizonAccountingExtension_AlreadyClaimed.selector); @@ -604,7 +615,15 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _amount = bound(_amount, type(uint16).max, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), @@ -634,7 +653,15 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _amount = bound(_amount, type(uint16).max, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), @@ -687,7 +714,15 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _amount = bound(_amount, type(uint16).max, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), @@ -734,7 +769,15 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _amount = bound(_amount, type(uint16).max, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), @@ -782,10 +825,18 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { vm.assume(_pledger != _slashedUser); vm.assume(_slashedUser != _notSlashedUser); + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max - 1); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max - 1); + _amount = bound(_amount, type(uint16).max, type(uint64).max - 1); + _bondSize = bound(_bondSize, 1, type(uint16).max - 1); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); + _pledgesAgainstDispute = _pledgesForDispute * _amount / _bondSize + 1; // Mock and expect the call to oracle checking the dispute status @@ -853,9 +904,16 @@ contract HorizonAccountingExtension_Unit_ClaimEscalationReward is HorizonAccount uint256 _pledgesAgainstDispute, uint256 _bondSize, uint256 _amount - ) public happyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount) { + ) public { vm.assume(_pledger != _slashedUser); vm.assume(_slashedUser != _notSlashedUser); + // bound input parameters + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max - 1); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max - 1); + _amount = bound(_amount, type(uint16).max, type(uint64).max - 1); + _bondSize = bound(_bondSize, 1, type(uint16).max - 1); + + _setUpHappyPath(_pledgesForDispute, _pledgesAgainstDispute, _bondSize, _amount); _pledgesForDispute = _pledgesAgainstDispute * _amount / _bondSize + 1; @@ -1478,11 +1536,12 @@ contract HorizonAccountingExtension_Unit_Slash is HorizonAccountingExtension_Uni uint256 _pledgesForDispute, uint256 _bondSize ) { - vm.assume(_usersToSlash > 0 && _usersToSlash < type(uint16).max); - vm.assume(_maxUsersToCheck > 0 && _maxUsersToCheck < type(uint16).max); + _setUpHappyPath(_users, _pledgesForDispute, _bondSize); + _; + } + + function _setUpHappyPath(address[] memory _users, uint256 _pledgesForDispute, uint256 _bondSize) internal { vm.assume(_users.length > 0 && _users.length < type(uint16).max); - vm.assume(_pledgesForDispute > 0 && _pledgesForDispute < type(uint16).max); - vm.assume(_bondSize > 0 && _bondSize < type(uint16).max); uint256 _slashAmount = _pledgesForDispute * _bondSize; @@ -1499,7 +1558,6 @@ contract HorizonAccountingExtension_Unit_Slash is HorizonAccountingExtension_Uni horizonAccountingExtension.setEscalationResultForTest( _mockDisputeId, _mockRequestId, 1, _bondSize, bondEscalationModule ); - _; } function test_revertIfNoEscalationResult(uint256 _usersToSlash, uint256 _maxUsersToCheck, address _pledger) public { @@ -1518,7 +1576,15 @@ contract HorizonAccountingExtension_Unit_Slash is HorizonAccountingExtension_Uni address[] memory _users, uint256 _pledgesAgainstDispute, uint256 _bondSize - ) public happyPath(_usersToSlash, _maxUsersToCheck, _users, _pledgesAgainstDispute, _bondSize) { + ) public { + // bound input parameters + _usersToSlash = bound(_usersToSlash, 1, type(uint16).max); + _maxUsersToCheck = bound(_maxUsersToCheck, 1, type(uint16).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_users, _pledgesAgainstDispute, _bondSize); + horizonAccountingExtension.setBondedTokensForTest(_cleanPledgers.at(0), 0); // Mock and expect the call to oracle checking the dispute status @@ -1554,7 +1620,15 @@ contract HorizonAccountingExtension_Unit_Slash is HorizonAccountingExtension_Uni address[] memory _users, uint256 _pledgesAgainstDispute, uint256 _bondSize - ) public happyPath(_usersToSlash, _maxUsersToCheck, _users, _pledgesAgainstDispute, _bondSize) { + ) public { + // bound input parameters + _usersToSlash = bound(_usersToSlash, 1, type(uint16).max); + _maxUsersToCheck = bound(_maxUsersToCheck, 1, type(uint16).max); + _pledgesAgainstDispute = bound(_pledgesAgainstDispute, 1, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_users, _pledgesAgainstDispute, _bondSize); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), @@ -1599,7 +1673,15 @@ contract HorizonAccountingExtension_Unit_Slash is HorizonAccountingExtension_Uni address[] memory _users, uint256 _pledgesForDispute, uint256 _bondSize - ) public happyPath(_usersToSlash, _maxUsersToCheck, _users, _pledgesForDispute, _bondSize) { + ) public { + // bound input parameters + _usersToSlash = bound(_usersToSlash, 1, type(uint16).max); + _maxUsersToCheck = bound(_maxUsersToCheck, 1, type(uint16).max); + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_users, _pledgesForDispute, _bondSize); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), @@ -1644,7 +1726,15 @@ contract HorizonAccountingExtension_Unit_Slash is HorizonAccountingExtension_Uni address[] memory _users, uint256 _pledgesForDispute, uint256 _bondSize - ) public happyPath(_usersToSlash, _maxUsersToCheck, _users, _pledgesForDispute, _bondSize) { + ) public { + // bound input parameters + _usersToSlash = bound(_usersToSlash, 1, type(uint16).max); + _maxUsersToCheck = bound(_maxUsersToCheck, 1, type(uint16).max); + _pledgesForDispute = bound(_pledgesForDispute, 1, type(uint64).max); + _bondSize = bound(_bondSize, 1, type(uint16).max); + + _setUpHappyPath(_users, _pledgesForDispute, _bondSize); + // Mock and expect the call to oracle checking the dispute status _mockAndExpect( address(oracle), diff --git a/test/utils/Helpers.sol b/test/utils/Helpers.sol index 164b5e9..bf4b8e3 100644 --- a/test/utils/Helpers.sol +++ b/test/utils/Helpers.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.19; -import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/IAccessController.sol'; import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol'; +import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/access/IAccessController.sol'; import 'forge-std/Test.sol'; diff --git a/yarn.lock b/yarn.lock index 959a157..dd2d686 100644 --- a/yarn.lock +++ b/yarn.lock @@ -180,22 +180,22 @@ solc-typed-ast "18.1.2" yargs "17.7.2" -"@defi-wonderland/prophet-core@0.0.0-823459fc": - version "0.0.0-823459fc" - resolved "https://registry.yarnpkg.com/@defi-wonderland/prophet-core/-/prophet-core-0.0.0-823459fc.tgz#a48f7b35899968468f37f5c9eb2c67a1c8a823ff" - integrity sha512-lqTFlKFUwt4yjBGnSUJf9PwNQE6MP4KJHUSCov2+yxJCkKHKzFlYQ7M25dAdebiwa6Hfd+XHQfLx1bzff6mM6Q== - -"@defi-wonderland/prophet-core@0.0.0-8bb062e0": - version "0.0.0-8bb062e0" - resolved "https://registry.yarnpkg.com/@defi-wonderland/prophet-core/-/prophet-core-0.0.0-8bb062e0.tgz#6678171885de8ddd484b7f51a8a8d6dca6ab9ab3" - integrity sha512-jjMly9ZjPHxxiBEpU6+OGNhyII+eDYYTVifTttX59uZTdmDsPSue818pkjr29YJJ62zGc0XEEe5Yzrwuirs5Tw== - -"@defi-wonderland/prophet-modules@0.0.0-86078350": - version "0.0.0-86078350" - resolved "https://registry.yarnpkg.com/@defi-wonderland/prophet-modules/-/prophet-modules-0.0.0-86078350.tgz#902877ef3f6585cd1a61066f0989ed05ce2e5b89" - integrity sha512-vAooZ+EXiounXQ3fiTya9yslFk7THerCxnQGQFEtJCIJU3hadbr8AzZOr+uRyMljs5f2/62YBeZC64RAxj9S1w== - dependencies: - "@defi-wonderland/prophet-core" "0.0.0-823459fc" +"@defi-wonderland/prophet-core@0.0.0-819e5fe9": + version "0.0.0-819e5fe9" + resolved "https://registry.yarnpkg.com/@defi-wonderland/prophet-core/-/prophet-core-0.0.0-819e5fe9.tgz#bd165f5cec99ae23bfd8c7f2f2cc3fa018abc676" + integrity sha512-K+zc0woc2mbZ6kqtO7ix/TJp7Y4YuCyz+l1XJL0VumsQkw7nJ5pLXOaV8Ss4wOyxu+P6vQ4aJpfY2yMHjQ+Hsw== + +"@defi-wonderland/prophet-core@0.0.0-c80cc1e9": + version "0.0.0-c80cc1e9" + resolved "https://registry.yarnpkg.com/@defi-wonderland/prophet-core/-/prophet-core-0.0.0-c80cc1e9.tgz#3586b8bcde26bd670384155f187888745af1e000" + integrity sha512-CU/IRGdOPoHDBiNv3XdimdJqx8Tl/4o3JrkYBKVfx+VW58k9e5i9XquAk+NqDiGZx18TMFZwskkt6fA5cMAQHQ== + +"@defi-wonderland/prophet-modules@0.0.0-022dfec8": + version "0.0.0-022dfec8" + resolved "https://registry.yarnpkg.com/@defi-wonderland/prophet-modules/-/prophet-modules-0.0.0-022dfec8.tgz#eade840c8b66689912f7effe1854add6c59113b8" + integrity sha512-TAsvkfkCyrk94jJ8YcV3HQtXX0jqiu/ufTq79PyUIpYWxTP09b//H4QPs5iE3xKcawSN2wUbmscNzJsH4/t/kw== + dependencies: + "@defi-wonderland/prophet-core" "0.0.0-c80cc1e9" "@openzeppelin/contracts" "4.9.5" solmate "https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c" @@ -1684,9 +1684,9 @@ solhint-community@4.0.0: optionalDependencies: prettier "^2.8.3" -"solmate@https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c": +"solmate@git+https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c": version "6.1.0" - resolved "https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c" + resolved "git+https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c" sort-object-keys@^1.1.3: version "1.1.3"