Skip to content

Commit 48be37a

Browse files
authored
Merge pull request #1267 from graphprotocol/issuance-allocator-6
IA: Audit fix/response for Issuance Allocator Incorporated into audit report (Graph_IssuanceAllocator_v01.pdf) and now part of baseline for subsequent.
2 parents dbf5d2b + 88ce412 commit 48be37a

File tree

14 files changed

+1564
-200
lines changed

14 files changed

+1564
-200
lines changed

packages/contracts/contracts/rewards/RewardsManager.sol

Lines changed: 130 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,46 @@ contract RewardsManager is RewardsManagerV6Storage, GraphUpgradeable, IERC165, I
108108
address indexed newRewardsEligibilityOracle
109109
);
110110

111+
/**
112+
* @notice Emitted when the eligibility reclaim address is set
113+
* @param oldReclaimAddress Previous eligibility reclaim address
114+
* @param newReclaimAddress New eligibility reclaim address
115+
*/
116+
event IndexerEligibilityReclaimAddressSet(address indexed oldReclaimAddress, address indexed newReclaimAddress);
117+
118+
/**
119+
* @notice Emitted when the subgraph reclaim address is set
120+
* @param oldReclaimAddress Previous subgraph reclaim address
121+
* @param newReclaimAddress New subgraph reclaim address
122+
*/
123+
event SubgraphDeniedReclaimAddressSet(address indexed oldReclaimAddress, address indexed newReclaimAddress);
124+
125+
/**
126+
* @notice Emitted when denied rewards are reclaimed due to eligibility
127+
* @param indexer Address of the indexer whose rewards were denied
128+
* @param allocationID Address of the allocation
129+
* @param amount Amount of rewards reclaimed
130+
*/
131+
event RewardsReclaimedDueToIndexerEligibility(
132+
address indexed indexer,
133+
address indexed allocationID,
134+
uint256 amount
135+
);
136+
137+
/**
138+
* @notice Emitted when denied rewards are reclaimed due to subgraph denylist
139+
* @param indexer Address of the indexer whose rewards were denied
140+
* @param allocationID Address of the allocation
141+
* @param subgraphDeploymentID Subgraph deployment ID that was denied
142+
* @param amount Amount of rewards reclaimed
143+
*/
144+
event RewardsReclaimedDueToSubgraphDenylist(
145+
address indexed indexer,
146+
address indexed allocationID,
147+
bytes32 indexed subgraphDeploymentID,
148+
uint256 amount
149+
);
150+
111151
// -- Modifiers --
112152

113153
/**
@@ -264,6 +304,32 @@ contract RewardsManager is RewardsManagerV6Storage, GraphUpgradeable, IERC165, I
264304
}
265305
}
266306

307+
/**
308+
* @inheritdoc IRewardsManager
309+
* @dev Set to zero address to disable eligibility reclaim functionality
310+
*/
311+
function setIndexerEligibilityReclaimAddress(address newReclaimAddress) external override onlyGovernor {
312+
address oldReclaimAddress = indexerEligibilityReclaimAddress;
313+
314+
if (oldReclaimAddress != newReclaimAddress) {
315+
indexerEligibilityReclaimAddress = newReclaimAddress;
316+
emit IndexerEligibilityReclaimAddressSet(oldReclaimAddress, newReclaimAddress);
317+
}
318+
}
319+
320+
/**
321+
* @inheritdoc IRewardsManager
322+
* @dev Set to zero address to disable subgraph reclaim functionality
323+
*/
324+
function setSubgraphDeniedReclaimAddress(address newReclaimAddress) external override onlyGovernor {
325+
address oldReclaimAddress = subgraphDeniedReclaimAddress;
326+
327+
if (oldReclaimAddress != newReclaimAddress) {
328+
subgraphDeniedReclaimAddress = newReclaimAddress;
329+
emit SubgraphDeniedReclaimAddressSet(oldReclaimAddress, newReclaimAddress);
330+
}
331+
}
332+
267333
// -- Denylist --
268334

