Skip to content

Commit

Permalink
feat: access control (#50)
Browse files Browse the repository at this point in the history
Co-authored-by: zorzal <[email protected]>
Co-authored-by: Ashitaka <[email protected]>
  • Loading branch information
3 people authored Nov 18, 2024
1 parent 34e6099 commit e1cacd7
Show file tree
Hide file tree
Showing 21 changed files with 687 additions and 320 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -34,8 +34,8 @@
"package.json": "sort-package-json"
},
"dependencies": {
"@defi-wonderland/prophet-core": "0.0.0-96d1084b",
"@defi-wonderland/prophet-modules": "0.0.0-b72dcda6"
"@defi-wonderland/prophet-core": "0.0.0-819e5fe9",
"@defi-wonderland/prophet-modules": "0.0.0-022dfec8"
},
"devDependencies": {
"@commitlint/cli": "19.3.0",
Expand Down
3 changes: 3 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ contract Deploy is Script {
_requestData.nonce = 0;

// Set requester and modules

_requestData.requester = address(eboRequestCreator);
// todo : replace with HorizonOperatorAccessModule
_requestData.accessModule = address(0);
_requestData.requestModule = address(eboRequestModule);
_requestData.responseModule = address(bondedResponseModule);
_requestData.disputeModule = address(bondEscalationModule);
Expand Down
9 changes: 7 additions & 2 deletions src/contracts/CouncilArbitrator.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;

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';

Expand Down Expand Up @@ -68,16 +69,20 @@ contract CouncilArbitrator is ICouncilArbitrator {
if (getAnswer[_disputeId] != IOracle.DisputeStatus.None) revert CouncilArbitrator_DisputeAlreadyArbitrated();

getAnswer[_disputeId] = _award;
IAccessController.AccessControl memory _accessControl =
IAccessController.AccessControl({user: address(this), data: bytes('')});

ORACLE.resolveDispute(_resolutionParams.request, _resolutionParams.response, _resolutionParams.dispute);
ORACLE.resolveDispute(
_resolutionParams.request, _resolutionParams.response, _resolutionParams.dispute, _accessControl
);

// If the request was not finalized, finalize it
if (ORACLE.finalizedAt(_resolutionParams.dispute.requestId) == 0) {
// If the dispute was lost, finalize with response
if (_award != IOracle.DisputeStatus.Lost) {
_resolutionParams.response.requestId = 0;
}
ORACLE.finalize(_resolutionParams.request, _resolutionParams.response);
ORACLE.finalize(_resolutionParams.request, _resolutionParams.response, _accessControl);
}

emit DisputeArbitrated(_disputeId, _award);
Expand Down
79 changes: 79 additions & 0 deletions src/contracts/EBOAccessModule.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}
6 changes: 4 additions & 2 deletions src/contracts/EBORequestCreator.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;

import {IAccessController} from '@defi-wonderland/prophet-core/solidity/interfaces/access/IAccessController.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';

import {
Expand Down Expand Up @@ -81,10 +82,11 @@ contract EBORequestCreator is IEBORequestCreator {
) revert EBORequestCreator_RequestAlreadyCreated();

_requestModuleData.chainId = _chainId;

_requestData.requestModuleData = abi.encode(_requestModuleData);

_requestId = ORACLE.createRequest(_requestData, bytes32(0));
IAccessController.AccessControl memory _accessControl =
IAccessController.AccessControl({user: address(this), data: bytes('')});
_requestId = ORACLE.createRequest(_requestData, bytes32(0), _accessControl);

requestIdPerChainAndEpoch[_chainId][_epoch] = _requestId;

Expand Down
1 change: 0 additions & 1 deletion src/contracts/EBORequestModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity 0.8.26;

import {IModule, Module} from '@defi-wonderland/prophet-core/solidity/contracts/Module.sol';

import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';

import {IArbitrable, IEBORequestCreator, IEBORequestModule, IOracle} from 'interfaces/IEBORequestModule.sol';
Expand Down
55 changes: 55 additions & 0 deletions src/interfaces/IEBOAccessModule.sol
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions src/interfaces/IEBORequestCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ interface IEBORequestCreator {
* @return _disputeModule The dispute module address
* @return _resolutionModule The resolution module address
* @return _finalityModule The finality module address
* @return _accessModule The address of the access module
* @return _requestModuleData The request module data
* @return _responseModuleData The response module data
* @return _disputeModuleData The dispute module data
Expand All @@ -170,6 +171,7 @@ interface IEBORequestCreator {
address _disputeModule,
address _resolutionModule,
address _finalityModule,
address _accessModule,
bytes memory _requestModuleData,
bytes memory _responseModuleData,
bytes memory _disputeModuleData,
Expand Down
9 changes: 9 additions & 0 deletions src/interfaces/external/IHorizonStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
8 changes: 4 additions & 4 deletions test/integration/arbitrum/BondEscalation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 9 additions & 3 deletions test/integration/arbitrum/CreateRequest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ contract IntegrationCreateRequest is IntegrationBase {

// Should revert if the requester is not the EBORequestCreator
vm.expectRevert(IEBORequestModule.EBORequestModule_InvalidRequester.selector);
vm.prank(_requester);
_requestData.requester = _requester;
oracle.createRequest(_requestData, '');

vm.prank(_requester);
oracle.createRequest(_requestData, '', _createAccessControl());

// Should revert if the epoch is invalid
vm.expectRevert(IEBORequestCreator.EBORequestCreator_InvalidEpoch.selector);
Expand All @@ -44,7 +45,12 @@ contract IntegrationCreateRequest is IntegrationBase {
_requestData.requester = address(eboRequestCreator);

// Expect the oracle to create the request
vm.expectCall(address(oracle), abi.encodeWithSelector(IOracle.createRequest.selector, _requestData, bytes32(0)));
vm.expectCall(
address(oracle),
abi.encodeWithSelector(
IOracle.createRequest.selector, _requestData, bytes32(0), _createAccessControl(address(eboRequestCreator))
)
);

vm.prank(_requester);
eboRequestCreator.createRequest(_currentEpoch, _chainId);
Expand Down
2 changes: 1 addition & 1 deletion test/integration/arbitrum/DisputeResponse.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit e1cacd7

Please sign in to comment.