Core Contracts

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

`_votingState.calculateAndUpdatePower` double counts the amount for computing the voting power in the `increaseLock` function

Summary

The veRAACToken.sol 's increase function is used for when the user wants to increase or add up to the amount of locked raacTokens/rewards and getting the updated votingPower however when the newPower that is going be minted to the user is double counted when the calculateAndUpdatePower is called for computing the new power.

Vulnerability Details

In the increase function firstly what happens is the _lockState.increaseLock(msg.sender, amount); is called and in this function as can be seen the amount of additional tokens is passed in i,e the amount that the user wants to increase his lock with and inside the function the LockState struct of the user is updated with the added additional amount of the lock which is passed in the increase function. Specifically the LockState.amount is updated and that is the Amount of tokens locked. here the state is updated with the added amount. Now the issue here is that when the new voting power of the user is calculated and updated the amount param that is passed in are the previously updated LockState.amount in the increaseLock function and the in addition to that the additional amount is passed in again that can be seen here in this line Lets take an example to see the difference and how this will affect the newly computed votingPower.

Lets assume that a userA has already locked in 10000e18 tokens using the lock function for 2 years of duration and later this user decides to increase his lock by 20000e18 tokens so he calls the increaseLock function with passing in 20000e18 as the amount. Now as previously he deposited 10k tokens the UserState was updated previously too in the lock function so the amount param of the USerState is 10k before calling the increase fucntion. Now in the increase function again the UserState Lock.amount is updated via this line <- so now the updated locks.amount = 10k + 20k = 30kand the issue: when the this function is called that updated locks.amount i.e 30k is also passed in + the additional amount is passed again i.e 20k so this makes will make the function compute for more than the amount that the user has locked in i.e 30k + 20k now lets see how much the power/bias will be returned now. Example- uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION; // (50000e18 * 62553600) / 126144000 = 24794520547945205479452

Now lets see the difference in the computed power when the right amount was passed i.e 30ke18 -> (30000e18 * 62553600) / 126144000 = 14876712328767123287671 Here it can be clearly seen the difference in the voting powerss is massive if we compare to if the correct amount i.e previously updated locks.amount was passed in.

Impact

High imapct and also very high likelihood too, as the logic is flawed, the user's votingPower will be computed to a lot more than it should

Tools Used

MAnual Review

Recommendations

When calling the calculateAndUPdatePower function in the increase function, instead of passing - userLock.amount + amount just pass in the userLock.amount as the additional amount was already added to this state in the above increaseLock line

Code Snippets

function increase(uint256 amount) external nonReentrant whenNotPaused {
// Increase lock using LockManager
-> _lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount + amount, //AUDIT this state is already updated above, but still the amount is passed which will lead to incorrect calculations of votingPower
userLock.end
);```
``` function increaseLock(
LockState storage state,
address user,
uint256 additionalAmount
) internal {
Lock storage lock = state.locks[user];
if (!lock.exists) revert LockNotFound();
if (lock.end <= block.timestamp) revert LockExpired();
// Maximum lock amount
if (lock.amount + additionalAmount > state.maxLockAmount) revert AmountExceedsLimit();
// Maximum total locked amount
// if (state.totalLocked + additionalAmount > state.maxTotalLocked) revert AmountExceedsLimit();
-> lock.amount += additionalAmount;
state.totalLocked += additionalAmount;```
``` function calculateAndUpdatePower(
VotingPowerState storage state,
address user,
uint256 amount,
uint256 unlockTime
) internal returns (int128 bias, int128 slope) {
if (amount == 0 || unlockTime <= block.timestamp) revert InvalidPowerParameters();
uint256 MAX_LOCK_DURATION = 1460 days; // 4 years
// FIXME: Get me to uncomment me when able
// bias = RAACVoting.calculateBias(amount, unlockTime, block.timestamp);
// slope = RAACVoting.calculateSlope(amount);
// Calculate initial voting power that will decay linearly to 0 at unlock time
uint256 duration = unlockTime - block.timestamp;
uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION; // Normalize by max duration
bias = int128(int256(initialPower));```
Updates

Lead Judging Commences

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

veRAACToken::increase doubles the voting power of users

Support

FAQs

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