Core Contracts

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

Due to the miscalculation of `nextPeriodStart` in `BaseGauge::updatePeriod` function ends up doubling the intended period duration.

Summary

In the BaseGauge::updatePeriod function scheduling error where new reward/voting periods are initialized with double the intended duration (14 days instead of 7 days). This miscalculation creates systemic misalignment of protocol cycles, disrupting time-sensitive operations including reward distributions, voting periods, and boost recalculations.

Vulnerability Details

When the CONTROLLER_ROLE calls the updatePeriod function, it updates the period and calculates new weights. However, the logic incorrectly sets nextPeriodStart, causing the new period to start two intervals later instead of one. According to the intended design, nextPeriodStart should be set 7 days later as defined in the getPeriodDuration function.

function updatePeriod() external override onlyController {
uint256 currentTime = block.timestamp;
uint256 periodEnd = periodState.periodStartTime + getPeriodDuration();
if (currentTime < periodEnd) {
revert PeriodNotElapsed();
}
uint256 periodDuration = getPeriodDuration();
// Calculate average weight for the ending period
uint256 avgWeight = periodState.votingPeriod.calculateAverage(periodEnd);
// Calculate the start of the next period (ensure it's in the future)
@>> uint256 nextPeriodStart = ((currentTime / periodDuration) + 2) * periodDuration;
// Reset period state
periodState.distributed = 0;
periodState.periodStartTime = nextPeriodStart;
// Create new voting period
TimeWeightedAverage.createPeriod(
periodState.votingPeriod,
nextPeriodStart,
periodDuration,
avgWeight,
WEIGHT_PRECISION
);
}

Example Calculations

RAACGauge (7-day Period)

  • Assumptions:

    • block.timestamp (currentTime) = 1739050128

    • periodDuration = 604800 seconds (7 days)

  • Calculation:

    nextPeriodStart = ((1739050128 / 604800) + 2) * 604800 = 1740259728
  • Result:

    • Time gap = 1740259728 - 1739050128 = 1209600 seconds, which equals 14 days.

RWAGauge (30-day Period)

  • Assumptions:

    • periodDuration = 2592000 seconds (30 days)

  • Calculation:

    nextPeriodStart = ((1739050128 / 2592000) + 2) * 2592000 = 1744234128
  • Result:

    • Time gap = 1744234128 - 1739050128 = 5184000 seconds, which equals 60 days.

Due to the miscalculation, the protocol ends up doubling the intended period duration (e.g., 14 days instead of 7, 60 days instead of 30). This leads to:

  • Delayed reward distributions.

  • Misaligned voting periods.

  • Inaccurate boost recalculations.

Impact

The error causes the gauge to update its cycle boundaries twice as late as intended, so instead of a 7-day cycle, the gauge’s internal state resets every 14 days. This misalignment delays reward rate adjustments, disrupts the voting period and boost calculations (which depend on timely, averaged weight data), and can lead to unpredictable reward accrual and distribution, ultimately compromising the protocol’s operational consistency.

Recommendations

function updatePeriod() external override onlyController {
uint256 currentTime = block.timestamp;
uint256 periodEnd = periodState.periodStartTime + getPeriodDuration();
if (currentTime < periodEnd) {
revert PeriodNotElapsed();
}
uint256 periodDuration = getPeriodDuration();
// Calculate average weight for the ending period
uint256 avgWeight = periodState.votingPeriod.calculateAverage(periodEnd);
// Calculate the start of the next period (ensure it's in the future)
- uint256 nextPeriodStart = ((currentTime / periodDuration) + 2) * periodDuration;
+ uint256 nextPeriodStart = ((currentTime / periodDuration) + 1) * periodDuration; // After (proper 7-day intervals)
// Reset period state
periodState.distributed = 0;
periodState.periodStartTime = nextPeriodStart;
// Create new voting period
TimeWeightedAverage.createPeriod(
periodState.votingPeriod,
nextPeriodStart,
periodDuration,
avgWeight,
WEIGHT_PRECISION
);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 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 7 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.

Give us feedback!