code-423n4 / 2021-12-pooltogether-findings

0 stars 0 forks source link

`cancelPromotion()` Unable to cancel unstarted promotions #101

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

Handle

WatchPug

Vulnerability details

For unstarted promotions, cancelPromotion() will revert at block.timestamp - _promotion.startTimestamp in _getCurrentEpochId().

Call stack: cancelPromotion() -> _getRemainingRewards() -> _getCurrentEpochId().

https://github.com/pooltogether/v4-periphery/blob/0e94c54774a6fce29daf9cb23353208f80de63eb/contracts/TwabRewards.sol#L331-L336

function _getRemainingRewards(Promotion memory _promotion) internal view returns (uint256) {
    // _tokensPerEpoch * _numberOfEpochsLeft
    return
        _promotion.tokensPerEpoch *
        (_promotion.numberOfEpochs - _getCurrentEpochId(_promotion));
}

https://github.com/pooltogether/v4-periphery/blob/0e94c54774a6fce29daf9cb23353208f80de63eb/contracts/TwabRewards.sol#L276-L279

function _getCurrentEpochId(Promotion memory _promotion) internal view returns (uint256) {
    // elapsedTimestamp / epochDurationTimestamp
    return (block.timestamp - _promotion.startTimestamp) / _promotion.epochDuration;
}

Recommendation

Consider checking if _promotion.startTimestamp > block.timestamp and refund _promotion.tokensPerEpoch * _promotion.numberOfEpochs in cancelPromotion().