Link to Affected Code:
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/gauges/BaseGauge.sol#L185-L210
function _updateWeights(uint256 newWeight) internal {
uint256 currentTime = block.timestamp;
uint256 duration = getPeriodDuration();
if (weightPeriod.startTime == 0) {
uint256 nextPeriodStart = ((currentTime / duration) + 1) * duration;
TimeWeightedAverage.createPeriod(
weightPeriod,
nextPeriodStart,
duration,
newWeight,
WEIGHT_PRECISION
);
} else {
uint256 nextPeriodStart = ((currentTime / duration) + 1) * duration;
TimeWeightedAverage.createPeriod(
weightPeriod,
nextPeriodStart,
duration,
newWeight,
WEIGHT_PRECISION
);
}
}
Description:
\
The _updateWeights
function contains redundant logic that calculates period start times incorrectly. Both the initial and subsequent period branches use calendar-based alignment (currentTime / duration
) instead of maintaining continuous periods( since weightPeriod.startTime !== 0). This can create gaps in time-weighted average calculations when:
Initial period starts mid-way through a calendar period
Subsequent updates occur after period gaps
Impact:
Potential gaps in time-weighted average calculations
Inaccurate reward distributions based on weights
Periods that don't properly sequence from previous period end
Proof of Concept:
\
Consider this sequence with 7-day periods:
currentTime = Jan 5
duration = 7 days
nextPeriodStart = ((Jan 5 / 7 days) + 1) * 7 days = Jan 7
currentTime = Jan 15
nextPeriodStart = ((Jan 15 / 7 days) + 1) * 7 days = Jan 21
Recommended Mitigation:
\
Modify implementation to maintain continuous periods:
function _updateWeights(uint256 newWeight) internal {
uint256 duration = getPeriodDuration();
uint256 nextPeriodStart;
if (weightPeriod.startTime == 0) {
nextPeriodStart = ((block.timestamp / duration) + 1) * duration;
} else {
nextPeriodStart = weightPeriod.startTime + duration;
}
TimeWeightedAverage.createPeriod(
weightPeriod,
nextPeriodStart,
duration,
newWeight,
WEIGHT_PRECISION
);
}