Core Contracts

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

Average weight will always be 0, whenever period update occurs via `BaseGuage::updatePeriod()` function.

Summary

The BaseGuage::updatePeriod() function is as follow -

/**
* @notice Updates the period and calculates new weights
*/
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
);
}

calculateAverage() function is as follow -

function calculateAverage(
Period storage self,
uint256 timestamp
) internal view returns (uint256) {
if (timestamp <= self.startTime) return self.value;
uint256 endTime = timestamp > self.endTime ? self.endTime : timestamp;
// @audit - this will always be 0.
uint256 totalWeightedSum = self.weightedSum;
if (endTime > self.lastUpdateTime) {
uint256 duration = endTime - self.lastUpdateTime;
// self.value = 0, determined in constructor.
uint256 timeWeightedValue = self.value * duration;
if (duration > 0 && timeWeightedValue / duration != self.value) revert ValueOverflow();
totalWeightedSum += timeWeightedValue;
}
return totalWeightedSum / (endTime - self.startTime); // returns 0
}
  1. self.value = 0, determined in constructor.

  2. so, timeWeightedValue will also be 0. means return value will also be 0.

  3. so avgWeight will be zero, as-

uint256 avgWeight = periodState.votingPeriod.calculateAverage(periodEnd);
  1. It means when new period will be created via TimeWeightedAverage.createPeriod, -

TimeWeightedAverage.createPeriod(
periodState.votingPeriod,
nextPeriodStart,
periodDuration,
avgWeight, // 0
WEIGHT_PRECISION
);
  1. If means whenever new period P1, P2, P3... is created, the avgWeight accounting of previous periods is not tracked.

  2. Which is very important aspect of protocol, to track the time-weighted average.

  3. But with current implementation it's not happening, i.e. average weighted value is always 0.

  4. NOTE - Developers may be assuming that they can set the weight of current period by calling setInitialWeight() function, but they won't be able to -

function setInitialWeight(uint256 weight) external onlyController {
uint256 periodDuration = getPeriodDuration();
uint256 currentTime = block.timestamp;
uint256 nextPeriodStart = ((currentTime / periodDuration) + 2) * periodDuration;
TimeWeightedAverage.createPeriod(
periodState.votingPeriod,
nextPeriodStart,
periodDuration,
weight,
10000 // WEIGHT_PRECISION
);
periodState.periodStartTime = nextPeriodStart;
}
  1. The reason why they won't be able to beacuse, there's check inside TimeWeightedAverage.createPeriod function -

if (self.startTime != 0 && startTime < self.startTime + self.totalDuration) {
revert PeriodNotElapsed();
}
  1. In simple words, controller can't update the weight of current period, more accuratly contraoller can't change any data of current ongoing period.

  2. .value can only be updated after end of a period/ or during start of next period.

Vulnerability Details

Impact

  • averageWeight of period is not tracked or it always returns 0, which is not the expected behavior.

Tools Used

Manual

Recommendations

  • In constructor, don't initialize initial value with 0, do it with any not-zero number.

  • The main cause of this issue is this, which is triggering as chain-reaction of avgWeight for all periods to 0.

Updates

Lead Judging Commences

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

BaseGauge constructor initializes votingPeriod with value=0, causing updatePeriod to always calculate avgWeight=0, permanently breaking time-weighted average tracking

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

BaseGauge constructor initializes votingPeriod with value=0, causing updatePeriod to always calculate avgWeight=0, permanently breaking time-weighted average tracking

Support

FAQs

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