When a pool is paused, staking is disabled; however, block.timestampcontinues to advance while the pool remains paused. As a result, the paused duration is still counted toward the pool's staking window. Once the pool is unpaused, the expiry remains unchanged, reducing the effective time available for staking.
To preserve the intended staking duration, the pool's expiry should be extended by the amount of time the pool remained paused.
Likelihood:
Reason 1: Occurs whenever the pool is paused for any period of time, as block.timestamp continues advancing while staking remains disabled.
Reason 2: The longer the pool remains paused, the greater the reduction in the effective staking window, making the issue increasingly likely to impact participants(breaks intended timeframes).
Impact 1: The pool incorrectly accounts for paused time by continuing to include it in the staking period, causing the staking phase to end earlier than intended.
Impact 2: The effective staking period becomes shorter than the configured pool duration.
A pool is created with an expiry of 60 days.
On day 55, the pool is paused, preventing any further staking.
The pool is unpaused on day 61. Since the expiry timestamp was never adjusted, block.timestamp >= expiry, causing all subsequent calls to stake() to revert with StakingClosed().
Although the owner could increase the expiry using setExpiry(), the function enforces a minimum lead time of 30 days
Therefore, recovering only the 6 days lost during the pause is impossible. The owner would instead be forced to extend the expiry by at least 30 days, resulting in a staking period that is longer than originally intended.
Instead, the pool should automatically extend the expiry by exactly the duration it remained paused, preserving the originally configured staking window.
Track the total time spent paused and extend the expiry when the pool is unpaused.
One simple approach is to record the pause timestamp and shift expiry by the paused duration:
uint256 public pausedAt;
function pause() external onlyOwner whenPoolNotPaused {
pausedAt = block.timestamp;
_pause();
}
function unpause() external onlyOwner whenPoolPaused {
uint256 pauseDuration = block.timestamp - pausedAt;
}
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.