Summary
Users can increase the amount of locked RAAC tokens and receive more veRAAC tokens due to incorrect accounting within the veRAACToken.increase()
function.
Vulnerability Details
When users want to increase the the amount of locked RAAC tokens, they invoke veRAACToken.increase()
function.
The function first updates the user’s _lockState
by calling _lockState.increaseLock(msg.sender, amount)
, which correctly increases userLock.amount
by amount
, then calculates newBias
.
Since we first updates _lockState
, userLock.amount
is increased by amount. However, veRAACToken.increase()
uses userLock.amount + amount
as param for _votingState.calculateAndUpdatePower()
.
As result, it will return inflated newBias
and user will receive inflated veRAAC tokens.
function increase(uint256 amount) external nonReentrant whenNotPaused {
_lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
@> userLock.amount + amount,
userLock.end
);
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
raacToken.safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}
Impact
Users will receive inflated amounts of veRAAC tokens when they increase their locked RAAC tokens due to this flaw, potentially affecting the overall fairness and distribution of voting power in the system.
Tools Used
Manual Review
Recommendations
Remove addition of amount in calculation.
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,
+ userLock.amount,
userLock.end
);
// Update checkpoints
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Transfer additional tokens and mint veTokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}