Core Contracts

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

Updating the boost value for a user in a specific pool breaks accounting

Summary

BoostController.sol implements the functionality of updating a user's boost to a specific pool. The boost to the relevant pool is calculated based on the user's veToken balance at the time of executing the call. Unfortunately, the protocol makes a mistake by tweaking the pool's workingSupply (the value responsible for representing the boosted supply of a pool) wrongfully.

Vulnerability Details

After all necessary initialisations and safety checks, we execute the following line:

uint256 newBoost = _calculateBoost(user, pool, 10000);

The boost calculation itself is fine. Using these values, we then update the users state via:

userBoost.amount = newBoost; and userBoost.lastUpdateTime = block.timestamp.

The pools totals (regarding the boosts) are updated within an if and else condition. After such operation, we set the poolBoost.workingSupply to the user's unique newBoost value.

function updateUserBoost(address user, address pool) external override nonReentrant whenNotPaused {
...
poolBoost.workingSupply = newBoost; // Set working supply directly to new boost

Impact

This would mean that anything accounting related to the poolBoost's workingSupply, such as the getPoolBoost(pool) (which returns one of the parameters as the workingSupply of the queried pool) would yield false results.

Simultaneously, when removing boosts, we use an if condition to check if the workingSupply of the pool is more than the delegated amount, and if it is, then we remove. We can now assume a very possible scenario of the poolBoost's working supply being higher than the delegated amount, therefore the delegated amount should be deducted from the workingSupply, but due to the flaw described, it would not deduct.
The main problem arises from the fact that, when multiple users utilise the same poolBoost, then the workingSupply is actually broken, because the value is unique to the user(s) who initially executed updateUserBoost for the pool.

Tools Used

Chisel

Recommendations

Correctly tweak the poolBoost's working supply, by adding the newBoost amount to it rather than explicitly setting it to such value based on a user's singular calculation.

Updates

Lead Judging Commences

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

BoostController::updateUserBoost overwrites workingSupply with single user's boost value instead of accumulating, breaking reward multipliers and allowing last updater to capture all benefits

Support

FAQs

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

Give us feedback!