function _calculateReward(address gauge) public view returns (uint256, uint256) {
Gauge storage g = gauges[gauge];
@> uint256 totalWeight = getTotalWeight();
if (totalWeight == 0) return (0, 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), gaugeShare);
}
This means that, gauge types that shouldn't have a share of a particular emission are technically allocated shares as well, effectively reducing the available shares for the actual deserving gauge type.
This effect is heightened as more gauges are added to the controller.
pragma solidity ^0.8.19;
import {ERC20Mock} from "../../../../contracts/mocks/core/tokens/ERC20Mock.sol";
import {FeeCollector} from "../../../../contracts/core/collectors/FeeCollector.sol";
import {Treasury} from "../../../../contracts/core/collectors/Treasury.sol";
import {RAACToken} from "../../../../contracts/core/tokens/RAACToken.sol";
import {veRAACToken} from "../../../../contracts/core/tokens/veRAACToken.sol";
import {GaugeController, IGaugeController} from "../../../../contracts/core/governance/gauges/GaugeController.sol";
import {RAACGauge} from "../../../../contracts/core/governance/gauges/RAACGauge.sol";
import {RWAGauge} from "../../../../contracts/core/governance/gauges/RWAGauge.sol";
import {Test, console} from "forge-std/Test.sol";
contract TestSuite is Test {
FeeCollector feeCollector;
Treasury treasury;
RAACToken raacToken;
veRAACToken veRAACTok;
GaugeController gaugeController;
RAACGauge raacGauge;
RAACGauge raacGauge2;
RWAGauge rwaGauge;
address repairFund;
address admin;
address rewardToken;
uint256 initialSwapTaxRate = 100;
uint256 initialBurnTaxRate = 50;
function setUp() public {
repairFund = makeAddr("repairFund");
admin = makeAddr("admin");
rewardToken = address(new ERC20Mock("Reward Token", "RWT"));
treasury = new Treasury(admin);
raacToken = new RAACToken(admin, initialSwapTaxRate, initialBurnTaxRate);
veRAACTok = new veRAACToken(address(raacToken));
feeCollector = new FeeCollector(address(raacToken), address(veRAACTok), address(treasury), repairFund, admin);
vm.startPrank(admin);
raacToken.setFeeCollector(address(feeCollector));
raacToken.setMinter(admin);
gaugeController = new GaugeController(address(veRAACTok));
raacGauge = new RAACGauge(rewardToken, address(veRAACTok), address(gaugeController));
raacGauge2 = new RAACGauge(rewardToken, address(veRAACTok), address(gaugeController));
rwaGauge = new RWAGauge(rewardToken, address(veRAACTok), address(gaugeController));
vm.stopPrank();
}
function testTotalGaugeWeightImplementationReducesGaugeShares() public {
uint256 initialWeightRAAC = 4000;
uint256 initialWeightRWA = 2000;
vm.startPrank(admin);
gaugeController.addGauge(address(raacGauge), IGaugeController.GaugeType.RAAC, initialWeightRAAC);
gaugeController.addGauge(address(raacGauge2), IGaugeController.GaugeType.RAAC, initialWeightRAAC);
gaugeController.addGauge(address(rwaGauge), IGaugeController.GaugeType.RWA, initialWeightRWA);
vm.stopPrank();
(, uint256 actualGaugeShare) = gaugeController._calculateReward(address(raacGauge));
uint256 expectedGaugeShare = 5000;
console.log("Actual gauge share: ", actualGaugeShare);
console.log("Expected gauge share: ", expectedGaugeShare);
assertLt(actualGaugeShare, expectedGaugeShare);
}
Create a function that takes into consideration the gauge type when calculating the total weight and use that to calculate the rewards for each gauge. Alternatively, modify the existing `totalWeight` function to do so instead.