Core Contracts

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

Incorrect Boost State Update Order in `veRAACToken.lock` Causes Systemic Reward Calculation Errors

Summary

The veRAACToken.lock function contains a critical state management flaw where boost calculations use outdated voting power data during lock creation. This occurs because boost state updates are performed before completing voting power calculations and token minting operations. The incorrect sequencing leads to systematically underreported voting power values being used in reward distributions and governance weight calculations, creating cumulative inaccuracies in core protocol mechanisms over time.

Vulnerability Details

The vulnerability arises from incorrect state update sequencing in the veRAACToken lock mechanism. The veRAACToken.lock function (veRAACToken.sol#L227) updates boost state parameters before completing critical voting power calculations and token minting operations:

  1. Premature Boost State Update _updateBoostState() is called before:

  • Voting power calculation via _votingState.calculateAndUpdatePower()

  • veToken minting operation _mint()

contract veRAACToken is ERC20, Ownable, ReentrancyGuard, IveRAACToken {
function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
// ...
// Create lock position
_lockState.createLock(msg.sender, amount, duration);
@> _updateBoostState(msg.sender, amount);
// Calculate initial voting power
@> (int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
msg.sender,
amount,
unlockTime
);
// Update checkpoints
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Mint veTokens
@> _mint(msg.sender, newPower);
// ...
}
function _updateBoostState(address user, uint256 newAmount) internal {
// Update boost calculator state
@> _boostState.votingPower = _votingState.calculatePowerAtTimestamp(user, block.timestamp);
@> _boostState.totalVotingPower = totalSupply();
_boostState.totalWeight = _lockState.totalLocked;
_boostState.updateBoostPeriod();
}
}
  1. Stale Data Dependency
    The boost calculation in _updateBoostState() depends on:

  • _votingState.points[user] updated by _votingState.calculateAndUpdatePower()

  • totalSupply() value changed by _mint()

library VotingPowerLib {
function calculateAndUpdatePower(
VotingPowerState storage state,
address user,
uint256 amount,
uint256 unlockTime
) internal returns (int128 bias, int128 slope) {
// ...
// Calculate initial voting power that will decay linearly to 0 at unlock time
uint256 duration = unlockTime - block.timestamp;
uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION; // Normalize by max duration
bias = int128(int256(initialPower));
slope = int128(int256(initialPower / duration)); // Power per second decay
// ...
@> state.points[user] = RAACVoting.Point({
@> bias: bias,
@> slope: slope,
@> timestamp: block.timestamp
});
// ...
}
function calculatePowerAtTimestamp(
VotingPowerState storage state,
address account,
uint256 timestamp
) internal view returns (uint256) {
@> RAACVoting.Point memory point = state.points[account];
if (point.timestamp == 0) return 0;
if (timestamp < point.timestamp) {
return 0;
}
@> uint256 timeDelta = timestamp - point.timestamp;
@> int128 adjustedBias = point.bias - (point.slope * int128(int256(timeDelta)));
return adjustedBias > 0 ? uint256(uint128(adjustedBias)) : 0;
}
}

This results in boost calculations being based on pre-operation state values, systematically underreporting the user's actual voting power during the lock creation transaction.

Impact

This sequencing error creates systemic inaccuracies in three critical protocol mechanisms:

  1. Reward Miscalculations
    Boost-dependent reward distributions (in gauges and pools) will use stale voting power data, leading to:

    • Under-allocation of rewards for new locks

    • Disproportionate rewards for existing positions

    • Cumulative errors in long-term reward accounting

  2. Protocol Parameter Inaccuracies
    Key system metrics relying on boost calculations will be compromised:

    • Total voting power tracking

    • Gauge weight distributions

These effects compound over time, creating growing discrepancies between actual and recorded protocol states, ultimately undermining core protocol functionality and user trust in the RAAC governance system.

Tools Used

Manual Review

Recommendations

Move _updateBoostState() call after voting power calculation and token minting in veRAACToken.lock:

// Create lock position
_lockState.createLock(msg.sender, amount, duration);
- _updateBoostState(msg.sender, amount);
// Calculate initial voting power
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
msg.sender,
amount,
unlockTime
);
// Update checkpoints
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Mint veTokens
_mint(msg.sender, newPower);
+ _updateBoostState(msg.sender, amount);
Updates

Lead Judging Commences

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

veRAACToken::_updateBoostState should be called later inside lock/increase

Support

FAQs

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