Summary
In the veRAACToken.sol users are allowed to increase their stake and their voting power will also increase but these will end up adding more vote power to the user than they should have.
Vulnerability Details
When a user increases his locked token,
* @notice Increases the amount of locked RAAC tokens
* @dev Adds more tokens to an existing lock without changing the unlock time
* @param amount The additional amount of RAAC tokens to lock
*/
function increase(uint256 amount) external nonReentrant whenNotPaused {
@audit>> 1. _lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
@audit>>2. LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
@audit>> userLock.amount + amount,
userLock.end
);
uint256 newPower = uint256(uint128(newBias));
@audit>> _checkpointState.writeCheckpoint(msg.sender, newPower);
raacToken.safeTransferFrom(msg.sender, address(this), amount);
@audit>> _mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}
Increase lock will update the user's locked amount
* @notice Increases the amount in an existing lock
* @dev Adds tokens to existing lock without changing duration
* @param state The lock state storage
* @param user Address increasing their lock
* @param additionalAmount Additional amount to lock
*/
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();
if (lock.amount + additionalAmount > state.maxLockAmount) revert AmountExceedsLimit();
@audit>> lock.amount += additionalAmount;
state.totalLocked += additionalAmount;
emit LockIncreased(user, additionalAmount);
}
When call to get the userlock the locked details will return a already updated locked amount yet we add amount to locked amount giving the users more vote power than they should have.
@audit>>2. LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
@audit>> userLock.amount + amount,
userLock.end
);
E.g
User locks 10 and gets 5 vote power...... 10 * 2years/ 4 years = 5
calls to lock 10 more and get 5 more power to 10 ......... 20 * 2 years/ 4 years = 10
instead they will get 30*2 year/4years = 15 Power
5 more power
if the use deposited 20 directly they will get 10 Power but by breaking the deposit an attacker can again more power to influence the governance of the protocol.
Impact
Users are given more power than the actual amount they deposited. This will affect the governance has users with higher votes can push proposal.
Tools Used
Manual Review
Recommendations
Just user the users locked amount and not add amount
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
-- userLock.amount + amount,
++ userLock.amount,
userLock.end
);