Skip to content

Commit

Permalink
feat: ebo access module
Browse files Browse the repository at this point in the history
  • Loading branch information
ashitakah committed Nov 11, 2024
1 parent 49186a7 commit 17ca3b8
Show file tree
Hide file tree
Showing 5 changed files with 355 additions and 1 deletion.
94 changes: 94 additions & 0 deletions src/contracts/EBOAccessModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 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';
// TODO: CHECK IF IS A MODULE, ACCESSCONTROLLER OR SOMETHING ELSE

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 _horizonStaking The address of the Horizon Staking contract
* @param _horizonAccountingExtension The address of the Horizon Accounting Extension contract
*/
constructor(
IOracle _oracle,
IArbitrable _arbitrable,
IHorizonStaking _horizonStaking,
IHorizonAccountingExtension _horizonAccountingExtension
) Module(_oracle) {
ARBITRABLE = _arbitrable;
_setHorizonStaking(_horizonStaking);
_setHorizonAccountingExtension(_horizonAccountingExtension);
}

/// @inheritdoc IEBOAccessModule
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 setHorizonStaking(IHorizonStaking _horizonStaking) external {
ARBITRABLE.validateArbitrator(msg.sender);
_setHorizonStaking(_horizonStaking);
}

/// @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 staking contract.
* @param _horizonStaking The new horizon staking contract.
*/
function _setHorizonStaking(IHorizonStaking _horizonStaking) internal {
horizonStaking = _horizonStaking;

emit HorizonStakingSet(_horizonStaking);
}

/**
* @notice Internal function to set the horizon accounting extension contract.
* @param _horizonAccountingExtension The new horizon accounting extension contract.
*/
function _setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) internal {
horizonAccountingExtension = _horizonAccountingExtension;

emit HorizonAccountingExtensionSet(_horizonAccountingExtension);
}
}
84 changes: 84 additions & 0 deletions src/interfaces/IEBOAccessModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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 Staking contract is set
* @param _horizonStaking The new Horizon Staking contract
*/
event HorizonStakingSet(IHorizonStaking indexed _horizonStaking);

/**
* @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 Staking contract
* @return _horizonStaking The Horizon Staking contract
*/
function horizonStaking() external view returns (IHorizonStaking _horizonStaking);

/**
* @notice The Horizon Accounting Extension contract
* @return _horizonAccountingExtension The Horizon Accounting Extension contract
*/
function horizonAccountingExtension() external view returns (IHorizonAccountingExtension _horizonAccountingExtension);

/**
* @notice Decodes the access control parameters
* @param _data The encoded access control parameters
* @return _params The decoded access control parameters
*/
function decodeAccessControlParameters(bytes calldata _data)
external
pure
returns (IAccessModule.AccessControlParameters memory _params);

/**
* @notice Checks if the sender has access
* @param _data The encoded access control parameters
* @return _hasAccess True if the sender has access
*/
function hasAccess(bytes calldata _data) external view returns (bool _hasAccess);

/*///////////////////////////////////////////////////////////////
LOGIC
//////////////////////////////////////////////////////////////*/

/**
* @notice Sets the Horizon Staking contract
* @param _horizonStaking The new Horizon Staking contract
*/
function setHorizonStaking(IHorizonStaking _horizonStaking) external;

/**
* @notice Sets the Horizon Accounting Extension contract
* @param _horizonAccountingExtension The new Horizon Accounting Extension contract
*/
function setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) external;
}
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 operator The address to check for auth
* @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
* @return Whether the operator is authorized or not
*/
function isAuthorized(address operator, address serviceProvider, address verifier) external view returns (bool);
}
167 changes: 167 additions & 0 deletions test/unit/EBOAccessModule.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;

import {
EBOAccessModule,
IAccessModule,
IArbitrable,
IEBOAccessModule,

Check warning on line 8 in test/unit/EBOAccessModule.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Variable "IEBOAccessModule" is unused

Check warning on line 8 in test/unit/EBOAccessModule.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Variable "IEBOAccessModule" is unused
IHorizonAccountingExtension,
IHorizonStaking,
IOracle
} from 'contracts/EBOAccessModule.sol';

import 'forge-std/Test.sol';

contract EBOAccessModuleForTest is EBOAccessModule {
constructor(
IOracle _oracle,
IArbitrable _arbitrable,
IHorizonStaking _horizonStaking,
IHorizonAccountingExtension _horizonAccountingExtension
) EBOAccessModule(_oracle, _arbitrable, _horizonStaking, _horizonAccountingExtension) {}

function setHorizonStakingForTest(IHorizonStaking _horizonStaking) external {
horizonStaking = _horizonStaking;
}

function setHorizonAccountingExtensionForTest(IHorizonAccountingExtension _horizonAccountingExtension) external {
horizonAccountingExtension = _horizonAccountingExtension;
}
}

