60241 sc medium permanent freezing of staked funds caused by accumulation with zero rewards
Submitted on Nov 20th 2025 at 10:17:47 UTC by @Paludo0x for Audit Comp | Vechain | Stargate Hayabusa
Report ID: #60241
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/tree/main/packages/contracts/contracts/Stargate.sol
Impacts:
Permanent freezing of funds
Description
Brief / Intro
A delegator's NFT in the Stargate protocol can become permanently locked under these conditions:
It accumulates more claimable periods than
maxClaimablePeriods.It receives zero rewards across those periods.
Because lastClaimedPeriod only advances when the claimable reward is greater than zero, users with consistently zero rewards are unable to reduce the claimable period window. Once the period span exceeds the maximum allowed, all calls to unstake() and delegate() revert with MaxClaimablePeriodsExceeded, resulting in a permanent freeze of the user's staked VET.
Vulnerability details (summary)
The root cause is the interaction between:
computation of claimable period window (
_claimableDelegationPeriods),the
maxClaimablePeriodsguard (_exceedsMaxClaimablePeriods),and how
lastClaimedPeriodis updated in_claimRewards.
key points:
_claimableDelegationPeriodscomputes a window fromlastClaimedPeriod + 1up to either the delegationendPeriodor the validator'scompletedPeriods.As the validator completes more periods,
lastClaimablePeriod(the window upper bound) can grow indefinitely for active delegations.The guard
_exceedsMaxClaimablePeriodschecks the window length and blocks operations when the window length >=maxClaimablePeriods._claimRewardsupdateslastClaimedPeriodonly if the computedclaimableAmountis > 0. IfclaimableAmount == 0, the function returns early without updatinglastClaimedPeriod.Integer division when computing per-period rewards can make a delegator's reward round to 0:
If rewards round to zero for many consecutive periods,
lastClaimedPeriodstays unchanged, the window grows, then becomes and remains larger thanmaxClaimablePeriods. Becauseunstake()and redelegation check this guard before calling_claimRewards, the delegator cannot advancelastClaimedPeriodand becomes permanently locked.
Example of relevant code snippets
Window computation (excerpt):
Max periods guard:
Claim rewards (excerpt):
Impact
Affected delegators:
Cannot claim non-zero rewards (there are none).
Cannot shrink the claimable period window.
Cannot unstake or redelegate because those operations revert before allowing
_claimRewardsto advance the cursor.
This results in permanently frozen VET for affected NFTs.
Severity stated: Critical in text (but reported severity: Medium).
Proof of Concept (PoC)
PoC code
The full PoC test provided in the report (TypeScript / Hardhat test) is included below:
Required changes (provided in report)
The report includes three required edits used to run the PoC. These are reproduced here verbatim.
References
Target repository: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/tree/main/packages/contracts/contracts/Stargate.sol
(Report includes PoC test and mock/hardhat changes above.)
If you want, I can:
produce a minimal patch suggestion (contract-side) to fix the issue (e.g., ensure
lastClaimedPeriodis advanced even when rewards are zero, but only up to a safe clamped bound), orconvert the PoC test into a smaller reproducer or a transaction sequence for on-chain verification.
Which would you prefer?
Was this helpful?