The Stargate contract contains a double-decrement accounting bug where _updatePeriodEffectiveStake() is called twice with the same effective stake value during the unstake flow when a validator has exited. First, requestDelegationExit() decrements the effective stake , then unstake() decrements it again when the validator status is EXITED. This causes an arithmetic underflow in _updatePeriodEffectiveStake() , permanently preventing users from unstaking and withdrawing their staked VET.
Vulnerability Details
The vulnerability exists in the effective stake accounting system across three functions in Stargate.sol:
delegatorsEffectiveStake[validator] reduced by user's effective stake
Validator becomes EXITED (offline, slashed, or voluntary exit)
User calls unstake(tokenId)
Condition at line 267 evaluates true: currentValidatorStatus == VALIDATOR_STATUS_EXITED
_updatePeriodEffectiveStake() attempts second decrement (DECREMENT #2)
currentValue - _effectiveStake underflows because value already decremented in step 2
Transaction reverts with arithmetic underflow
User permanently unable to unstake or withdraw staked VET
The bug also triggers if delegation status becomes PENDING instead of validator becoming EXITED, following the same double-decrement logic.
Impact Details
Users who follow the sequence (stake → delegate → requestDelegationExit → validator exits → unstake) lose permanent access to their staked VET. The contract holds the VET but provides no recovery mechanism. There is no admin function to force-unstake on behalf of users, and no time-based unlock. The funds remain locked in the contract indefinitely.
Financial impact depends on the number of affected users and their stake amounts. VeChain Stargate NFT staking levels range from 600,000 VET (Level 1) to 25,000,000 VET (Level 7). If even a small percentage of high-level stakers encounter this bug during validator exits, the total locked value could reach tens of millions of VET.
This constitutes permanent freezing of funds per Immunefi's Critical impact definition: "user is no longer able to withdraw their funds" with no recovery path.
Proof of Concept
Test File: packages/contracts/test/integration/DoubleDecrementBugPOC.test.ts