@@ -7,15 +7,19 @@ pragma abicoder v2;
77// solhint-disable gas-increment-by-one, gas-indexed-events, gas-small-strings, gas-strict-inequalities
88
99import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol " ;
10+ import { IERC165 } from "@openzeppelin/contracts/introspection/IERC165.sol " ;
1011
1112import { GraphUpgradeable } from "../upgrades/GraphUpgradeable.sol " ;
1213import { Managed } from "../governance/Managed.sol " ;
1314import { MathUtils } from "../staking/libs/MathUtils.sol " ;
1415import { IGraphToken } from "@graphprotocol/interfaces/contracts/contracts/token/IGraphToken.sol " ;
1516
16- import { RewardsManagerV5Storage } from "./RewardsManagerStorage.sol " ;
17+ import { RewardsManagerV6Storage } from "./RewardsManagerStorage.sol " ;
1718import { IRewardsIssuer } from "@graphprotocol/interfaces/contracts/contracts/rewards/IRewardsIssuer.sol " ;
1819import { IRewardsManager } from "@graphprotocol/interfaces/contracts/contracts/rewards/IRewardsManager.sol " ;
20+ import { IIssuanceAllocationDistribution } from "@graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceAllocationDistribution.sol " ;
21+ import { IIssuanceTarget } from "@graphprotocol/interfaces/contracts/issuance/allocate/IIssuanceTarget.sol " ;
22+ import { IRewardsEligibility } from "@graphprotocol/interfaces/contracts/issuance/eligibility/IRewardsEligibility.sol " ;
1923
2024/**
2125 * @title Rewards Manager Contract
@@ -27,6 +31,10 @@ import { IRewardsManager } from "@graphprotocol/interfaces/contracts/contracts/r
2731 * total rewards for the Subgraph are split up for each Indexer based on much they have Staked on
2832 * that Subgraph.
2933 *
34+ * @dev If an `issuanceAllocator` is set, it is used to determine the amount of GRT to be issued per block.
35+ * Otherwise, the `issuancePerBlock` variable is used. In relation to the IssuanceAllocator, this contract
36+ * is a self-minting target responsible for directly minting allocated GRT.
37+ *
3038 * Note:
3139 * The contract provides getter functions to query the state of accrued rewards:
3240 * - getAccRewardsPerSignal
@@ -37,7 +45,7 @@ import { IRewardsManager } from "@graphprotocol/interfaces/contracts/contracts/r
3745 * until the actual takeRewards function is called.
3846 * custom:security-contact Please email security+contracts@ thegraph.com (remove space) if you find any bugs. We might have an active bug bounty program.
3947 */
40- contract RewardsManager is RewardsManagerV5Storage , GraphUpgradeable , IRewardsManager {
48+ contract RewardsManager is RewardsManagerV6Storage , GraphUpgradeable , IERC165 , IRewardsManager , IIssuanceTarget {
4149 using SafeMath for uint256 ;
4250
4351 /// @dev Fixed point scaling factor used for decimals in reward calculations
@@ -61,6 +69,14 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
6169 */
6270 event RewardsDenied (address indexed indexer , address indexed allocationID );
6371
72+ /**
73+ * @notice Emitted when rewards are denied to an indexer due to eligibility
74+ * @param indexer Address of the indexer being denied rewards
75+ * @param allocationID Address of the allocation being denied rewards
76+ * @param amount Amount of rewards that would have been assigned
77+ */
78+ event RewardsDeniedDueToEligibility (address indexed indexer , address indexed allocationID , uint256 amount );
79+
6480 /**
6581 * @notice Emitted when a subgraph is denied for claiming rewards
6682 * @param subgraphDeploymentID Subgraph deployment ID being denied
@@ -75,6 +91,23 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
7591 */
7692 event SubgraphServiceSet (address indexed oldSubgraphService , address indexed newSubgraphService );
7793
94+ /**
95+ * @notice Emitted when the issuance allocator is set
96+ * @param oldIssuanceAllocator Previous issuance allocator address
97+ * @param newIssuanceAllocator New issuance allocator address
98+ */
99+ event IssuanceAllocatorSet (address indexed oldIssuanceAllocator , address indexed newIssuanceAllocator );
100+
101+ /**
102+ * @notice Emitted when the rewards eligibility oracle contract is set
103+ * @param oldRewardsEligibilityOracle Previous rewards eligibility oracle address
104+ * @param newRewardsEligibilityOracle New rewards eligibility oracle address
105+ */
106+ event RewardsEligibilityOracleSet (
107+ address indexed oldRewardsEligibilityOracle ,
108+ address indexed newRewardsEligibilityOracle
109+ );
110+
78111 // -- Modifiers --
79112
80113 /**
@@ -93,12 +126,27 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
93126 Managed._initialize (_controller);
94127 }
95128
129+ /**
130+ * @inheritdoc IERC165
131+ * @dev Implements ERC165 interface detection
132+ * Returns true if this contract implements the interface defined by interfaceId.
133+ * See: https://eips.ethereum.org/EIPS/eip-165
134+ */
135+ function supportsInterface (bytes4 interfaceId ) public view virtual override returns (bool ) {
136+ return
137+ interfaceId == type (IERC165 ).interfaceId ||
138+ interfaceId == type (IIssuanceTarget).interfaceId ||
139+ interfaceId == type (IRewardsManager).interfaceId;
140+ }
141+
96142 // -- Config --
97143
98144 /**
99145 * @inheritdoc IRewardsManager
146+ * @dev When an IssuanceAllocator is set, the effective issuance will be determined by the allocator,
147+ * but this local value can still be updated for cases when the allocator is later removed.
100148 *
101- * @dev The issuance is defined as a fixed amount of rewards per block in GRT.
149+ * The issuance is defined as a fixed amount of rewards per block in GRT.
102150 * Whenever this function is called in layer 2, the updateL2MintAllowance function
103151 * _must_ be called on the L1GraphTokenGateway in L1, to ensure the bridge can mint the
104152 * right amount of tokens.
@@ -152,6 +200,70 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
152200 emit SubgraphServiceSet (oldSubgraphService, _subgraphService);
153201 }
154202
203+ /**
204+ * @inheritdoc IIssuanceTarget
205+ * @dev This function facilitates upgrades by providing a standard way for targets
206+ * to change their allocator. Only the governor can call this function.
207+ * Note that the IssuanceAllocator can be set to the zero address to disable use of an allocator, and
208+ * use the local `issuancePerBlock` variable instead to control issuance.
209+ */
210+ function setIssuanceAllocator (address newIssuanceAllocator ) external override onlyGovernor {
211+ if (address (issuanceAllocator) != newIssuanceAllocator) {
212+ // Update rewards calculation before changing the issuance allocator
213+ updateAccRewardsPerSignal ();
214+
215+ // Check that the contract supports the IIssuanceAllocationDistribution interface
216+ // Allow zero address to disable the allocator
217+ if (newIssuanceAllocator != address (0 )) {
218+ require (
219+ IERC165 (newIssuanceAllocator).supportsInterface (type (IIssuanceAllocationDistribution).interfaceId),
220+ "Contract does not support IIssuanceAllocationDistribution interface "
221+ );
222+ }
223+
224+ address oldIssuanceAllocator = address (issuanceAllocator);
225+ issuanceAllocator = IIssuanceAllocationDistribution (newIssuanceAllocator);
226+ emit IssuanceAllocatorSet (oldIssuanceAllocator, newIssuanceAllocator);
227+ }
228+ }
229+
230+ /**
231+ * @inheritdoc IIssuanceTarget
232+ * @dev Ensures that all reward calculations are up-to-date with the current block
233+ * before any allocation changes take effect.
234+ *
235+ * This function can be called by anyone to update the rewards calculation state.
236+ * The IssuanceAllocator calls this function before changing a target's allocation to ensure
237+ * all issuance is properly accounted for with the current issuance rate before applying an
238+ * issuance allocation change.
239+ */
240+ function beforeIssuanceAllocationChange () external override {
241+ // Update rewards calculation with the current issuance rate
242+ updateAccRewardsPerSignal ();
243+ }
244+
245+ /**
246+ * @inheritdoc IRewardsManager
247+ * @dev Note that the rewards eligibility oracle can be set to the zero address to disable use of an oracle, in
248+ * which case no indexers will be denied rewards due to eligibility.
249+ */
250+ function setRewardsEligibilityOracle (address newRewardsEligibilityOracle ) external override onlyGovernor {
251+ if (address (rewardsEligibilityOracle) != newRewardsEligibilityOracle) {
252+ // Check that the contract supports the IRewardsEligibility interface
253+ // Allow zero address to disable the oracle
254+ if (newRewardsEligibilityOracle != address (0 )) {
255+ require (
256+ IERC165 (newRewardsEligibilityOracle).supportsInterface (type (IRewardsEligibility).interfaceId),
257+ "Contract does not support IRewardsEligibility interface "
258+ );
259+ }
260+
261+ address oldRewardsEligibilityOracle = address (rewardsEligibilityOracle);
262+ rewardsEligibilityOracle = IRewardsEligibility (newRewardsEligibilityOracle);
263+ emit RewardsEligibilityOracleSet (oldRewardsEligibilityOracle, newRewardsEligibilityOracle);
264+ }
265+ }
266+
155267 // -- Denylist --
156268
157269 /**
@@ -180,6 +292,17 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
180292
181293 // -- Getters --
182294
295+ /**
296+ * @inheritdoc IRewardsManager
297+ * @dev Gets the effective issuance per block, taking into account the IssuanceAllocator if set
298+ */
299+ function getRewardsIssuancePerBlock () public view override returns (uint256 ) {
300+ if (address (issuanceAllocator) != address (0 )) {
301+ return issuanceAllocator.getTargetIssuancePerBlock (address (this )).selfIssuancePerBlock;
302+ }
303+ return issuancePerBlock;
304+ }
305+
183306 /**
184307 * @inheritdoc IRewardsManager
185308 * @dev Linear formula: `x = r * t`
@@ -197,8 +320,10 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
197320 if (t == 0 ) {
198321 return 0 ;
199322 }
200- // ...or if issuance is zero
201- if (issuancePerBlock == 0 ) {
323+
324+ uint256 rewardsIssuancePerBlock = getRewardsIssuancePerBlock ();
325+
326+ if (rewardsIssuancePerBlock == 0 ) {
202327 return 0 ;
203328 }
204329
@@ -209,7 +334,7 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
209334 return 0 ;
210335 }
211336
212- uint256 x = issuancePerBlock .mul (t);
337+ uint256 x = rewardsIssuancePerBlock .mul (t);
213338
214339 // Get the new issuance per signalled token
215340 // We multiply the decimals to keep the precision as fixed-point number
@@ -405,6 +530,13 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
405530 rewards = accRewardsPending.add (
406531 _calcRewards (tokens, accRewardsPerAllocatedToken, updatedAccRewardsPerAllocatedToken)
407532 );
533+
534+ // Do not reward if indexer is not eligible based on rewards eligibility
535+ if (address (rewardsEligibilityOracle) != address (0 ) && ! rewardsEligibilityOracle.isEligible (indexer)) {
536+ emit RewardsDeniedDueToEligibility (indexer, _allocationID, rewards);
537+ return 0 ;
538+ }
539+
408540 if (rewards > 0 ) {
409541 // Mint directly to rewards issuer for the reward amount
410542 // The rewards issuer contract will do bookkeeping of the reward and
0 commit comments