Skip to content

Commit

Permalink
fix: round down tokens thawing when slashing (TRST-H04)
Browse files Browse the repository at this point in the history
  • Loading branch information
Maikol committed Dec 2, 2024
1 parent d02f410 commit 167055a
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
7 changes: 4 additions & 3 deletions packages/horizon/contracts/staking/HorizonStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
_graphToken().burnTokens(providerTokensSlashed - tokensVerifier);

// Provision accounting
// TODO check for rounding issues
uint256 provisionFractionSlashed = (providerTokensSlashed * FIXED_POINT_PRECISION) / prov.tokens;
uint256 provisionFractionSlashed = (providerTokensSlashed * FIXED_POINT_PRECISION + prov.tokens - 1) /
prov.tokens;
prov.tokensThawing =
(prov.tokensThawing * (FIXED_POINT_PRECISION - provisionFractionSlashed)) /
(FIXED_POINT_PRECISION);
Expand Down Expand Up @@ -497,7 +497,8 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
_graphToken().burnTokens(tokensToSlash);

// Delegation pool accounting
uint256 delegationFractionSlashed = (tokensToSlash * FIXED_POINT_PRECISION) / pool.tokens;
uint256 delegationFractionSlashed = (tokensToSlash * FIXED_POINT_PRECISION + pool.tokens - 1) /
pool.tokens;
pool.tokens = pool.tokens - tokensToSlash;
pool.tokensThawing =
(pool.tokensThawing * (FIXED_POINT_PRECISION - delegationFractionSlashed)) /
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest {
uint256 tokensSlashed = calcValues.providerTokensSlashed +
(isDelegationSlashingEnabled ? calcValues.delegationTokensSlashed : 0);
uint256 provisionThawingTokens = (before.provision.tokensThawing *
(1e18 - ((calcValues.providerTokensSlashed * 1e18) / before.provision.tokens))) / (1e18);
(1e18 - ((calcValues.providerTokensSlashed * 1e18 + before.provision.tokens - 1) / before.provision.tokens))) / (1e18);

// assert
assertEq(afterProvision.tokens + calcValues.providerTokensSlashed, before.provision.tokens);
Expand All @@ -1506,7 +1506,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest {
(before.provision.sharesThawing != 0 && afterProvision.sharesThawing == 0) ? before.provision.thawingNonce + 1 : before.provision.thawingNonce);
if (isDelegationSlashingEnabled) {
uint256 poolThawingTokens = (before.pool.tokensThawing *
(1e18 - ((calcValues.delegationTokensSlashed * 1e18) / before.pool.tokens))) / (1e18);
(1e18 - ((calcValues.delegationTokensSlashed * 1e18 + before.pool.tokens - 1) / before.pool.tokens))) / (1e18);
assertEq(afterPool.tokens + calcValues.delegationTokensSlashed, before.pool.tokens);
assertEq(afterPool.shares, before.pool.shares);
assertEq(afterPool.tokensThawing, poolThawingTokens);
Expand Down
42 changes: 42 additions & 0 deletions packages/horizon/test/staking/slash/slash.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,46 @@ contract HorizonStakingSlashTest is HorizonStakingTest {
vm.startPrank(subgraphDataServiceAddress);
_slash(users.indexer, subgraphDataServiceAddress, tokens + delegationTokens, 0);
}

function testSlash_RoundDown_TokensThawing_Provision() public useIndexer {
uint256 tokens = 1 ether + 1;
_useProvision(subgraphDataServiceAddress, tokens, MAX_PPM, MAX_THAWING_PERIOD);

_thaw(users.indexer, subgraphDataServiceAddress, tokens);

resetPrank(subgraphDataServiceAddress);
_slash(users.indexer, subgraphDataServiceAddress, 1, 0);

resetPrank(users.indexer);
Provision memory provision = staking.getProvision(users.indexer, subgraphDataServiceAddress);
assertEq(provision.tokens, tokens - 1);
// Tokens thawing should be rounded down
assertEq(provision.tokensThawing, tokens - 2);
}

function testSlash_RoundDown_TokensThawing_Delegation(
uint256 tokens
) public useIndexer useProvision(tokens, MAX_PPM, 0) useDelegationSlashing {
resetPrank(users.delegator);
uint256 delegationTokens = 1 ether + 1;
_delegate(users.indexer, subgraphDataServiceAddress, delegationTokens, 0);

DelegationInternal memory delegation = _getStorage_Delegation(
users.indexer,
subgraphDataServiceAddress,
users.delegator,
false
);
_undelegate(users.indexer, subgraphDataServiceAddress, delegation.shares);

resetPrank(subgraphDataServiceAddress);
// Slash 1 token from delegation
_slash(users.indexer, subgraphDataServiceAddress, tokens + 1, 0);

resetPrank(users.delegator);
DelegationPool memory pool = staking.getDelegationPool(users.indexer, subgraphDataServiceAddress);
assertEq(pool.tokens, delegationTokens - 1);
// Tokens thawing should be rounded down
assertEq(pool.tokensThawing, delegationTokens - 2);
}
}

0 comments on commit 167055a

Please sign in to comment.