A critical flaw in Stargate._claimableDelegationPeriods allows users who have exited their delegations to continue claiming rewards indefinitely from periods that occur after their exit. Once a delegator calls requestDelegationExit and completes their exit period, they should no longer earn rewards. However, the contract's logic incorrectly computes the claimable period range for exited delegations, enabling them to claim from all future periods as long as their validator continues producing blocks. Each call to claimRewards siphons VTHO that should have been distributed exclusively to active delegators, creating a permanent reward drain.
Vulnerability Details
Background
Expected lifecycle:
1
Stake and delegate
User stakes VET → mints NFT.
2
Delegate
User delegates the NFT → VET locked in ProtocolStaker; rewards accrue period by period.
3
Request exit
User requests delegation exit → ProtocolStaker sets endPeriod for the delegation.
4
Exit completes
When the period completes, the delegation status becomes EXITED.
5
No new rewards expected
From this point, no new rewards should accrue; user can withdraw stake or leave the NFT idle.
Actual behavior
Because of how Stargate._claimableDelegationPeriods computes the next claim window, an EXITED delegation retains a moving claim range that advances with every new validator period. The contract continues to treat the exited delegator as eligible for rewards, so repeated calls to claimRewards siphon future earnings forever.
Root Cause
The bug lives in _claimableDelegationPeriods (lines ~880–927 of Stargate.sol). Relevant excerpt:
When the delegator first claims after exit:
nextClaimablePeriod equals the first unclaimed period (still ≤ endPeriod).
The endPeriod > nextClaimablePeriod branch executes, returning [nextClaimable, endPeriod].
claimRewards sets lastClaimedPeriod to endPeriod.
On the next call:
nextClaimablePeriod = endPeriod + 1.
The exit branch condition endPeriod > nextClaimablePeriod fails.
The fallback branch sees nextClaimablePeriod < currentValidatorPeriod (validator kept producing blocks).
It therefore returns (endPeriod + 1, completedPeriods) – periods entirely beyond endPeriod.
Since _claimableRewardsForPeriod and delegatorsEffectiveStake[validator] still reflect the old stake (no checkpoint subtraction until unstake or redelegation), the exited delegator receives a legitimate share of each future period’s rewards.
Why exit does not stop the leakage
_updatePeriodEffectiveStake(..., false) runs only when the delegator withdraws or redelegates; simply exiting does not reduce the validator’s effective stake history.
lastClaimedPeriod is updated after every claim but no flag signals that the delegation ended permanently.
The endPeriod > nextClaimablePeriod guard uses a strict inequality. After successfully claiming through the end period, the guard no longer triggers and the fallback logic treats the exited delegator as active.
Impact Details
Direct impact
Exited delegators can keep farming VTHO rewards indefinitely without restaking.
Honest active delegators see reduced rewards each period, proportional to the attacker’s historical effective stake.
Proof of Concept
View PoC test (Hardhat / TypeScript)
References
(Links to code or documentation can be added here if available.)