Core Contracts

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

Multiple boost delegations allowed in BoostController contract

Target

contracts/core/governance/boost/BoostController.sol

Summary

The BoostController contract follows Curve-style boost mechanics, with the delegateBoost function handling the delegation of boosts from the caller to another address. However, this function allows a user to delegate their total boost amount to multiple addresses simultaneously.

Vulnerability Details

Boosts are calculated based on the total veRAAC delegated to a specific liquidity provider (pool). If the same veCRV could be delegated to multiple providers, it would result in double-counting and unfair reward distribution.

In Curve’s boost delegation model, if a user holds 100 veCRV, they can delegate the full amount to one address at a time and later reassign it to another. Alternatively, they can split their veCRV proportionally across multiple addresses—for instance, if Alice has two separate lock-ups of 50 veCRV each, she can delegate them independently.

However, in the RAAC protocol's BoostController, a user can delegate their entire veCRV balance to multiple addresses simultaneously, leading to incorrect reward allocation.

function delegateBoost(
address to,
uint256 amount,
uint256 duration
) external override nonReentrant {
if (paused()) revert EmergencyPaused();
if (to == address(0)) revert InvalidPool();
if (amount == 0) revert InvalidBoostAmount();
if (duration < MIN_DELEGATION_DURATION || duration > MAX_DELEGATION_DURATION)
revert InvalidDelegationDuration();
uint256 userBalance = IERC20(address(veToken)).balanceOf(msg.sender);
if (userBalance < amount) revert InsufficientVeBalance();
UserBoost storage delegation = userBoosts[msg.sender][to];
if (delegation.amount > 0) revert BoostAlreadyDelegated();
delegation.amount = amount;
delegation.expiry = block.timestamp + duration;
delegation.delegatedTo = to;
delegation.lastUpdateTime = block.timestamp;
emit BoostDelegated(msg.sender, to, amount, duration);
}

Impact

Allowing the same veRAAC balance to be delegated to multiple addresses would create conflicts in how the boost is applied to liquidity providers' rewards, leading to double-counting or unfair reward distributions.

Tools Used

Manual Review

Recommendations

Refactor the boost delegation logic to ensure that boosts are non-divisible when delegated. This means that the full boost associated with a user’s veRAAC balance can only be delegated to one address at a time.

POC

Add the test script below to : test/unit/core/governance/boost/BoostController.test.js

describe("Boost Delegation Exploit Scenario", () => {
it("allows double delegation", async () => {
let amount = await veToken.balanceOf(user1.address);
console.log(amount);
let duration = 7 * 24 * 3600;
await boostController.connect(user1).delegateBoost(user2.address, amount, duration);
await expect(
boostController.connect(user1).delegateBoost(manager.address, amount, duration)
).to.be.revertedWithCustomError(boostController, "BoostAlreadyDelegated");
});
});
Updates

Lead Judging Commences

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