A vulnerability arises because the TimeWeightedAverage::updateValue()
function erroneously increments the totalDuration
field, incorrectly extending the current period’s duration. This increment incorrectly treats the elapsed time within the current period as part of the overall duration, causing new period creation (via TimeWeightedAverage::createPeriod
) to revert with PeriodNotElapsed()
. Consequently, once the period is "stretched out," any subsequent calls to start a new period - such as those triggered by additional veRAACToken::lock()
or veRAACToken::increase()
calls - will indefinitely fail until the artificially extended period time finally elapses.
In the BoostCalculator::updateBoostPeriod()
function, if the current period has not yet ended, it calls:
Inside TimeWeightedAverage::updateValue()
, the code erroneously does:
Here, duration
is the time elapsed since the last update. By adding that elapsed time to totalDuration
, the current period’s duration is unintentionally extended.
totalDuration
is used to determine whether a new period can start:
Because totalDuration
grows every time TimeWeightedAverage::updateValue()
is called:
The contract behaves as though the current period never ends.
Any lock()
or increase()
calls that attempt to create a new period will revert with PeriodNotElapsed().
This effectively locks the system into an infinite extension loop until the artificially extended duration fully elapses.
Users who create or increase locks within the original period will unintentionally extend totalDuration
, causing the period to be considered "not over" due to the accumulated duration.
Once in this state, no further lock or increase operations can be performed successfully. The contract will reject all new actions until the artificially prolonged period naturally expires.
This issue repeats for every new period, meaning the protocol will be locked up in every cycle.
lock()
and increase()
operationsCalls to lock()
or increase()
will always revert when a new period should be created but is prevented by PeriodNotElapsed()
.
The lockout duration can last as long as the boost period, making it impossible for users to create/increase locks.
This issue repeats every period, meaning the protocol will repeatedly face disruption in every new cycle.
Manual Review
Here is a POC for the issue:
and the test's output:
In TimeWeightedAverage::updateValue()
, remove the line:
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.