Core Contracts

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

Excessive minting due to double increase in veRAACToken#increase()

Summary

The veRAACToken#increase() incorrectly increases the voting power calculation twice when a user locks additional tokens. This results in the over-minting of veRAAC tokens, which can inflate voting power unfairly and break governance integrity.

Vulnerability Details

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, //@audit amount already added in `increaseLock()`
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);
}

_lockState.increaseLock(msg.sender, amount); already adds amount to the user's locked balance.

Then, _votingState.calculateAndUpdatePower() is called and adds amount again.

Since amount is already added in _lockState.increaseLock(), adding it again here results in an excessive increase in voting power.

This leads to the over-minting of veRAAC tokens, allowing users to gain disproportionate voting power and potentially manipulate governance.

  • Proof Of Code

Testcode is written in veRAACToken.test.js

describe("Newspace POC", () => {
it("double increase lock amount", 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);
console.log(await veRAACToken.balanceOf(users[0].address));
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);
console.log(position.power);
});
});

Output:

250000000000000000000n 499999857305936073059n

Exact Result:

250000000000000000000n
374999892979452054794n

As seen output, only increasing 500e18 tokens are same as 1000e18 tokens. This causes double increase.

Impact

veRAACTokens can be inflating leading to disrupt the protocol.

Tools Used

manual, hardhat

Recommendations

Update increase() to prevent double increase amount.

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