Skip to content

Commit aac9682

Browse files
HACK: partial AllocationManager to lib - 22.521
1 parent 5c86317 commit aac9682

File tree

2 files changed

+313
-92
lines changed

2 files changed

+313
-92
lines changed

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

Lines changed: 194 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
pragma solidity 0.8.27;
33

44
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
5-
import { IHorizonStaking } from "@graphprotocol/horizon/contracts/interfaces/IHorizonStaking.sol";
5+
import { IEpochManager } from "@graphprotocol/contracts/contracts/epochs/IEpochManager.sol";
6+
import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol";
67
import { IRewardsManager } from "@graphprotocol/contracts/contracts/rewards/IRewardsManager.sol";
8+
import { TokenUtils } from "@graphprotocol/contracts/contracts/utils/TokenUtils.sol";
9+
import { IHorizonStakingTypes } from "@graphprotocol/horizon/contracts/interfaces/internal/IHorizonStakingTypes.sol";
10+
import { IHorizonStaking } from "@graphprotocol/horizon/contracts/interfaces/IHorizonStaking.sol";
11+
import { IGraphPayments } from "@graphprotocol/horizon/contracts/interfaces/IGraphPayments.sol";
712
import { ProvisionTracker } from "@graphprotocol/horizon/contracts/data-service/libraries/ProvisionTracker.sol";
13+
import { PPMMath } from "@graphprotocol/horizon/contracts/libraries/PPMMath.sol";
814

