Core Contracts

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

Users can maintain voting power without the required token lock.

Summary

the veToken system is designed to align long-term incentives by requiring users to lock RAAC tokens to participate in governance. Just like putting real estate in escrow you maintain ownership but commit to holding for a set period. The lock mechanism is crucial for protocol stability and preventing governance attacks. Having veRAAC tokens requires having locked RAAC, this mirrors how in real estate, you can't have equity rights without actually owning the property.

A user can end up with a positive veRAAC balance but no corresponding locked position. This means they could participate in governance without the required skin-in-the-game, similar to voting on property decisions without actually being invested.

If we look at the dual gauge system (RAACGauge.sol and RWAGauge.sol), this vulnerability becomes even more concerning. These gauges direct protocol incentives based on veRAAC voting power. An account with unvested voting power could manipulate gauge weights, affecting both the DeFi and real estate sides of the protocol.

Vulnerability Details

veRAACToken._update

function _update(
address from,
address to,
uint256 amount
) internal virtual override {
// BRANCH 1: Special Operations
if (from == address(0) || to == address(0)) {
// MINTING: from = address(0), to = user
// BURNING: from = user, to = address(0)
super._update(from, to, amount);
return;
}
// BRANCH 2: Regular Transfers
// Blocks direct transfers between users
// This is where the lock consistency should be enforced
revert TransferNotAllowed();
}

Users can accumulate voting power without maintaining the required token locks. In the context of RAAC's dual-gauge system, this creates a dangerous misalignment of incentives. The GaugeController distributes both weekly RAAC emissions and monthly real estate yields based on these voting weights.

When you Look at the gauge system implementation, we can see how this cascades. The RAACGauge handles protocol token emissions while the RWAGauge directs real estate yields. Both rely on accurate vote-weight accounting from veRAACToken. When lock consistency breaks, it distorts the entire reward distribution mechanism.

The TimeWeightedAverage library, which calculates voting power decay, operates on potentially invalid state. This allows manipulation of both DeFi incentives and real estate yield allocation the two pillars of RAAC's economic model.

  1. Operation Types:

    • Minting: from = address(0) → Creates new veRAAC tokens

    • Burning: to = address(0) → Destroys existing veRAAC tokens

    • Regular: Both addresses non-zero → Always reverts

  2. The Flow:

Minting → Lock Creation → Voting Power
Lock State Check Missing Here
Potential Balance/Lock Mismatch

Impact

The code expect that any user with a positive veRAACToken balance must have tokens locked in the system, the relationship between balanceOf() and getLockedBalance() is fundamental to the vote-escrow mechanism.

Looking at veRAACToken.sol, we can see how this could be violated:

  1. The lock() function mints veRAACTokens based on amount and duration

  2. The withdraw() function should only allow withdrawals after lock expiry

  3. The balance tracking and lock state can become desynchronized

Stems from the relationship between:

  • Token balances (tracked via ERC20 mechanics)

  • Lock positions (tracked in the LockManager library)

  • Voting power calculations (handled by VotingPowerLib)

Tools Used

manual

Recommendations

Strengthen the connection between token balances and lock positions in veRAACToken. Every balance-changing operation must verify lock consistency, similar to how real estate transactions require title verification.

function _update(address from, address to, uint256 amount) internal virtual override {
// VALIDATION ZONE
if (from != address(0)) { // Skip check for minting
// Lock Verification
// Ensures user has sufficient locked tokens before any balance reduction
require(locks[from].amount >= amount, "Insufficient locked balance");
require(block.timestamp >= locks[from].end, "Lock not expired");
}
// OPERATION ZONE
if (from == address(0) || to == address(0)) {
// MINTING (from = 0x0): Requires corresponding lock creation
// BURNING (to = 0x0): Requires valid lock expiration
super._update(from, to, amount);
return;
}
// TRANSFER ZONE
// Regular transfers remain blocked
// Preserves vote-escrow tokenomics
revert TransferNotAllowed();
}
Operation Flow:
1. Lock Validation (New)
└─ Check lock amount
└─ Verify lock expiration
2. Special Operations
└─ Minting: Must pair with lock
└─ Burning: Must respect lock
3. Transfer Protection
└─ Maintains non-transferability
Updates

Lead Judging Commences

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

GaugeController doesn't decay gauge vote weights when veRAAC voting power expires, allowing users to influence reward distribution with expired voting power

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

GaugeController doesn't decay gauge vote weights when veRAAC voting power expires, allowing users to influence reward distribution with expired voting power

Support

FAQs

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

Give us feedback!