Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ const eslintConfig = [
...globals.mocha,
},
},
rules: {
// Allow 'any' types in test files where they're often necessary for testing edge cases
'@typescript-eslint/no-explicit-any': 'off',
},
},

// Add Hardhat globals for hardhat config files
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"lint:yaml": "npx yaml-lint .github/**/*.{yml,yaml} packages/contracts/task/config/*.yml; prettier -w --cache --log-level warn '**/*.{yml,yaml}'",
"format": "prettier -w --cache --log-level warn '**/*.{js,ts,cjs,mjs,jsx,tsx,json,md,yaml,yml}'",
"test": "pnpm build && pnpm -r run test:self",
"test:coverage": "pnpm build && pnpm -r run test:coverage:self"
"test:coverage": "pnpm build && pnpm -r run build:self:coverage && pnpm -r run test:coverage:self"
},
"devDependencies": {
"@changesets/cli": "catalog:",
Expand Down
97 changes: 90 additions & 7 deletions packages/contracts/contracts/rewards/RewardsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@
// TODO: Re-enable and fix issues when publishing a new version
// solhint-disable gas-increment-by-one, gas-indexed-events, gas-small-strings, gas-strict-inequalities

import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";

Check warning on line 9 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @openzeppelin/contracts/math/SafeMath.sol
import { ERC165 } from "@openzeppelin/contracts/introspection/ERC165.sol";

Check warning on line 10 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @openzeppelin/contracts/introspection/ERC165.sol
import { IERC165 } from "@openzeppelin/contracts/introspection/IERC165.sol";

Check warning on line 11 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @openzeppelin/contracts/introspection/IERC165.sol

import { GraphUpgradeable } from "../upgrades/GraphUpgradeable.sol";
import { Managed } from "../governance/Managed.sol";
import { MathUtils } from "../staking/libs/MathUtils.sol";
import { IGraphToken } from "../token/IGraphToken.sol";

import { RewardsManagerV6Storage } from "./RewardsManagerStorage.sol";
import { IRewardsManager } from "@graphprotocol/interfaces/contracts/contracts/rewards/IRewardsManager.sol";
import { RewardsManagerV7Storage } from "./RewardsManagerStorage.sol";
import { IRewardsIssuer } from "./IRewardsIssuer.sol";
import { IRewardsManager } from "@graphprotocol/interfaces/contracts/contracts/rewards/IRewardsManager.sol";

Check warning on line 20 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @graphprotocol/interfaces/contracts/contracts/rewards/IRewardsManager.sol
import { IIssuanceAllocator } from "@graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceAllocator.sol";

Check warning on line 21 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceAllocator.sol
import { IIssuanceTarget } from "@graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceTarget.sol";

Check warning on line 22 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceTarget.sol
import { IRewardsEligibilityOracle } from "@graphprotocol/interfaces/contracts/issuance/eligibility/IRewardsEligibilityOracle.sol";

Check warning on line 23 in packages/contracts/contracts/rewards/RewardsManager.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManager.sol doesn't exist in: @graphprotocol/interfaces/contracts/issuance/eligibility/IRewardsEligibilityOracle.sol

/**
* @title Rewards Manager Contract
Expand All @@ -29,6 +32,10 @@
* total rewards for the Subgraph are split up for each Indexer based on much they have Staked on
* that Subgraph.
*
* @dev If an `issuanceAllocator` is set, it is used to determine the amount of GRT to be issued per block.
* Otherwise, the `issuancePerBlock` variable is used. In relation to the IssuanceAllocator, this contract
* is a self-minting target responsible for directly minting allocated GRT.
*
* Note:
* The contract provides getter functions to query the state of accrued rewards:
* - getAccRewardsPerSignal
Expand All @@ -39,7 +46,7 @@
* until the actual takeRewards function is called.
* custom:security-contact Please email security+contracts@ thegraph.com (remove space) if you find any bugs. We might have an active bug bounty program.
*/
contract RewardsManager is RewardsManagerV6Storage, GraphUpgradeable, IRewardsManager {
contract RewardsManager is RewardsManagerV7Storage, GraphUpgradeable, ERC165, IRewardsManager, IIssuanceTarget {
using SafeMath for uint256;

/// @dev Fixed point scaling factor used for decimals in reward calculations
Expand Down Expand Up @@ -85,6 +92,13 @@
*/
event SubgraphServiceSet(address indexed oldSubgraphService, address indexed newSubgraphService);

/**
* @notice Emitted when the issuance allocator is set
* @param oldIssuanceAllocator Previous issuance allocator address
* @param newIssuanceAllocator New issuance allocator address
*/
event IssuanceAllocatorSet(address indexed oldIssuanceAllocator, address indexed newIssuanceAllocator);

/**
* @notice Emitted when the rewards eligibility oracle contract is set
* @param oldRewardsEligibilityOracle Previous rewards eligibility oracle address
Expand Down Expand Up @@ -117,7 +131,10 @@

/**
* @inheritdoc IRewardsManager
* @dev The issuance is defined as a fixed amount of rewards per block in GRT.
* @dev When an IssuanceAllocator is set, the effective issuance will be determined by the allocator,
* but this local value can still be updated for cases when the allocator is later removed.
*
* The issuance is defined as a fixed amount of rewards per block in GRT.
* Whenever this function is called in layer 2, the updateL2MintAllowance function
* _must_ be called on the L1GraphTokenGateway in L1, to ensure the bridge can mint the
* right amount of tokens.
Expand Down Expand Up @@ -171,6 +188,48 @@
emit SubgraphServiceSet(oldSubgraphService, _subgraphService);
}

/**
* @inheritdoc IIssuanceTarget
* @dev This function facilitates upgrades by providing a standard way for targets
* to change their allocator. Only the governor can call this function.
* Note that the IssuanceAllocator can be set to the zero address to disable use of an allocator, and
* use the local `issuancePerBlock` variable instead to control issuance.
*/
function setIssuanceAllocator(address newIssuanceAllocator) external override onlyGovernor {
if (address(issuanceAllocator) != newIssuanceAllocator) {
// Update rewards calculation before changing the issuance allocator
updateAccRewardsPerSignal();

// Check that the contract supports the IIssuanceAllocator interface
// Allow zero address to disable the allocator
if (newIssuanceAllocator != address(0)) {
require(
IERC165(newIssuanceAllocator).supportsInterface(type(IIssuanceAllocator).interfaceId),
"Contract does not support IIssuanceAllocator interface"
);
}

address oldIssuanceAllocator = address(issuanceAllocator);
issuanceAllocator = IIssuanceAllocator(newIssuanceAllocator);
emit IssuanceAllocatorSet(oldIssuanceAllocator, newIssuanceAllocator);
}
}

/**
* @inheritdoc IIssuanceTarget
* @dev Ensures that all reward calculations are up-to-date with the current block
* before any allocation changes take effect.
*
* This function can be called by anyone to update the rewards calculation state.
* The IssuanceAllocator calls this function before changing a target's allocation to ensure
* all issuance is properly accounted for with the current issuance rate before applying an
* issuance allocation change.
*/
function beforeIssuanceAllocationChange() external override {
// Update rewards calculation with the current issuance rate
updateAccRewardsPerSignal();
}

/**
* @inheritdoc IRewardsManager
* @dev Note that the rewards eligibility oracle can be set to the zero address to disable use of an oracle, in
Expand All @@ -193,6 +252,17 @@
}
}

/**
* @inheritdoc ERC165
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IIssuanceTarget).interfaceId ||
interfaceId == type(IRewardsManager).interfaceId ||
interfaceId == type(IERC165).interfaceId ||
super.supportsInterface(interfaceId);
}

// -- Denylist --

/**
Expand Down Expand Up @@ -221,6 +291,17 @@

// -- Getters --

/**
* @inheritdoc IRewardsManager
* @dev Gets the effective issuance per block, taking into account the IssuanceAllocator if set
*/
function getRewardsIssuancePerBlock() public view override returns (uint256) {
if (address(issuanceAllocator) != address(0)) {
return issuanceAllocator.getTargetIssuancePerBlock(address(this)).selfIssuancePerBlock;
}
return issuancePerBlock;
}

/**
* @inheritdoc IRewardsManager
* @dev Linear formula: `x = r * t`
Expand All @@ -238,8 +319,10 @@
if (t == 0) {
return 0;
}
// ...or if issuance is zero
if (issuancePerBlock == 0) {

uint256 rewardsIssuancePerBlock = getRewardsIssuancePerBlock();

if (rewardsIssuancePerBlock == 0) {
return 0;
}

Expand All @@ -250,7 +333,7 @@
return 0;
}

uint256 x = issuancePerBlock.mul(t);
uint256 x = rewardsIssuancePerBlock.mul(t);

// Get the new issuance per signalled token
// We multiply the decimals to keep the precision as fixed-point number
Expand Down
12 changes: 12 additions & 0 deletions packages/contracts/contracts/rewards/RewardsManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

pragma solidity ^0.7.6 || 0.8.27;

import { IIssuanceAllocator } from "@graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceAllocator.sol";

Check warning on line 10 in packages/contracts/contracts/rewards/RewardsManagerStorage.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManagerStorage.sol doesn't exist in: @graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceAllocator.sol
import { IRewardsEligibilityOracle } from "@graphprotocol/interfaces/contracts/issuance/eligibility/IRewardsEligibilityOracle.sol";

Check warning on line 11 in packages/contracts/contracts/rewards/RewardsManagerStorage.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManagerStorage.sol doesn't exist in: @graphprotocol/interfaces/contracts/issuance/eligibility/IRewardsEligibilityOracle.sol
import { IRewardsIssuer } from "./IRewardsIssuer.sol";
import { IRewardsManager } from "@graphprotocol/interfaces/contracts/contracts/rewards/IRewardsManager.sol";

Check warning on line 13 in packages/contracts/contracts/rewards/RewardsManagerStorage.sol

View workflow job for this annotation

GitHub Actions / Lint Files

Import in packages/contracts/contracts/rewards/RewardsManagerStorage.sol doesn't exist in: @graphprotocol/interfaces/contracts/contracts/rewards/IRewardsManager.sol
import { Managed } from "../governance/Managed.sol";

/**
Expand Down Expand Up @@ -64,6 +65,7 @@
*/
contract RewardsManagerV4Storage is RewardsManagerV3Storage {
/// @notice GRT issued for indexer rewards per block
/// @dev Only used when issuanceAllocator is zero address.
uint256 public issuancePerBlock;
}

Expand All @@ -86,3 +88,13 @@
/// @notice Address of the rewards eligibility oracle contract
IRewardsEligibilityOracle public rewardsEligibilityOracle;
}

/**
* @title RewardsManagerV7Storage
* @author Edge & Node
* @notice Storage layout for RewardsManager V7
*/
contract RewardsManagerV7Storage is RewardsManagerV6Storage {
/// @notice Address of the issuance allocator
IIssuanceAllocator public issuanceAllocator;
}
Loading
Loading