269335
/**
@@ -494,6 +560,60 @@ contract RewardsManager is RewardsManagerV6Storage, GraphUpgradeable, IERC165, I
494560
return newAccrued.mul(_tokens).div(FIXED_POINT_SCALING_FACTOR);
495561
}
496562

563+
/**
564+
* @notice Checks for and handles denial and reclaim of rewards due to subgraph deny list
565+
* @dev If denied, emits RewardsDenied event and mints to reclaim address if configured
566+
* @param indexer Address of the indexer
567+
* @param allocationID Address of the allocation
568+
* @param subgraphDeploymentID Subgraph deployment ID
569+
* @param rewards Amount of rewards that would be distributed
570+
* @return True if rewards are denied, false otherwise
571+
*/
572+
function _rewardsDeniedDueToSubgraphDenyList(
573+
address indexer,
574+
address allocationID,
575+
bytes32 subgraphDeploymentID,
576+
uint256 rewards
577+
) private returns (bool) {
578+
if (isDenied(subgraphDeploymentID)) {
579+
emit RewardsDenied(indexer, allocationID);
580+
581+
// If a reclaim address is set, mint the denied rewards there
582+
if (0 < rewards && subgraphDeniedReclaimAddress != address(0)) {
583+
graphToken().mint(subgraphDeniedReclaimAddress, rewards);
584+
emit RewardsReclaimedDueToSubgraphDenylist(indexer, allocationID, subgraphDeploymentID, rewards);
585+
}
586+
return true;
587+
}
588+
return false;
589+
}
590+
591+
/**
592+
* @notice Checks for and handles denial and reclaim of rewards due to indexer eligibility
593+
* @dev If denied, emits RewardsDeniedDueToEligibility event and mints to reclaim address if configured
594+
* @param indexer Address of the indexer
595+
* @param allocationID Address of the allocation
596+
* @param rewards Amount of rewards that would be distributed
597+
* @return True if rewards are denied, false otherwise
598+
*/
599+
function _rewardsDeniedDueToIndexerEligibility(
600+
address indexer,
601+
address allocationID,
602+
uint256 rewards
603+
) private returns (bool) {
604+
if (address(rewardsEligibilityOracle) != address(0) && !rewardsEligibilityOracle.isEligible(indexer)) {
605+
emit RewardsDeniedDueToEligibility(indexer, allocationID, rewards);
606+
607+
// If a reclaim address is set, mint the denied rewards there
608+
if (0 < rewards && indexerEligibilityReclaimAddress != address(0)) {
609+
graphToken().mint(indexerEligibilityReclaimAddress, rewards);
610+
emit RewardsReclaimedDueToIndexerEligibility(indexer, allocationID, rewards);
611+
}
612+
return true;
613+
}
614+
return false;
615+
}
616+
497617
/**
498618
* @inheritdoc IRewardsManager
499619
* @dev This function can only be called by an authorized rewards issuer which are
@@ -518,31 +638,24 @@ contract RewardsManager is RewardsManagerV6Storage, GraphUpgradeable, IERC165, I
518638

519639
uint256 updatedAccRewardsPerAllocatedToken = onSubgraphAllocationUpdate(subgraphDeploymentID);
520640

521-
// Do not do rewards on denied subgraph deployments ID
522-
if (isDenied(subgraphDeploymentID)) {
523-
emit RewardsDenied(indexer, _allocationID);
524-
return 0;
525-
}
526-
527641
uint256 rewards = 0;
528642
if (isActive) {
529643
// Calculate rewards accrued by this allocation
530644
rewards = accRewardsPending.add(
531645
_calcRewards(tokens, accRewardsPerAllocatedToken, updatedAccRewardsPerAllocatedToken)
532646
);
647+
}
533648

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-
}
649+
if (_rewardsDeniedDueToSubgraphDenyList(indexer, _allocationID, subgraphDeploymentID, rewards)) return 0;
539650

540-
if (rewards > 0) {
541-
// Mint directly to rewards issuer for the reward amount
542-
// The rewards issuer contract will do bookkeeping of the reward and
543-
// assign in proportion to each stakeholder incentive
544-
graphToken().mint(rewardsIssuer, rewards);
545-
}
651+
if (_rewardsDeniedDueToIndexerEligibility(indexer, _allocationID, rewards)) return 0;
652+
653+
// Mint rewards to the rewards issuer
654+
if (rewards > 0) {
655+
// Mint directly to rewards issuer for the reward amount
656+
// The rewards issuer contract will do bookkeeping of the reward and
657+
// assign in proportion to each stakeholder incentive
658+
graphToken().mint(rewardsIssuer, rewards);
546659
}
547660

548661
emit HorizonRewardsAssigned(indexer, _allocationID, rewards);

packages/contracts/contracts/rewards/RewardsManagerStorage.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,15 @@ contract RewardsManagerV5Storage is RewardsManagerV4Storage {
8383
* @title RewardsManagerV6Storage
8484
* @author Edge & Node
8585
* @notice Storage layout for RewardsManager V6
86-
* Includes support for Rewards Eligibility Oracle and Issuance Allocator.
86+
* Includes support for Rewards Eligibility Oracle, Issuance Allocator, and reclaim addresses.
8787
*/
8888
contract RewardsManagerV6Storage is RewardsManagerV5Storage {
8989
/// @notice Address of the rewards eligibility oracle contract
9090
IRewardsEligibility public rewardsEligibilityOracle;
9191
/// @notice Address of the issuance allocator
9292
IIssuanceAllocationDistribution public issuanceAllocator;
93+
/// @notice Address to receive tokens denied due to indexer eligibility checks, set to zero to disable
94+
address public indexerEligibilityReclaimAddress;
95+
/// @notice Address to receive tokens denied due to subgraph denylist, set to zero to disable
96+
address public subgraphDeniedReclaimAddress;
9397
}

packages/contracts/test/tests/unit/rewards/rewards-interface.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('RewardsManager interfaces', () => {
5757
})
5858

5959
it('IRewardsManager should have stable interface ID', () => {
60-
expect(IRewardsManager__factory.interfaceId).to.equal('0xa31d8306')
60+
expect(IRewardsManager__factory.interfaceId).to.equal('0x731e44f0')
6161
})
6262
})
6363

0 commit comments

Comments
 (0)