Description
The Stargate contract fails to properly handle the state transition where a user has already requested a delegation exit (requestDelegationExit), but the target validator subsequently transitions to an EXITED state before the user calls unstake.
The Logic Flaw:
When a user calls requestDelegationExit(), the contract decreases the user's effective stake from the validator's accounting for the next period. When the user later calls unstake(), the contract checks the validator's status.
If the validator status is VALIDATOR_STATUS_EXITED, the unstake function unconditionally attempts to decrease the effective stake again.
if (
currentValidatorStatus == VALIDATOR_STATUS_EXITED || // <--- Trigger condition
delegation.status == DelegationStatus.PENDING
) {
// ... logic to get period ...
// CRITICAL: Attempts to decrease stake a second time
_updatePeriodEffectiveStake(..., false);
}
Since the stake was already subtracted during the initial requestDelegationExit, the Checkpoints library (using uint224) attempts to subtract the amount from a value that has already been reduced. If the remaining stake is 0 (or less than the user's stake), this causes an Arithmetic Underflow, reverting the transaction.
Impact Permanent Lock of End-User Funds. Users who are unfortunate enough to have their delegated validator exit (or get banned) after they have initiated an exit request will be unable to unstake their VET. Every attempt to retrieve their funds will revert due to the underflow error.
Recommendation Modify the logic in unstake to ensure that effective stake is not deducted again if the user has already requested an exit.
// In Stargate.sol -> unstake function
// ...
bool hasAlreadyRequestedExit = delegation.endPeriod != type(uint32).max;
if (
(currentValidatorStatus == VALIDATOR_STATUS_EXITED || delegation.status == DelegationStatus.PENDING) &&
!hasAlreadyRequestedExit // FIX: Only deduct if exit wasn't already processed
) {
// ... existing logic to decrease effective stake ...
_updatePeriodEffectiveStake(..., false);
}
//
Validation steps
Reproduction Steps
MockStargateDependencies.sol file with the mock capable of simulating validator status changes.StargateDoubleDedup.test.ts test file.npx hardhat compilenpx hardhat test test/StargateDoubleDedup.test.ts