60282 sc high last delegators for an exited validator may be dosed from re delegating or unstaking due to incorrect accounting of period effective stake
Description
Brief/Intro
Vulnerability Details
function requestDelegationExit(
uint256 _tokenId
) external whenNotPaused onlyTokenOwner(_tokenId) nonReentrant {
StargateStorage storage $ = _getStargateStorage();
uint256 delegationId = $.delegationIdByTokenId[_tokenId];
if (delegationId == 0) {
revert DelegationNotFound(_tokenId);
}
Delegation memory delegation = _getDelegationDetails($, _tokenId);
if (delegation.status == DelegationStatus.PENDING) {
// if the delegation is pending, we can exit it immediately
// by withdrawing the VET from the protocol
$.protocolStakerContract.withdrawDelegation(delegationId);
emit DelegationWithdrawn(
_tokenId,
delegation.validator,
delegationId,
delegation.stake,
$.stargateNFTContract.getTokenLevel(_tokenId)
);
// and reset the mappings in storage regarding this delegation
_resetDelegationDetails($, _tokenId);
} else if (delegation.status == DelegationStatus.ACTIVE) {
// If the delegation is active, we need to signal the exit to the protocol and wait for the end of the period
// We do not allow the user to request an exit multiple times
if (delegation.endPeriod != type(uint32).max) {
revert DelegationExitAlreadyRequested();
}
$.protocolStakerContract.signalDelegationExit(delegationId);
} else {
revert InvalidDelegationStatus(_tokenId, delegation.status);
}
// decrease the effective stake
// Get the latest completed period of the validator
(, , , uint32 completedPeriods) = $.protocolStakerContract.getValidationPeriodDetails(
delegation.validator
);
(, uint32 exitBlock) = $.protocolStakerContract.getDelegationPeriodDetails(delegationId);
// decrease the effective stake
> _updatePeriodEffectiveStake($, delegation.validator, _tokenId, completedPeriods + 2, false);
emit DelegationExitRequested(_tokenId, delegation.validator, delegationId, exitBlock);
}
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));
}Impact Details
Recommendation
References
Proof of Concept
Previous60289 sc low misconfigured level with maturityblocks 0 allows skip of maturity requirements and backrun mintingNextBelong
Was this helpful?