Skip to content

Commit

Permalink
docs: add natspec to data service contracts
Browse files Browse the repository at this point in the history
Signed-off-by: Tomás Migone <[email protected]>
  • Loading branch information
tmigone committed May 30, 2024
1 parent 6093c53 commit 8616335
Show file tree
Hide file tree
Showing 17 changed files with 462 additions and 88 deletions.
24 changes: 21 additions & 3 deletions packages/horizon/contracts/data-service/DataService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,35 @@ import { GraphDirectory } from "./GraphDirectory.sol";
import { ProvisionManager } from "./utilities/ProvisionManager.sol";

/**
* @title Implementation of the {IDataService} interface.
* @dev This implementation provides base functionality for a data service:
* @title DataService contract
* @dev Implementation of the {IDataService} interface.
* @notice This implementation provides base functionality for a data service:
* - GraphDirectory, allows the data service to interact with Graph Horizon contracts
* - ProvisionManager, provides functionality to manage provisions
*
* The derived contract MUST implement all the interfaces described in {IDataService}.
* The derived contract MUST implement all the interfaces described in {IDataService} and in
* accordance with the Data Service framework.
* @dev Implementation must initialize the contract using {__DataService_init} or
* {__DataService_init_unchained} functions.
*/
abstract contract DataService is GraphDirectory, ProvisionManager, DataServiceV1Storage, IDataService {
/**
* @dev Addresses in GraphDirectory are immutables, they can only be set in this constructor.
* @param controller The address of the Graph Horizon controller contract.
*/
constructor(address controller) GraphDirectory(controller) {}

/**
* @notice Initializes the contract and any parent contracts.
*/
function __DataService_init() internal onlyInitializing {
__DataService_init_unchained();
}

/**
* @notice Initializes the contract.
*/
function __DataService_init_unchained() internal onlyInitializing {
__ProvisionManager_init_unchained();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { DataService } from "../DataService.sol";
import { DataServiceFeesV1Storage } from "./DataServiceFeesStorage.sol";

/**
* @title DataServiceFees
* @notice Adds functionality to the {IDataService} contract to handle payment collateralization
* using a Horizon provision. See {IDataServiceFees} for more details.
* @title DataServiceFees contract
* @dev Implementation of the {IDataServiceFees} interface.
* @notice Extension for the {IDataService} contract to handle payment collateralization
* using a Horizon provision. See {IDataServiceFees} for more details.
*/
abstract contract DataServiceFees is DataService, DataServiceFeesV1Storage, IDataServiceFees {
using ProvisionTracker for mapping(address => uint256);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { IDataServiceFees } from "../interfaces/IDataServiceFees.sol";

import { LinkedList } from "../../libraries/LinkedList.sol";

/**
* @title Storage layout for the {DataServiceFees} extension contract.
*/
abstract contract DataServiceFeesV1Storage {
mapping(address serviceProvider => uint256 tokens) public feesProvisionTracker;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,50 @@ import { IDataServicePausable } from "../interfaces/IDataServicePausable.sol";
import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol";
import { DataService } from "../DataService.sol";

/**
* @title DataServicePausable contract
* @dev Implementation of the {IDataServicePausable} interface.
* @notice Extension for the {IDataService} contract, adds pausing functionality
* to the data service. Pausing is controlled by privileged accounts called
* pause guardians.
* @dev Note that this extension does not provide an external function to set pause
* guardians. This should be implemented in the derived contract.
*/
abstract contract DataServicePausable is Pausable, DataService, IDataServicePausable {
/// @notice List of pause guardians and their allowed status
mapping(address pauseGuardian => bool allowed) public pauseGuardians;

/**
* @notice Checks if the caller is a pause guardian.
*/
modifier onlyPauseGuardian() {
require(pauseGuardians[msg.sender], DataServicePausableNotPauseGuardian(msg.sender));
_;
}

/**
* @notice See {IDataServicePausable-pause}
*/
function pause() external onlyPauseGuardian whenNotPaused {
_pause();
}

/**
* @notice See {IDataServicePausable-pause}
*/
function unpause() external onlyPauseGuardian whenPaused {
_unpause();
}

/**
* @notice Sets a pause guardian.
* @dev Internal function to be used by the derived contract to set pause guardians.
*
* Emits a {PauseGuardianSet} event.
*
* @param _pauseGuardian The address of the pause guardian
* @param _allowed The allowed status of the pause guardian
*/
function _setPauseGuardian(address _pauseGuardian, bool _allowed) internal whenNotPaused {
pauseGuardians[_pauseGuardian] = _allowed;
emit PauseGuardianSet(_pauseGuardian, _allowed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,61 @@ import { IDataServicePausable } from "../interfaces/IDataServicePausable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import { DataService } from "../DataService.sol";

/**
* @title DataServicePausableUpgradeable contract
* @dev Implementation of the {IDataServicePausable} interface.
* @dev Upgradeable version of the {DataServicePausable} contract.
*/
abstract contract DataServicePausableUpgradeable is PausableUpgradeable, DataService, IDataServicePausable {
/// @notice List of pause guardians and their allowed status
mapping(address pauseGuardian => bool allowed) public pauseGuardians;

/**
* @notice Checks if the caller is a pause guardian.
*/
modifier onlyPauseGuardian() {
require(pauseGuardians[msg.sender], DataServicePausableNotPauseGuardian(msg.sender));
_;
}

/**
* @notice See {IDataServicePausable-pause}
*/
function pause() external onlyPauseGuardian whenNotPaused {
_pause();
}

/**
* @notice See {IDataServicePausable-pause}
*/
function unpause() external onlyPauseGuardian whenPaused {
_unpause();
}

/**
* @notice Initializes the contract and parent contracts
*/
// solhint-disable-next-line func-name-mixedcase
function __DataServicePausable_init() internal {
function __DataServicePausable_init() internal onlyInitializing {
__Pausable_init_unchained();
__DataServicePausable_init_unchained();
}

/**
* @notice Initializes the contract
*/
// solhint-disable-next-line func-name-mixedcase
function __DataServicePausable_init_unchained() internal {}
function __DataServicePausable_init_unchained() internal onlyInitializing {}

/**
* @notice Sets a pause guardian.
* @dev Internal function to be used by the derived contract to set pause guardians.
*
* Emits a {PauseGuardianSet} event.
*
* @param _pauseGuardian The address of the pause guardian
* @param _allowed The allowed status of the pause guardian
*/
function _setPauseGuardian(address _pauseGuardian, bool _allowed) internal whenNotPaused {
pauseGuardians[_pauseGuardian] = _allowed;
emit PauseGuardianSet(_pauseGuardian, _allowed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,54 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
* @dev Allows a contract to have a function to rescue tokens sent by mistake.
* The contract must implement the external rescueTokens function or similar,
* that calls this contract's _rescueTokens.
* @dev Note that this extension does not provide an external function to set
* rescuers. This should be implemented in the derived contract.
*/
abstract contract DataServiceRescuable is DataService, IDataServiceRescuable {
/// @notice List of rescuers and their allowed status
mapping(address rescuer => bool allowed) public rescuers;

/**
* @notice Checks if the caller is a rescuer.
*/
modifier onlyRescuer() {
require(rescuers[msg.sender], DataServiceRescuableNotRescuer(msg.sender));
_;
}

function rescueGRT(address to, uint256 tokens) external onlyRescuer {
/**
* @notice See {IDataServiceRescuable-rescueGRT}
*/
function rescueGRT(address to, uint256 tokens) external virtual onlyRescuer {
_rescueTokens(to, address(_graphToken()), tokens);
}

function rescueETH(address payable to, uint256 tokens) external onlyRescuer {
/**
* @notice See {IDataServiceRescuable-rescueETH}
*/
function rescueETH(address payable to, uint256 tokens) external virtual onlyRescuer {
_rescueTokens(to, Denominations.NATIVE_TOKEN, tokens);
}

/**
* @notice Sets a rescuer.
* @dev Internal function to be used by the derived contract to set rescuers.
*
* Emits a {RescuerSet} event.
*
* @param _rescuer Address of the rescuer
* @param _allowed Allowed status of the rescuer
*/
function _setRescuer(address _rescuer, bool _allowed) internal {
rescuers[_rescuer] = _allowed;
emit RescuerSet(_rescuer, _allowed);
}

/**
* @dev Allows rescuing tokens sent to this contract
* @param _to Destination address to send the tokens
* @param _token Address of the token being rescued
* @param _tokens Amount of tokens to pull
* @param _to Destination address to send the tokens
* @param _token Address of the token being rescued
* @param _tokens Amount of tokens to pull
*/
function _rescueTokens(address _to, address _token, uint256 _tokens) internal {
require(_tokens != 0, DataServiceRescuableCannotRescueZero());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { IGraphPayments } from "../../interfaces/IGraphPayments.sol";

/**
* @title Interface of the base {DataService} contract as defined by the Graph Horizon specification.
* @notice This interface provides a guardrail for data service implementations that utilize Graph Horizon.
* It's expected that implementations follow the specification however much of it is intentionally loose
* to allow for greater flexibility when designing a data service. For specifics always check the data
* service implementation.
* In general, this is a great starting point for data services that want to use Graph Horizon
* to provide economic security for a service being provided.
* @notice This interface provides a guardrail for contracts that use the Data Service framework
* to implement a data service on Graph Horizon. Much of the specification is intentionally loose
* to allow for greater flexibility when designing a data service. It's not possible to guarantee that
* an implementation will honor the Data Service framework guidelines so it's advised to always review
* the implementation code and the documentation.
* @dev This interface is expected to be inherited and extended by a data service interface. It can be
* used to interact with it however it's advised to use the more specific parent interface.
*/
interface IDataService {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pragma solidity 0.8.26;
import { IDataService } from "./IDataService.sol";

/**
* @title Interface for the {IDataServiceFees} contract.
* @notice Adds functionality to the {IDataService} contract to handle payment collateralization
* @title Interface for the {DataServiceFees} contract.
* @notice Extension for the {IDataService} contract to handle payment collateralization
* using a Horizon provision.
*
* It's designed to be used with the Data Service framework:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,43 @@ pragma solidity 0.8.26;

import { IDataService } from "./IDataService.sol";

/**
* @title Interface for the {DataServicePausable} contract.
* @notice Extension for the {IDataService} contract, adds pausing functionality
* to the data service. Pausing is controlled by privileged accounts called
* pause guardians.
*/
interface IDataServicePausable is IDataService {
/**
* @notice Emitted when a pause guardian is set.
* @param account The address of the pause guardian
* @param allowed The allowed status of the pause guardian
*/
event PauseGuardianSet(address indexed account, bool allowed);

/**
* @notice Emitted when a the caller is not a pause guardian
* @param account The address of the pause guardian
*/
error DataServicePausableNotPauseGuardian(address account);

/**
* @notice Pauses the data service.
* @dev Note that only functions using the modifiers `whenNotPaused`
* and `whenPaused` will be affected by the pause.
*
* Requirements:
* - The contract must not be already paused
*/
function pause() external;

/**
* @notice Unpauses the data service.
* @dev Note that only functions using the modifiers `whenNotPaused`
* and `whenPaused` will be affected by the pause.
*
* Requirements:
* - The contract must be paused
*/
function unpause() external;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,57 @@ pragma solidity 0.8.26;

import { IDataService } from "./IDataService.sol";

/**
* @title Interface for the {IDataServicePausable} contract.
* @notice Extension for the {IDataService} contract, adds the ability to rescue
* any ERC20 token or ETH from the contract, controlled by a rescuer privileged role.
*/
interface IDataServiceRescuable is IDataService {
/**
* @dev Tokens rescued by the user
* @notice Emitted when tokens are rescued from the contract.
*/
event TokensRescued(address indexed from, address indexed to, uint256 tokens);

/**
* @notice Emitted when a rescuer is set.
*/
event RescuerSet(address indexed account, bool allowed);

/**
* @notice Thrown when trying to rescue zero tokens.
*/
error DataServiceRescuableCannotRescueZero();

/**
* @notice Thrown when the caller is not a rescuer.
*/
error DataServiceRescuableNotRescuer(address account);

/**
* @notice Rescues GRT tokens from the contract.
* @dev Declared as virtual to allow disabling the function via override.
*
* Requirements:
* - Cannot rescue zero tokens.
*
* Emits a {TokensRescued} event.
*
* @param to Address of the tokens recipient.
* @param tokens Amount of tokens to rescue.
*/
function rescueGRT(address to, uint256 tokens) external;

/**
* @notice Rescues ether from the contract.
* @dev Declared as virtual to allow disabling the function via override.
*
* Requirements:
* - Cannot rescue zeroether.
*
* Emits a {TokensRescued} event.
*
* @param to Address of the tokens recipient.
* @param tokens Amount of tokens to rescue.
*/
function rescueETH(address payable to, uint256 tokens) external;
}
Loading

0 comments on commit 8616335

Please sign in to comment.