Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Gaps between periods will result in faulty reward calculations

Description

updatePeriod() and setInitialWeight() calculate the next period start time as:

uint256 nextPeriodStart = ((currentTime / periodDuration) + 2) * periodDuration;

This logic would create gaps between periods which could be as large as twice of periodDuration. For example, in case of RWA Gauge Period, assume current period starts with day 30 and ends on day 60. Let's say currentTime is equal to endTime of current period i.e. day 60. Period duration for RWA gauge is 30 days. So next period start would be (60/30 + 2) * 30 = 120 i.e. 60 days after current time.
This gap is problematic because any change in weights during this interim gap duration are not considered for calculating time-weighted weights' average and hence totally ignored. Users can increase/decrease their vote position but with no effect.

Impact

The primary purpose of calculateAverage() is to determine time-weighted vote weights, which affect:

  • How rewards are distributed between different gauges based on their relative weights

Users who increase & decrease their position during the interim gap duration will see it have no effect on the above. This is because calculateAverage() only considers weights inside period durations and not outside them:

function calculateAverage(
Period storage self,
uint256 timestamp
) internal view returns (uint256) {
@---> if (timestamp <= self.startTime) return self.value;
// .... rest of the code

Mitigation

Change to something like:

uint256 nextPeriodStart = currentPeriod.endTime + periodDuration;
if (nextPeriodStart <= block.timestamp) nextPeriodStart = block.timestamp + 1;

Additional Area

_updateWeights() has a similar problematic calculation:

function _updateWeights(uint256 newWeight) internal {
uint256 currentTime = block.timestamp;
uint256 duration = getPeriodDuration();
if (weightPeriod.startTime == 0) {
// For initial period, start from next period boundary
@---> uint256 nextPeriodStart = ((currentTime / duration) + 1) * duration;
TimeWeightedAverage.createPeriod(
weightPeriod,
nextPeriodStart,
duration,
newWeight,
WEIGHT_PRECISION
);
}
// ... Rest of the code
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge::updatePeriod uses ((currentTime / periodDuration) + 2) calculation causing entire reward periods to be skipped, resulting in permanent loss of user rewards

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge::updatePeriod uses ((currentTime / periodDuration) + 2) calculation causing entire reward periods to be skipped, resulting in permanent loss of user rewards

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.