Summary
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/gauges/GaugeController.sol#L354C5-L383C6
period misalignment leads to incorrect weight calculations
Vulnerability Details
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/gauges/GaugeController.sol#L354C5-L383C6
* @notice Calculates reward amount for a gauge
* @dev Uses gauge weight and type weight to determine share
* @param gauge Address of gauge to calculate reward for
* @return Calculated reward amount
*/
function _calculateReward(address gauge) internal view returns (uint256) {
Gauge storage g = gauges[gauge];
uint256 totalWeight = getTotalWeight();
if (totalWeight == 0) return 0;
uint256 gaugeShare = (g.weight * WEIGHT_PRECISION) / totalWeight;
uint256 typeShare = (typeWeights[g.gaugeType] * WEIGHT_PRECISION) / MAX_TYPE_WEIGHT;
uint256 periodEmission = g.gaugeType == GaugeType.RWA ? _calculateRWAEmission() : _calculateRAACEmission();
return (periodEmission * gaugeShare * typeShare) / (WEIGHT_PRECISION * WEIGHT_PRECISION);
}
uint256 duration = g.gaugeType == GaugeType.RWA ? 30 days : 7 days;
if (g.gaugeType == GaugeType.RWA) {
updatePeriod(gauge);
}
if (g.gaugeType == GaugeType.RAAC) {
updatePeriod(gauge);
}
function _calculateReward(address gauge) internal view returns (uint256) {
uint256 periodEmission = g.gaugeType == GaugeType.RWA ?
1000000 * 10**18 :
250000 * 10**18;
}
TimeWeightedAverage.Period storage period = gaugePeriods[gauge];
if (g.gaugeType == GaugeType.RWA) {
uint256 average = TimeWeightedAverage.calculateAverage(period, block.timestamp);
}
if (g.gaugeType == GaugeType.RAAC) {
uint256 average = TimeWeightedAverage.calculateAverage(period, block.timestamp);
}
RWA Periods: 0 -> 30 -> 60 -> 90
RAAC Periods: 0 -> 7 -> 14 -> 21 -> 28 -> 35 -> 42 -> 49 -> 56 -> 63 -> 70 -> 77 -> 84
Impact
period misalignment leads to incorrect weight calculations
Tools Used
Foundry
Recommendations
Copy
uint256 constant BASE_PERIOD = 7 days;
uint256 constant RWA_MULTIPLIER = 4;
function updatePeriod(address gauge) external {
Gauge storage g = gauges[gauge];
uint256 periods = g.gaugeType == GaugeType.RWA ? RWA_MULTIPLIER : 1;
uint256 duration = BASE_PERIOD * periods;
TimeWeightedAverage.createPeriod(
period,
block.timestamp,
duration,
startWeight,
endWeight
);
}
function _calculateEmission(GaugeType gaugeType) internal pure returns (uint256) {
uint256 baseEmission = 250000 * 10**18;
return gaugeType == GaugeType.RWA ?
baseEmission * RWA_MULTIPLIER :
baseEmission;
}