Core Contracts

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

Incorrect total supply check in veRAACToken::lock allows legitimate lock attempts to be blocked

Description

The veRAACToken::lock function incorrectly uses the raw lock amount parameter when checking against MAX_TOTAL_SUPPLY, rather than the actual veRAAC tokens to be minted. This prevents valid lock operations where the calculated voting power (based on lock duration) would stay under the supply cap but the raw amount exceeds remaining capacity.

Proof of Concept

  1. Protocol has 99M veRAAC minted (MAX_TOTAL_SUPPLY = 100M)

  2. User attempts to lock 1.5M RAAC for 2/3 of max duration (973 days)

  3. Contract calculates voting power as (1.5M * 973d)/1460d = ~1M veRAAC (slightly less than 1M)

  4. Current check totalSupply() + 1.5M = 100.5M fails

  5. Valid lock attempt gets rejected despite having sufficient capacity

Test case to demonstrate vulnerability:

In veRAACToken.test.js, add this test and run npx hardhat test --grep "blocks valid locks due to incorrect supply check"

it("blocks valid locks due to incorrect supply check", async () => {
// Create 10 locks of 9.9M RAAC to reach 99M veRAAC
const lockAmountPerTx = ethers.parseEther("9900000"); // 9.9M RAAC
const lockDuration = MAX_LOCK_DURATION;
for (let i = 0; i < 10; i++) {
await raacToken.mint(owner.address, lockAmountPerTx);
await raacToken
.connect(owner)
.approve(await veRAACToken.getAddress(), MaxUint256);
await veRAACToken.connect(owner).lock(lockAmountPerTx, lockDuration);
}
console.log("Owner lock completed");
// Attempt valid lock that should mint slightly less than 1M veRAAC (1.5M RAAC * 973d/1460d = 999657534246575342465753)
const userLockAmount = ethers.parseEther("1500000");
const validDuration = 973 * 24 * 3600;
// Setup user approvals
await raacToken.mint(users[0].address, userLockAmount);
await raacToken
.connect(users[0])
.approve(await veRAACToken.getAddress(), userLockAmount);
// Reverts with TotalSupplyLimitExceeded but 99M + 999657534246575342465753 = 99999657534246575342465753 which is < MAX_TOTAL_SUPPLY
await expect(
veRAACToken.connect(users[0]).lock(userLockAmount, validDuration)
).to.be.revertedWithCustomError(veRAACToken, "TotalSupplyLimitExceeded");
});

Impact

High Severity - Permanently blocks legitimate users from creating locks when protocol approaches supply cap, directly violating core protocol functionality. Creates artificial limitation that shouldn't exist based on system design.

Recommendation

  • Use calculated voting power for supply check:

contracts/core/tokens/veRAACToken.sol
function lock(uint256 amount, uint256 duration) external {
// ... existing checks ...
- if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
+ uint256 veAmount = (amount * duration) / MAX_LOCK_DURATION;
+ if (totalSupply() + veAmount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
}
  • Use calculated newPower for supply check:

contracts/core/tokens/veRAACToken.sol
function lock(uint256 amount, uint256 duration) external {
- if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
// ... existing checks ...
// ... code after `newPower` is computed
+ if (totalSupply() + newPower > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
}
  • Reuse existing calculation logic:

function calculateVeAmount(uint256 amount, uint256 lockDuration) public view returns (uint256) {
return (amount * lockDuration) / MAX_LOCK_DURATION;
}
  • Add helper function for supply validation:

function _checkSupplyLimit(uint256 veAmount) internal view {
if (totalSupply() + veAmount > MAX_TOTAL_SUPPLY) {
revert TotalSupplyLimitExceeded();
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect `MAX_TOTAL_SUPPLY` check in the `veRAACToken::lock/extend` function of `veRAACToken` could harm locking functionality

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.