Core Contracts

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

On boost delegation removal, updating to poolBoost storage struct isn't happening.

Summary

Contract - BoostController.sol

Code snippet of delegateBoost() function.

function delegateBoost(
address to,
uint256 amount,
uint256 duration
) external override nonReentrant {
if (paused()) revert EmergencyPaused();
if (to == address(0)) revert InvalidPool();
if (amount == 0) revert InvalidBoostAmount();
if (duration < MIN_DELEGATION_DURATION || duration > MAX_DELEGATION_DURATION)
revert InvalidDelegationDuration();
uint256 userBalance = IERC20(address(veToken)).balanceOf(msg.sender);
if (userBalance < amount) revert InsufficientVeBalance();
UserBoost storage delegation = userBoosts[msg.sender][to];
if (delegation.amount > 0) revert BoostAlreadyDelegated();
delegation.amount = amount;
delegation.expiry = block.timestamp + duration;
delegation.delegatedTo = to;
delegation.lastUpdateTime = block.timestamp;
// @audit - PoolBoost storage poolBoost = poolBoosts[to]; not being used here, which is being used in remove delegation operat
// in removeBoostDelegation function, there will not any state change happen as poolBoost data will be empty object there.
emit BoostDelegated(msg.sender, to, amount, duration);
}

Code snippet of removeBoostDelegation() function.

function removeBoostDelegation(address from) external override nonReentrant {
UserBoost storage delegation = userBoosts[from][msg.sender];
if (delegation.delegatedTo != msg.sender) revert DelegationNotFound();
if (delegation.expiry > block.timestamp) revert InvalidDelegationDuration();
// Update pool boost totals before removing delegation
PoolBoost storage poolBoost = poolBoosts[msg.sender];
// @audit - reflection of previous audit, no if statement will execute.
if (poolBoost.totalBoost >= delegation.amount) {
poolBoost.totalBoost -= delegation.amount;
}
if (poolBoost.workingSupply >= delegation.amount) {
poolBoost.workingSupply -= delegation.amount;
}
poolBoost.lastUpdateTime = block.timestamp;
emit DelegationRemoved(from, msg.sender, delegation.amount);
delete userBoosts[from][msg.sender];
}

Vulnerability Details

  1. When removeBoostDelegation() is called, it's expected to update poolBoost.totalBoost and poolBoost.workingSupply.

  2. If poolBoost.totalBoost >= delegation.amount and poolBoost.workingSupply >= delegation.amount, then poolBoost state
    will update.

  3. But problem here is that poolBoost will be empty object all the time.

  4. Why? Because in delegateBoost() function, poolBoost is not set for to address. something like -

PoolBoost storage poolBoost = poolBoosts[to];
  1. as to in delegateBoost() is equivalent to msg.sender in removeBoostDelegation().

  2. In PoolBoost storage poolBoost = poolBoosts[msg.sender];; poolBoost will always be an empty object.

  3. so the operation (below) will never execute.

if (poolBoost.totalBoost >= delegation.amount) {
poolBoost.totalBoost -= delegation.amount;
}
if (poolBoost.workingSupply >= delegation.amount) {
poolBoost.workingSupply -= delegation.amount;
}

Impact

  1. poolBoost state not being udpated can lead to multiple issue, as it's used many places, throughout the proctocol.

  2. Also it's causing the function to not work properly.

Tools Used

Manual

Recommendations

In delegateBoost() function update poolBoost for to address. something like -

function delegateBoost(
address to,
uint256 amount,
uint256 duration
) external override nonReentrant {
// Code....
+ PoolBoost storage poolBoost = poolBoosts[to];
+ poolBoost.totalBoost += delegation.amount;
+ poolBoost.workingSupply += delegation.amount;
// Code....
}
Updates

Lead Judging Commences

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

BoostController removes pool boost on delegation removal without adding it on delegation creation, leading to accounting inconsistencies and potential underflows

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

BoostController removes pool boost on delegation removal without adding it on delegation creation, leading to accounting inconsistencies and potential underflows

Support

FAQs

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