Core Contracts

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

Wrong calculation of voting power in veRAACToken::increase allows users to gain more voting power than they should

Summary

In the veRAACToken::increase function, the calculation of the new voting power of the user uses an incorrect amount of tokens that lead to users gaining more voting power than they should.

Vunerability Details

The veRAACToken::increase function is used to increases the amount of locked RAAC tokens whithout changing the unlock time.

File: contracts/core/tokens/veRAACToken.sol#L251-L273
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]; // @audit user's lock is already updated - its amount has already increased
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount + amount, // @audit userLock.amount already takes `amount` into account in L253
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);
}

It invokes the LockManager::increaseLock function to add the given amount of RAAC tokens to the existing lock of the user (the caller of the function). Then it calculates the new voting power of the user and mint the difference (newPower - oldPower) to the user.
The issue here is that the amount used to calculates the new voting power is userLock.amount + amount where userLock.amount is supposed to be the old amount of locked RAAC tokens that the user wants to increase. However, we already added amount to the old amount of locked tokens when increasing the lock using the LockManager::increaseLock function.

File: contracts/libraries/governance/LockManager.sol#L152-L170
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;
emit LockIncreased(user, additionalAmount);
}

This means that userLock.amount + amount is actually userLock.amount + amount + amount.

Impact

This increases the voting power by more than it should.

Proof Of Concept

Place the following test in test/unit/core/tokens/veRAACToken.test.js.

it.only("should increase voting power by more than it should", async () => {
const initialAmount = ethers.parseEther("1000");
const additionalAmount = ethers.parseEther("500");
const duration = 365 * 24 * 3600; // 1 year
await veRAACToken.connect(users[0]).lock(initialAmount, duration);
const expectedVotingPower = ((initialAmount + additionalAmount) * BigInt(duration)) / BigInt(MAX_LOCK_DURATION);
await expect(veRAACToken.connect(users[0]).increase(additionalAmount))
.to.emit(veRAACToken, "LockIncreased")
.withArgs(users[0].address, additionalAmount);
const position = await veRAACToken.getLockPosition(users[0].address);
expect(position.amount).to.equal(initialAmount + additionalAmount);
const votingPower = await veRAACToken.balanceOf(users[0]);
console.log({expectedVotingPower, votingPower});
expect(votingPower).to.gt(expectedVotingPower);
});

Run the npx hardhat test test/unit/core/tokens/veRAACToken.test.js command in the terminal.

Tools Used

Manual review.

Recommendations

In veRAACToken.sol#L260 make the following change.

- userLock.amount + amount,
+ userLock.amount,
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 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.

Give us feedback!