915
import { Allocation } from "../libraries/Allocation.sol";
1016
import { LegacyAllocation } from "../libraries/LegacyAllocation.sol";
@@ -13,11 +19,10 @@ import { AllocationManager } from "../utilities/AllocationManager.sol";
1319
library AllocationManagerLib {
1420
using ProvisionTracker for mapping(address => uint256);
1521
using Allocation for mapping(address => Allocation.State);
22+
using Allocation for Allocation.State;
1623
using LegacyAllocation for mapping(address => LegacyAllocation.State);
17-
18-
///@dev EIP712 typehash for allocation id proof
19-
bytes32 private constant EIP712_ALLOCATION_ID_PROOF_TYPEHASH =
20-
keccak256("AllocationIdProof(address indexer,address allocationId)");
24+
using PPMMath for uint256;
25+
using TokenUtils for IGraphToken;
2126

2227
struct AllocateParams {
2328
uint256 currentEpoch;
@@ -32,6 +37,23 @@ library AllocationManagerLib {
3237
uint32 _delegationRatio;
3338
}
3439

40+
struct PresentParams {
41+
uint256 maxPOIStaleness;
42+
IEpochManager graphEpochManager;
43+
IHorizonStaking graphStaking;
44+
IRewardsManager graphRewardsManager;
45+
IGraphToken graphToken;
46+
address _allocationId;
47+
bytes32 _poi;
48+
bytes _poiMetadata;
49+
uint32 _delegationRatio;
50+
address _paymentsDestination;
51+
}
52+
53+
///@dev EIP712 typehash for allocation id proof
54+
bytes32 private constant EIP712_ALLOCATION_ID_PROOF_TYPEHASH =
55+
keccak256("AllocationIdProof(address indexer,address allocationId)");
56+
3557
/**
3658
* @notice Create an allocation
3759
* @dev The `_allocationProof` is a 65-bytes Ethereum signed message of `keccak256(indexerAddress,allocationId)`
@@ -85,6 +107,173 @@ library AllocationManagerLib {
85107
);
86108
}
87109

110+
function presentPOI(
111+
mapping(address allocationId => Allocation.State allocation) storage _allocations,
112+
mapping(address indexer => uint256 tokens) storage allocationProvisionTracker,
113+
mapping(bytes32 subgraphDeploymentId => uint256 tokens) storage _subgraphAllocatedTokens,
114+
PresentParams memory params
115+
) external returns (uint256) {
116+
Allocation.State memory allocation = _allocations.get(params._allocationId);
117+
require(allocation.isOpen(), AllocationManager.AllocationManagerAllocationClosed(params._allocationId));
118+
119+
// Mint indexing rewards if all conditions are met
120+
uint256 tokensRewards = (!allocation.isStale(params.maxPOIStaleness) &&
121+
!allocation.isAltruistic() &&
122+
params._poi != bytes32(0)) && params.graphEpochManager.currentEpoch() > allocation.createdAtEpoch
123+
? params.graphRewardsManager.takeRewards(params._allocationId)
124+
: 0;
125+
126+
// ... but we still take a snapshot to ensure the rewards are not accumulated for the next valid POI
127+
_allocations.snapshotRewards(
128+
params._allocationId,
129+
params.graphRewardsManager.onSubgraphAllocationUpdate(allocation.subgraphDeploymentId)
130+
);
131+
_allocations.presentPOI(params._allocationId);
132+
133+
// Any pending rewards should have been collected now
134+
_allocations.clearPendingRewards(params._allocationId);
135+
136+
uint256 tokensIndexerRewards = 0;
137+
uint256 tokensDelegationRewards = 0;
138+
if (tokensRewards != 0) {
139+
// Distribute rewards to delegators
140+
uint256 delegatorCut = params.graphStaking.getDelegationFeeCut(
141+
allocation.indexer,
142+
address(this),
143+
IGraphPayments.PaymentTypes.IndexingRewards
144+
);
145+
IHorizonStakingTypes.DelegationPool memory delegationPool = params.graphStaking.getDelegationPool(
146+
allocation.indexer,
147+
address(this)
148+
);
149+
// If delegation pool has no shares then we don't need to distribute rewards to delegators
150+
tokensDelegationRewards = delegationPool.shares > 0 ? tokensRewards.mulPPM(delegatorCut) : 0;
151+
if (tokensDelegationRewards > 0) {
152+
params.graphToken.approve(address(params.graphStaking), tokensDelegationRewards);
153+
params.graphStaking.addToDelegationPool(allocation.indexer, address(this), tokensDelegationRewards);
154+
}
155+
156+
// Distribute rewards to indexer
157+
tokensIndexerRewards = tokensRewards - tokensDelegationRewards;
158+
if (tokensIndexerRewards > 0) {
159+
if (params._paymentsDestination == address(0)) {
160+
params.graphToken.approve(address(params.graphStaking), tokensIndexerRewards);
161+
params.graphStaking.stakeToProvision(allocation.indexer, address(this), tokensIndexerRewards);
162+
} else {
163+
params.graphToken.pushTokens(params._paymentsDestination, tokensIndexerRewards);
164+
}
165+
}
166+
}
167+
168+
emit AllocationManager.IndexingRewardsCollected(
169+
allocation.indexer,
170+
params._allocationId,
171+
allocation.subgraphDeploymentId,
172+
tokensRewards,
173+
tokensIndexerRewards,
174+
tokensDelegationRewards,
175+
params._poi,
176+
params._poiMetadata,
177+
params.graphEpochManager.currentEpoch()
178+
);
179+
180+
// Check if the indexer is over-allocated and force close the allocation if necessary
181+
if (
182+
_isOverAllocated(
183+
allocationProvisionTracker,
184+
params.graphStaking,
185+
allocation.indexer,
186+
params._delegationRatio
187+
)
188+
) {
189+
_closeAllocation(
190+
_allocations,
191+
allocationProvisionTracker,
192+
_subgraphAllocatedTokens,
193+
params.graphRewardsManager,
194+
params._allocationId,
195+
true
196+
);
197+
}
198+
199+
return tokensRewards;
200+
}
201+
202+
function closeAllocation(
203+
mapping(address allocationId => Allocation.State allocation) storage _allocations,
204+
mapping(address indexer => uint256 tokens) storage allocationProvisionTracker,
205+
mapping(bytes32 subgraphDeploymentId => uint256 tokens) storage _subgraphAllocatedTokens,
206+
IRewardsManager graphRewardsManager,
207+
address _allocationId,
208+
bool _forceClosed
209+
) external {
210+
_closeAllocation(
211+
_allocations,
212+
allocationProvisionTracker,
213+
_subgraphAllocatedTokens,
214+
graphRewardsManager,
215+
_allocationId,
216+
_forceClosed
217+
);
218+
}
219+
220+
/**
221+
* @notice Checks if an allocation is over-allocated
222+
* @param _indexer The address of the indexer
223+
* @param _delegationRatio The delegation ratio to consider when locking tokens
224+
* @return True if the allocation is over-allocated, false otherwise
225+
*/
226+
function isOverAllocated(
227+
mapping(address indexer => uint256 tokens) storage allocationProvisionTracker,
228+
IHorizonStaking graphStaking,
229+
address _indexer,
230+
uint32 _delegationRatio
231+
) external view returns (bool) {
232+
return _isOverAllocated(allocationProvisionTracker, graphStaking, _indexer, _delegationRatio);
233+
}
234+
235+
function _closeAllocation(
236+
mapping(address allocationId => Allocation.State allocation) storage _allocations,
237+
mapping(address indexer => uint256 tokens) storage allocationProvisionTracker,
238+
mapping(bytes32 subgraphDeploymentId => uint256 tokens) storage _subgraphAllocatedTokens,
239+
IRewardsManager graphRewardsManager,
240+
address _allocationId,
241+
bool _forceClosed
242+
) private {
243+
Allocation.State memory allocation = _allocations.get(_allocationId);
244+
245+
// Take rewards snapshot to prevent other allos from counting tokens from this allo
246+
_allocations.snapshotRewards(
247+
_allocationId,
248+
graphRewardsManager.onSubgraphAllocationUpdate(allocation.subgraphDeploymentId)
249+
);
250+
251+
_allocations.close(_allocationId);
252+
allocationProvisionTracker.release(allocation.indexer, allocation.tokens);
253+
254+
// Update total allocated tokens for the subgraph deployment
255+
_subgraphAllocatedTokens[allocation.subgraphDeploymentId] =
256+
_subgraphAllocatedTokens[allocation.subgraphDeploymentId] -
257+
allocation.tokens;
258+
259+
emit AllocationManager.AllocationClosed(
260+
allocation.indexer,
261+
_allocationId,
262+
allocation.subgraphDeploymentId,
263+
allocation.tokens,
264+
_forceClosed
265+
);
266+
}
267+
268+
function _isOverAllocated(
269+
mapping(address indexer => uint256 tokens) storage allocationProvisionTracker,
270+
IHorizonStaking graphStaking,
271+
address _indexer,
272+
uint32 _delegationRatio
273+
) private view returns (bool) {
274+
return !allocationProvisionTracker.check(graphStaking, _indexer, _delegationRatio);
275+
}
276+
88277
/**
89278
* @notice Verifies ownership of an allocation id by verifying an EIP712 allocation proof
90279
* @dev Requirements:

0 commit comments

Comments
 (0)