59904 sc high it s possible to decrease twice delegator stake in certain conditions
Submitted on Nov 16th 2025 at 20:50:22 UTC by @Paludo0x for Audit Comp | Vechain | Stargate Hayabusa
Report ID: #59904
Report Type: Smart Contract
Report severity: High
Target: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/tree/main/packages/contracts/contracts/Stargate.sol
Impacts:
Permanent freezing of funds
Theft of unclaimed yield
Description
Brief / Intro
A delegator can trigger two scheduled decreases of the validator’s cumulative delegators effective stake by first calling requestDelegationExit while the validator is ACTIVE and later calling unstake after the validator becomes EXITED.
Vulnerability Details
Updates of delegatorsEffectiveStake are handled through _updatePeriodEffectiveStake, which reads the current cumulative value for _period using upperLookup and then adds or subtracts the token’s current effective stake:
function _updatePeriodEffectiveStake(
StargateStorage storage $,
address _validator,
uint256 _tokenId,
uint32 _period,
bool _isIncrease
) private {
// calculate the effective stake
uint256 effectiveStake = _calculateEffectiveStake($, _tokenId);
// get the current effective stake
uint256 currentValue = $.delegatorsEffectiveStake[_validator].upperLookup(_period);
// calculate the updated effective stake
uint256 updatedValue = _isIncrease
? currentValue + effectiveStake
: currentValue - effectiveStake;
// push the updated effective stake
$.delegatorsEffectiveStake[_validator].push(_period, SafeCast.toUint224(updatedValue));
}There are two different paths which schedule a decrease of delegatorsEffectiveStake. These are represented below as steps.
Because there is no specific guard preventing both scheduling actions for the same token, both scheduled decreases may subtract the same token’s effective stake at different future periods.
This is the snippet of the faulty code in unstake():
Impact Details
The share formula used by _claimableRewardsForPeriod:
Consequences:
When the second decrease lands on a period where the cumulative already reflects the first decrease (zero in a single-delegator validator), the subtraction attempts cause an underflow and therefore revert inside
_updatePeriodEffectiveStake.When there are multiple delegators so the cumulative stays > 0, the double subtraction understates the denominator from that later period onward, inflating all other positions' shares.
Critical impact: Permanent freezing of funds — in pools where there is a sole delegator, the second scheduled decrease causes an underflow reverting _updatePeriodEffectiveStake. All flows that must apply this scheduled decrease will keep reverting, effectively freezing funds permanently.
Proof of Concept
Summary
Root cause: lack of guard to prevent scheduling the same token's effective stake to be decreased twice via two different code paths (requestDelegationExit while ACTIVE and unstake when EXITED/PENDING).
Consequences: underflow reverts when sole delegator -> permanent freeze; incorrect reward distribution when multiple delegators -> inflated shares for others.
Files referenced: Stargate.sol (target repository link above).
Was this helpful?