Core Contracts

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

The `veRAACToken::increase()` function incorrectly calculates the `amount`, allowing users to gain double the intended voting power.

Summary

The veRAACToken::increase() function incorrectly calculates the amount, allowing users to gain double the intended voting power.

Vulnerability Details

The veRAACToken::increase() function is designed to increase the amount in an existing lock. It first calls the LockManager::increaseLock() library function, which updates _lockState.locks[user].amount. After that, it calls calculateAndUpdatePower() to compute the user's new voting power. However, the function incorrectly passes userLock.amount + amount as a parameter, effectively doubling the amount considered in the voting power calculation.

// veRAACToken::increase()
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.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);
}
// LockManager::increaseLock()
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);
}

Poc

Add the following test to test/unit/core/tokens/veRAACToken.test.js and execute it:

describe("increase double voting power", () => {
it("Poc", async () => {
const amount = ethers.parseEther("1000");
const duration = 365 * 24 * 3600 * 4 ; // 4 year
// users[0] lock 1000e18
await veRAACToken.connect(users[0]).lock(amount, duration);
// user[1] lock 100e18
await veRAACToken.connect(users[1]).lock(ethers.parseEther("100"), duration);
// user[1] increase 900e18
await veRAACToken.connect(users[1]).increase(ethers.parseEther("900"));
// check
console.log("users[0] voting power:", await veRAACToken.getVotingPower(users[0].address));
console.log("users[1] voting power:", await veRAACToken.getVotingPower(users[1].address));
});
});

output:

veRAACToken
increase double voting power
users[0] voting power: 999999896943176052767n
users[1] voting power: 1899999939751395230847n

Impact

Due to the incorrect calculation, users can gain double the intended voting power when increasing their locked amount, which can significantly impact governance and decision-making mechanisms.

Tools Used

Manual Review

Recommendations

Modify the veRAACToken::increase() function to pass only userLock.amount instead of userLock.amount + amount when updating voting power:

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);
}

test again:

veRAACToken
increase double voting power
users[0] voting power: 999999904870624048708n
users[1] voting power: 999999976217656012176n
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!