Core Contracts

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

Unbounded Boost Delegation Undermines veRAACToken Economics

Summary

The boost delegation mechanism allows users to delegate more voting power than their veToken balance permits. This breaks the core economic model of the protocol by enabling boost multipliers beyond the intended 2.5x maximum.

A user with veToken balance can delegate boost amounts that exceed the MAX_BOOST limit (25000 basis points or 2.5x). The BoostController's delegateBoost() function accepts amount parameters that can be higher than the calculated maximum boost based on the user's veToken balance.

We expects delegated amounts to stay within MAX_BOOST (2.5x) of the user's veToken balance. However, the delegateBoost() function only checks if the user has sufficient veToken balance, not if the boost amount respects the maximum multiplier.

Vulnerability Details

The BoostController, designed to manage voting power delegation in the RAAC protocol's flaw in its delegation mechanism. When a user delegates boost power, the contract fails to enforce the protocol's fundamental 2.5x boost limit (MAX_BOOST = 25000 basis points).

An attacker can exploiting by first acquiring a minimal amount of veRAACToken. They then delegate boost amounts far exceeding their voting power to multiple pools. The BoostController naively checks only the raw token balance without considering the MAX_BOOST multiplier cap.

The consequences ripple through the entire protocol ecosystem. The GaugeController, responsible for managing reward distributions between RWA and RAAC gauges, now processes voting weights based on artificially inflated boost values. This directly impacts yield distribution in the LendingPool and undermines the stability mechanisms built into the StabilityPool.

function delegateBoost(
address to,
uint256 amount,
uint256 duration
) external override nonReentrant {
// 🛑 Emergency checks
if (paused()) revert EmergencyPaused();
if (to == address(0)) revert InvalidPool();
if (amount == 0) revert InvalidBoostAmount();
// ⏰ Duration validation
if (duration < MIN_DELEGATION_DURATION || duration > MAX_DELEGATION_DURATION)
revert InvalidDelegationDuration();
// 🚩 vulnerability: Only checks raw balance without MAX_BOOST limit
uint256 userBalance = IERC20(address(veToken)).balanceOf(msg.sender);
if (userBalance < amount) revert InsufficientVeBalance();
// 📝 Delegation state management
UserBoost storage delegation = userBoosts[msg.sender][to];
if (delegation.amount > 0) revert BoostAlreadyDelegated();
// 💾 Store delegation details
delegation.amount = amount;
delegation.expiry = block.timestamp + duration;
delegation.delegatedTo = to;
delegation.lastUpdateTime = block.timestamp;
// 📢 Event emission
emit BoostDelegated(msg.sender, to, amount, duration);
}

This is equivalent to allowing a minority shareholder with 1% voting rights to cast votes with 100% voting power, completely subverting corporate governance. In the RAAC protocol, this means a user with minimal veRAACToken stake could control disproportionate amounts of protocol rewards and governance decisions.

Just like the Curve gauge exploitation (2021) but with a crucial difference, our boost delegation directly impacts the GaugeController's reward calculations.

Impact

The BoostController's delegation system connects directly to the core veRAACToken voting mechanism because the boost delegation completely bypasses the MAX_BOOST limit (25000 basis points) defined in the protocol whitepaper.

This allows users to delegate boost amounts that exceed protocol limits, undermining the economic incentives. A malicious user could:

  1. Lock minimal veToken amount

  2. Delegate excessive boost to multiple pools

  3. Gain disproportionate rewards

When boost delegation exceeds MAX_BOOST:

  • Gauge voting power becomes unbalanced

  • RAACGauge and RWAGauge reward distributions skew unfairly

  • The entire time-weighted average calculation in GaugeController breaks down

Recommendations

function delegateBoost(
address to,
uint256 amount,
uint256 duration
) external override nonReentrant {
// 🛑 Emergency and input validation
if (paused()) revert EmergencyPaused();
if (to == address(0)) revert InvalidPool();
if (amount == 0) revert InvalidBoostAmount();
// ⏰ Duration validation
if (duration < MIN_DELEGATION_DURATION || duration > MAX_DELEGATION_DURATION)
revert InvalidDelegationDuration();
// 💫 Balance and boost limit checks
uint256 userBalance = IERC20(address(veToken)).balanceOf(msg.sender);
if (userBalance < amount) revert InsufficientVeBalance();
// ✨ New: Enforce protocol boost limits
uint256 maxBoostAmount = (userBalance * MAX_BOOST) / 10000;
require(amount <= maxBoostAmount, "Exceeds max boost");
// 📝 Delegation state management
UserBoost storage delegation = userBoosts[msg.sender][to];
if (delegation.amount > 0) revert BoostAlreadyDelegated();
// 💾 Store delegation details
delegation.amount = amount;
delegation.expiry = block.timestamp + duration;
delegation.delegatedTo = to;
delegation.lastUpdateTime = block.timestamp;
// 📢 Event emission
emit BoostDelegated(msg.sender, to, amount, duration);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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