contract EBOAccessModule_Unit_BaseTest is Test {
// Contracts
EBOAccessModuleForTest public eboAccessModule;
IOracle public oracle;
IArbitrable public arbitrable;
IHorizonStaking public horizonStaking;
IHorizonAccountingExtension public horizonAccountingExtension;

// Events
event HorizonStakingSet(IHorizonStaking indexed _horizonStaking);
event HorizonAccountingExtensionSet(IHorizonAccountingExtension indexed _horizonAccountingExtension);

function setUp() public {
oracle = IOracle(makeAddr('oracle'));
arbitrable = IArbitrable(makeAddr('arbitrable'));
horizonStaking = IHorizonStaking(makeAddr('horizonStaking'));
horizonAccountingExtension = IHorizonAccountingExtension(makeAddr('horizonAccountingExtension'));

eboAccessModule = new EBOAccessModuleForTest(oracle, arbitrable, horizonStaking, horizonAccountingExtension);
}
}

contract EBOAccessModule_Unit_Constructor is EBOAccessModule_Unit_BaseTest {
struct ConstructorParams {
IOracle oracle;
IArbitrable arbitrable;
IHorizonStaking horizonStaking;
IHorizonAccountingExtension horizonAccountingExtension;
}

function test_setOracle(ConstructorParams calldata _params) public {
eboAccessModule = new EBOAccessModuleForTest(
_params.oracle, _params.arbitrable, _params.horizonStaking, _params.horizonAccountingExtension
);

assertEq(address(eboAccessModule.ORACLE()), address(_params.oracle));
}

function test_setArbitrable(ConstructorParams calldata _params) public {
eboAccessModule = new EBOAccessModuleForTest(
_params.oracle, _params.arbitrable, _params.horizonStaking, _params.horizonAccountingExtension
);

assertEq(address(eboAccessModule.ARBITRABLE()), address(_params.arbitrable));
}

function test_setHorizonStaking(ConstructorParams calldata _params) public {
vm.expectEmit();
emit HorizonStakingSet(_params.horizonStaking);

eboAccessModule = new EBOAccessModuleForTest(
_params.oracle, _params.arbitrable, _params.horizonStaking, _params.horizonAccountingExtension
);

assertEq(address(eboAccessModule.horizonStaking()), address(_params.horizonStaking));
}

function test_setHorizonAccountingExtension(ConstructorParams calldata _params) public {
vm.expectEmit();
emit HorizonAccountingExtensionSet(_params.horizonAccountingExtension);

eboAccessModule = new EBOAccessModuleForTest(
_params.oracle, _params.arbitrable, _params.horizonStaking, _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(
horizonStaking.isAuthorized.selector,
_params.accessControl.user,
address(horizonAccountingExtension),
_params.sender
),
abi.encode(true)
);

eboAccessModule.hasAccess(_data);
}
}

contract EBOAccessModule_Unit_SetHorizonStaking is EBOAccessModule_Unit_BaseTest {
function test_setHorizonStaking(IHorizonStaking _horizonStaking) public {
vm.mockCall(
address(arbitrable), abi.encodeWithSelector(arbitrable.validateArbitrator.selector, msg.sender), abi.encode(true)
);

vm.expectEmit();
emit HorizonStakingSet(_horizonStaking);

eboAccessModule.setHorizonStaking(_horizonStaking);

assertEq(address(eboAccessModule.horizonStaking()), address(_horizonStaking));
}
}

contract EBOAccessModule_Unit_SetHorizonAccountingExtension is EBOAccessModule_Unit_BaseTest {
function test_setHorizonAccountingExtension(IHorizonAccountingExtension _horizonAccountingExtension) public {
vm.mockCall(
address(arbitrable), abi.encodeWithSelector(arbitrable.validateArbitrator.selector, msg.sender), abi.encode(true)
);

vm.expectEmit();
emit HorizonAccountingExtensionSet(_horizonAccountingExtension);

eboAccessModule.setHorizonAccountingExtension(_horizonAccountingExtension);

assertEq(address(eboAccessModule.horizonAccountingExtension()), address(_horizonAccountingExtension));
}
}
2 changes: 1 addition & 1 deletion test/unit/EBORequestCreator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 17ca3b8

Please sign in to comment.