Skip to content

Commit d0060b1

Browse files
authored
Merge pull request #1103 from graphprotocol/tmigone/allo-min-duration
2 parents 51976ec + f6923b9 commit d0060b1

File tree

15 files changed

+105
-100
lines changed

15 files changed

+105
-100
lines changed

packages/contracts/contracts/rewards/IRewardsIssuer.sol

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,4 @@ interface IRewardsIssuer {
3131
* @return Total tokens allocated to subgraph
3232
*/
3333
function getSubgraphAllocatedTokens(bytes32 _subgraphDeploymentId) external view returns (uint256);
34-
35-
/**
36-
* @notice Whether or not an allocation is active (i.e open)
37-
* @param _allocationId Allocation Id
38-
* @return Whether or not the allocation is active
39-
*/
40-
function isActiveAllocation(address _allocationId) external view returns (bool);
4134
}

packages/contracts/contracts/rewards/IRewardsManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ interface IRewardsManager {
3939

4040
function getAccRewardsPerAllocatedToken(bytes32 _subgraphDeploymentID) external view returns (uint256, uint256);
4141

42-
function getRewards(address _allocationID) external view returns (uint256);
42+
function getRewards(address _rewardsIssuer, address _allocationID) external view returns (uint256);
4343

4444
function calcRewards(uint256 _tokens, uint256 _accRewardsPerAllocatedToken) external pure returns (uint256);
4545

packages/contracts/contracts/rewards/RewardsManager.sol

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -322,32 +322,19 @@ contract RewardsManager is RewardsManagerV5Storage, GraphUpgradeable, IRewardsMa
322322
* @param _allocationID Allocation
323323
* @return Rewards amount for an allocation
324324
*/
325-
function getRewards(address _allocationID) external view override returns (uint256) {
326-
address rewardsIssuer = address(0);
327-
328-
// Check both the legacy and new allocations
329-
address[2] memory rewardsIssuers = [address(staking()), address(subgraphService)];
330-
for (uint256 i = 0; i < rewardsIssuers.length; i++) {
331-
if (rewardsIssuers[i] != address(0)) {
332-
if (IRewardsIssuer(rewardsIssuers[i]).isActiveAllocation(_allocationID)) {
333-
rewardsIssuer = address(rewardsIssuers[i]);
334-
break;
335-
}
336-
}
337-
}
338-
339-
// Bail if allo does not exist
340-
if (rewardsIssuer == address(0)) {
341-
return 0;
342-
}
325+
function getRewards(address _rewardsIssuer, address _allocationID) external view override returns (uint256) {
326+
require(
327+
_rewardsIssuer == address(staking()) || _rewardsIssuer == address(subgraphService),
328+
"Not a rewards issuer"
329+
);
343330

344331
(
345332
,
346333
bytes32 subgraphDeploymentId,
347334
uint256 tokens,
348335
uint256 alloAccRewardsPerAllocatedToken,
349336
uint256 accRewardsPending
350-
) = IRewardsIssuer(rewardsIssuer).getAllocationData(_allocationID);
337+
) = IRewardsIssuer(_rewardsIssuer).getAllocationData(_allocationID);
351338

352339
(uint256 accRewardsPerAllocatedToken, ) = getAccRewardsPerAllocatedToken(subgraphDeploymentId);
353340
return

packages/contracts/test/unit/rewards/rewards.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ describe('Rewards', () => {
466466
await helpers.mine(ISSUANCE_RATE_PERIODS)
467467

468468
// Rewards
469-
const contractRewards = await rewardsManager.getRewards(allocationID1)
469+
const contractRewards = await rewardsManager.getRewards(staking.address, allocationID1)
470470

471471
// We trust using this function in the test because we tested it
472472
// standalone in a previous test
@@ -504,12 +504,12 @@ describe('Rewards', () => {
504504
await staking.connect(indexer1).closeAllocation(allocationID1, randomHexBytes())
505505

506506
// Rewards
507-
const contractRewards = await rewardsManager.getRewards(allocationID1)
507+
const contractRewards = await rewardsManager.getRewards(staking.address, allocationID1)
508508
expect(contractRewards).eq(BigNumber.from(0))
509509
})
510510
it('rewards should be zero if the allocation does not exist', async function () {
511511
// Rewards
512-
const contractRewards = await rewardsManager.getRewards(allocationIDNull)
512+
const contractRewards = await rewardsManager.getRewards(staking.address, allocationIDNull)
513513
expect(contractRewards).eq(BigNumber.from(0))
514514
})
515515
})
@@ -1026,7 +1026,7 @@ describe('Rewards', () => {
10261026
await staking.connect(assetHolder).collect(tokensToCollect, allocationID1)
10271027

10281028
// check rewards diff
1029-
await rewardsManager.getRewards(allocationID1).then(formatGRT)
1029+
await rewardsManager.getRewards(staking.address, allocationID1).then(formatGRT)
10301030

10311031
await helpers.mine()
10321032
const accrual = await getRewardsAccrual(subgraphs)

packages/horizon/contracts/staking/HorizonStakingExtension.sol

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,6 @@ contract HorizonStakingExtension is HorizonStakingBase, IHorizonStakingExtension
274274
return __DEPRECATED_subgraphAllocations[subgraphDeploymentID];
275275
}
276276

277-
/**
278-
* @notice Return true if allocation is active.
279-
* @param allocationID Allocation identifier
280-
* @return True if allocation is active
281-
*/
282-
function isActiveAllocation(address allocationID) external view override returns (bool) {
283-
return _getAllocationState(allocationID) == AllocationState.Active;
284-
}
285-
286277
/**
287278
* @notice Get the total amount of tokens staked by the indexer.
288279
* @param indexer Address of the indexer

packages/subgraph-service/contracts/SubgraphService.sol

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -449,18 +449,6 @@ contract SubgraphService is
449449
return _subgraphAllocatedTokens[subgraphDeploymentId];
450450
}
451451

452-
/**
453-
* @notice Check if an allocation is open
454-
* @dev Implements {IRewardsIssuer.isAllocationActive}
455-
* @dev To be used by the {RewardsManager}.
456-
*
457-
* @param allocationId The allocation Id
458-
* @return Wether or not the allocation is active
459-
*/
460-
function isActiveAllocation(address allocationId) external view override returns (bool) {
461-
return _allocations[allocationId].isOpen();
462-
}
463-
464452
/**
465453
* @notice See {ISubgraphService.getLegacyAllocation}
466454
*/
@@ -475,13 +463,6 @@ contract SubgraphService is
475463
return _encodeAllocationProof(indexer, allocationId);
476464
}
477465

478-
/**
479-
* @notice See {ISubgraphService.isStaleAllocation}
480-
*/
481-
function isStaleAllocation(address allocationId) external view override returns (bool) {
482-
return _allocations.get(allocationId).isStale(maxPOIStaleness);
483-
}
484-
485466
/**
486467
* @notice See {ISubgraphService.isOverAllocated}
487468
*/

packages/subgraph-service/contracts/interfaces/ISubgraphService.sol

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,6 @@ interface ISubgraphService is IDataServiceFees {
241241
*/
242242
function encodeAllocationProof(address indexer, address allocationId) external view returns (bytes32);
243243

244-
/**
245-
* @notice Checks if an allocation is stale
246-
* @param allocationId The id of the allocation
247-
* @return True if the allocation is stale, false otherwise
248-
*/
249-
function isStaleAllocation(address allocationId) external view returns (bool);
250-
251244
/**
252245
* @notice Checks if an indexer is over-allocated
253246
* @param allocationId The id of the allocation

packages/subgraph-service/contracts/libraries/Allocation.sol

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ library Allocation {
3030
uint256 accRewardsPerAllocatedToken;
3131
// Accumulated rewards that are pending to be claimed due allocation resize
3232
uint256 accRewardsPending;
33+
// Epoch when the allocation was created
34+
uint256 createdAtEpoch;
3335
}
3436

3537
/**
@@ -68,7 +70,8 @@ library Allocation {
6870
address allocationId,
6971
bytes32 subgraphDeploymentId,
7072
uint256 tokens,
71-
uint256 accRewardsPerAllocatedToken
73+
uint256 accRewardsPerAllocatedToken,
74+
uint256 createdAtEpoch
7275
) internal returns (State memory) {
7376
require(!self[allocationId].exists(), AllocationAlreadyExists(allocationId));
7477

@@ -80,7 +83,8 @@ library Allocation {
8083
closedAt: 0,
8184
lastPOIPresentedAt: 0,
8285
accRewardsPerAllocatedToken: accRewardsPerAllocatedToken,
83-
accRewardsPending: 0
86+
accRewardsPending: 0,
87+
createdAtEpoch: createdAtEpoch
8488
});
8589

8690
self[allocationId] = allocation;

packages/subgraph-service/contracts/utilities/AllocationManager.sol

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@ abstract contract AllocationManager is EIP712Upgradeable, GraphDirectory, Alloca
4040
* @param allocationId The id of the allocation
4141
* @param subgraphDeploymentId The id of the subgraph deployment
4242
* @param tokens The amount of tokens allocated
43+
* @param currentEpoch The current epoch
4344
*/
4445
event AllocationCreated(
4546
address indexed indexer,
4647
address indexed allocationId,
4748
bytes32 indexed subgraphDeploymentId,
48-
uint256 tokens
49+
uint256 tokens,
50+
uint256 currentEpoch
4951
);
5052

5153
/**
@@ -157,17 +159,14 @@ abstract contract AllocationManager is EIP712Upgradeable, GraphDirectory, Alloca
157159
// solhint-disable-next-line func-name-mixedcase
158160
function __AllocationManager_init(string memory _name, string memory _version) internal onlyInitializing {
159161
__EIP712_init(_name, _version);
160-
__AllocationManager_init_unchained(_name, _version);
162+
__AllocationManager_init_unchained();
161163
}
162164

163165
/**
164166
* @notice Initializes the contract
165167
*/
166168
// solhint-disable-next-line func-name-mixedcase
167-
function __AllocationManager_init_unchained(
168-
string memory _name,
169-
string memory _version
170-
) internal onlyInitializing {}
169+
function __AllocationManager_init_unchained() internal onlyInitializing {}
171170

172171
/**
173172
* @notice Imports a legacy allocation id into the subgraph service
@@ -213,12 +212,15 @@ abstract contract AllocationManager is EIP712Upgradeable, GraphDirectory, Alloca
213212
// Ensure allocation id is not reused
214213
// need to check both subgraph service (on allocations.create()) and legacy allocations
215214
_legacyAllocations.revertIfExists(_graphStaking(), _allocationId);
215+
216+
uint256 currentEpoch = _graphEpochManager().currentEpoch();
216217
Allocation.State memory allocation = _allocations.create(
217218
_indexer,
218219
_allocationId,
219220
_subgraphDeploymentId,
220221
_tokens,
221-
_graphRewardsManager().onSubgraphAllocationUpdate(_subgraphDeploymentId)
222+
_graphRewardsManager().onSubgraphAllocationUpdate(_subgraphDeploymentId),
223+
currentEpoch
222224
);
223225

224226
// Check that the indexer has enough tokens available
@@ -230,23 +232,28 @@ abstract contract AllocationManager is EIP712Upgradeable, GraphDirectory, Alloca
230232
_subgraphAllocatedTokens[allocation.subgraphDeploymentId] +
231233
allocation.tokens;
232234

233-
emit AllocationCreated(_indexer, _allocationId, _subgraphDeploymentId, allocation.tokens);
235+
emit AllocationCreated(_indexer, _allocationId, _subgraphDeploymentId, allocation.tokens, currentEpoch);
234236
return allocation;
235237
}
236238

237239
/**
238240
* @notice Present a POI to collect indexing rewards for an allocation
239241
* This function will mint indexing rewards using the {RewardsManager} and distribute them to the indexer and delegators.
240242
*
241-
* To qualify for indexing rewards:
243+
* Conditions to qualify for indexing rewards:
242244
* - POI must be non-zero
243245
* - POI must not be stale, i.e: older than `maxPOIStaleness`
244246
* - allocation must not be altruistic (allocated tokens = 0)
247+
* - allocation must be open for at least one epoch
245248
*
246249
* Note that indexers are required to periodically (at most every `maxPOIStaleness`) present POIs to collect rewards.
247250
* Rewards will not be issued to stale POIs, which means that indexers are advised to present a zero POI if they are
248251
* unable to present a valid one to prevent being locked out of future rewards.
249252
*
253+
* Note on allocation duration restriction: this is required to ensure that non protocol chains have a valid block number for
254+
* which to calculate POIs. EBO posts once per epoch typically at each epoch change, so we restrict rewards to allocations
255+
* that have gone through at least one epoch change.
256+
*
250257
* Emits a {IndexingRewardsCollected} event.
251258
*
252259
* @param _allocationId The id of the allocation to collect rewards for
@@ -260,10 +267,12 @@ abstract contract AllocationManager is EIP712Upgradeable, GraphDirectory, Alloca
260267
Allocation.State memory allocation = _allocations.get(_allocationId);
261268
require(allocation.isOpen(), AllocationManagerAllocationClosed(_allocationId));
262269

270+
uint256 currentEpoch = _graphEpochManager().currentEpoch();
271+
263272
// Mint indexing rewards if all conditions are met
264273
uint256 tokensRewards = (!allocation.isStale(maxPOIStaleness) &&
265274
!allocation.isAltruistic() &&
266-
_poi != bytes32(0))
275+
_poi != bytes32(0)) && currentEpoch > allocation.createdAtEpoch
267276
? _graphRewardsManager().takeRewards(_allocationId)
268277
: 0;
269278

@@ -318,7 +327,7 @@ abstract contract AllocationManager is EIP712Upgradeable, GraphDirectory, Alloca
318327
tokensIndexerRewards,
319328
tokensDelegationRewards,
320329
_poi,
321-
_graphEpochManager().currentEpoch()
330+
currentEpoch
322331
);
323332

324333
// Check if the indexer is over-allocated and close the allocation if necessary

packages/subgraph-service/hardhat.config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ if (process.env.BUILD_RUN !== 'true') {
1717

1818
const config: HardhatUserConfig = {
1919
...hardhatBaseConfig,
20+
solidity: {
21+
version: '0.8.27',
22+
settings: {
23+
optimizer: {
24+
enabled: true,
25+
runs: 50,
26+
},
27+
},
28+
},
2029
graph: {
2130
deployments: {
2231
...hardhatBaseConfig.graph?.deployments,

packages/subgraph-service/test/mocks/MockRewardsManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ contract MockRewardsManager is IRewardsManager {
6161

6262
function getAccRewardsPerAllocatedToken(bytes32) external view returns (uint256, uint256) {}
6363

64-
function getRewards(address) external view returns (uint256) {}
64+
function getRewards(address,address) external view returns (uint256) {}
6565

6666
function calcRewards(uint256, uint256) external pure returns (uint256) {}
6767

0 commit comments

Comments
 (0)