Skip to content

Commit 50d57e6

Browse files
committed
fix: ensure delegations are always slashable (OZ H-02)
Signed-off-by: Tomás Migone <[email protected]>
1 parent 0b66f7a commit 50d57e6

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

packages/subgraph-service/contracts/DisputeManager.sol

+5-4
Original file line numberDiff line numberDiff line change
@@ -675,17 +675,18 @@ contract DisputeManager is
675675
* @dev A few considerations:
676676
* - We include both indexer and delegators stake.
677677
* - Thawing stake is not excluded from the snapshot.
678-
* - Delegators stake is capped at the delegation ratio to prevent delegators from inflating the snapshot
679-
* to increase the indexer slash amount.
678+
*
679+
* Note that the snapshot can be inflated by delegators front-running the dispute creation with a delegation
680+
* to the indexer. Given the snapshot is a cap, the dispute outcome is uncertain and considering the cost of capital
681+
* and slashing risk, this is not a concern.
680682
* @param _indexer Indexer address
681683
* @param _indexerStake Indexer's stake
682684
* @return Total stake snapshot
683685
*/
684686
function _getStakeSnapshot(address _indexer, uint256 _indexerStake) private view returns (uint256) {
685687
ISubgraphService subgraphService_ = _getSubgraphService();
686688
uint256 delegatorsStake = _graphStaking().getDelegationPool(_indexer, address(subgraphService_)).tokens;
687-
uint256 delegatorsStakeMax = _indexerStake * uint256(subgraphService_.getDelegationRatio());
688-
uint256 stakeSnapshot = _indexerStake + MathUtils.min(delegatorsStake, delegatorsStakeMax);
689+
uint256 stakeSnapshot = _indexerStake + delegatorsStake;
689690
return stakeSnapshot;
690691
}
691692
}

packages/subgraph-service/test/disputeManager/disputes/indexing/create.t.sol

+24
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@ contract DisputeManagerIndexingCreateDisputeTest is DisputeManagerTest {
1616
_createIndexingDispute(allocationID, bytes32("POI1"));
1717
}
1818

19+
function test_Indexing_Create_Dispute_WithDelegation(uint256 tokens, uint256 delegationTokens) public useIndexer {
20+
vm.assume(tokens >= minimumProvisionTokens);
21+
vm.assume(tokens < 100_000_000 ether); // set a low cap to test overdelegation
22+
_createProvision(users.indexer, tokens, fishermanRewardPercentage, disputePeriod);
23+
_register(users.indexer, abi.encode("url", "geoHash", address(0)));
24+
bytes memory data = _createSubgraphAllocationData(
25+
users.indexer,
26+
subgraphDeployment,
27+
allocationIDPrivateKey,
28+
tokens
29+
);
30+
_startService(users.indexer, data);
31+
32+
uint256 delegationRatio = subgraphService.getDelegationRatio();
33+
delegationTokens = bound(delegationTokens, 1e18, tokens * delegationRatio * 2); // make sure we have overdelegation
34+
35+
resetPrank(users.delegator);
36+
token.approve(address(staking), delegationTokens);
37+
staking.delegate(users.indexer, address(subgraphService), delegationTokens, 0);
38+
39+
resetPrank(users.fisherman);
40+
_createIndexingDispute(allocationID, bytes32("POI1"));
41+
}
42+
1943
function test_Indexing_Create_Dispute_RevertWhen_SubgraphServiceNotSet(
2044
uint256 tokens
2145
) public useIndexer useAllocation(tokens) {

0 commit comments

Comments
 (0)