Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: access control #50

Merged
merged 20 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
xorsal marked this conversation as resolved.
Show resolved Hide resolved
_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
Loading