Core Contracts

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

Infinite Boost Delegation in BoostController Allows Users to Inflate Their Voting Power

Summary

The BoostController contract allows users to delegate more boost than their actual veToken balance by not tracking the total amount of boost delegated across all recipients. This enables users to perform multiple delegations of their full balance to different addresses, effectively creating unlimited voting power from a limited veToken balance.

Vulnerability Details

The vulnerability exists in the delegateBoost function of the BoostController contract. While the function checks if a user has sufficient veToken balance for each individual delegation and prevents double delegation to the same recipient, it fails to track the cumulative amount of boost delegated across all recipients.

Here's the vulnerable code:

function delegateBoost(address to, uint256 amount, uint256 duration) external override nonReentrant {
// Checks duration and basic parameters
...
// Checks user balance but only for this specific delegation
uint256 userBalance = IERC20(address(veToken)).balanceOf(msg.sender);
if (userBalance < amount) revert InsufficientVeBalance();
// Only checks delegation to this specific recipient
UserBoost storage delegation = userBoosts[msg.sender][to];
if (delegation.amount > 0) revert BoostAlreadyDelegated();
// Sets the delegation without reducing available balance
delegation.amount = amount;
delegation.expiry = block.timestamp + duration;
...
}

The issue can be exploited as follows:

  1. User has 100 veTokens

  2. User delegates 100 boost to recipient

  3. A User delegates another 100 boost to recipient B

  4. This process can be repeated for unlimited recipients

This was confirmed by the following test in governance/boost/BoostController.test.js:

it("should allow double-delegation by not tracking total available boost", async function () {
const { boostController, veToken, user1, user2, owner } = await loadFixture(deployFixture);
const boostAmount = ethers.parseEther("100");
await veToken.mint(user1.address, boostAmount);
// First delegation succeeds
await boostController.connect(user1).delegateBoost(user2.address, boostAmount, 7 * 24 * 3600);
// Second delegation also succeeds when it should fail
await boostController.connect(user1).delegateBoost(owner.address, boostAmount, 7 * 24 * 3600);
// Both delegations exist with full amount
const delegationToUser2 = await boostController.getUserBoost(user1.address, user2.address);
const delegationToOwner = await boostController.getUserBoost(user1.address, owner.address);
expect(delegationToUser2.amount).to.equal(boostAmount);
expect(delegationToOwner.amount).to.equal(boostAmount);
});

Impact

Critical. This vulnerability allows:

  1. Infinite multiplication of voting power

  2. Manipulation of governance decisions

  3. Unfair advantages in boost-based rewards or incentives

  4. Undermining of the entire veToken-based governance system

Tools Used

  • Manual code review

  • Unit tests with Hardhat

Recommendations

Add tracking of total delegated boost per user:

contract BoostController {
// Add state variable to track total delegated boost
mapping(address => uint256) public totalDelegatedBoost;
function delegateBoost(address to, uint256 amount, uint256 duration) external {
// Existing checks...
uint256 userBalance = IERC20(address(veToken)).balanceOf(msg.sender);
// Check total delegated amount including this delegation
if (totalDelegatedBoost[msg.sender] + amount > userBalance)
revert InsufficientVeBalance();
UserBoost storage delegation = userBoosts[msg.sender][to];
if (delegation.amount > 0) revert BoostAlreadyDelegated();
// Update total delegated amount
totalDelegatedBoost[msg.sender] += amount;
delegation.amount = amount;
delegation.expiry = block.timestamp + duration;
// ...
}
function undelegateBoost(address from) external {
// ... existing undelegate logic
// Update total delegated amount
totalDelegatedBoost[msg.sender] -= delegation.amount;
// ... rest of undelegate logic
}
}
Updates

Lead Judging Commences

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

BoostController::delegateBoost lacks total delegation tracking, allowing users to delegate the same veTokens multiple times to different pools for amplified influence and rewards

Support

FAQs

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