59564 sc high double calling updateperiodeffectivestake during the exit flow makes unstake revert trapping staked vet
Submitted on Nov 13th 2025 at 15:30:43 UTC by @niffylord for Audit Comp | Vechain | Stargate Hayabusa
Report ID: #59564
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
Description
Brief / Intro
If a delegator signals exit while their validator is still active and the validator subsequently exits before the delegator calls unstake, Stargate.sol subtracts the delegator’s effective stake twice. The second subtraction underflows, so unstake reverts forever and the user’s VET remains locked.
Vulnerability Details
requestDelegationExitimmediately reduces the validator checkpoint for the exiting token via_updatePeriodEffectiveStake(..., false)to ensure future rewards omit the delegator.【F:packages/contracts/contracts/Stargate.sol†L523-L569】Later,
unstakechecks the validator status. If it seesVALIDATOR_STATUS_EXITED, it runs_updatePeriodEffectiveStake(..., false)again, assuming the reduction has not yet happened.【F:packages/contracts/contracts/Stargate.sol†L260-L283】Because checkpoints store deltas, the second subtraction reuses the same
(validator, tokenId, period)entries. When the validator had little remaining stake, the subtraction underflows and Solidity panics (0x11), reverting the entire transaction. No retry can succeed because the same branch keeps triggering.
Impact Details
Any delegator whose validator exits between
requestDelegationExitandunstakeloses the ability to withdraw the principal VET;unstakereverts every time.Rewards also remain unclaimable because the contract burns the NFT only after a successful
unstake.Multiple users delegating to the same validator can be griefed as soon as that validator decides to exit, causing a protocol-wide denial of service on capital.
Chosen impact category: Permanent freezing of funds (Critical) — user-controlled VET becomes unreachable indefinitely.
Suggested Mitigations
Track whether
_updatePeriodEffectiveStakealready ran for the exiting delegation (e.g., store a boolean flag per token or delegation) and skip the second decrease inunstake.Alternatively, recompute the current checkpoint value in
unstakeand only subtract when the stored amount is greater than or equal to the token’s effective stake.Refactor the flow so validator status transitions trigger the checkpoint adjustment once, removing duplicate calls from user entry points.
References
Stargate.solrequestDelegationExit: first checkpoint decrease.【F:packages/contracts/contracts/Stargate.sol†L523-L569】Stargate.solunstake: second checkpoint decrease on exited validators.【F:packages/contracts/contracts/Stargate.sol†L260-L283】_updatePeriodEffectiveStake: raw subtraction without underflow guard.【F:packages/contracts/contracts/Stargate.sol†L993-L1012】Unit test reproducer:
Delegation.test.ts“should revert unstake after requesting exit if validator exits before unstake.”【F:packages/contracts/test/unit/Stargate/Delegation.test.ts†L205-L231】
Proof of Concept
Relevant test from packages/contracts/test/unit/Stargate/Delegation.test.ts:
Testing
Regression covered by
packages/contracts/test/unit/Stargate/Delegation.test.ts.To reproduce:
yarn contracts:test:unit(fails before fix with panic0x11, passes once mitigation is applied).
Was this helpful?