Core Contracts

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

`_updateBoostState` is called before ` _votingState.calculateAndUpdatePower` in `lock` and `increase` functions in veRAACToken contract, leading to incorrect boost updates.

Summary

lock and increase functions in veRAACToken contract are defined as follows:

function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
if (amount == 0) revert InvalidAmount();
if (amount > MAX_LOCK_AMOUNT) revert AmountExceedsLimit();
if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
if (duration < MIN_LOCK_DURATION || duration > MAX_LOCK_DURATION) {
revert InvalidLockDuration();
}
raacToken.safeTransferFrom(msg.sender, address(this), amount);
uint256 unlockTime = block.timestamp + duration;
// Create lock position
_lockState.createLock(msg.sender, amount, duration);
// @audit HIGH: `_updateBoostState` should be called after `calculateAndUpdatePower`
_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(msg.sender, newPower);
emit LockCreated(msg.sender, amount, unlockTime);
}
function increase(uint256 amount) external nonReentrant whenNotPaused {
// Increase lock using LockManager
_lockState.increaseLock(msg.sender, amount);
// @audit HIGH: `_updateBoostState` should be called after `calculateAndUpdatePower`
_updateBoostState(msg.sender, locks[msg.sender].amount);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) =
_votingState.calculateAndUpdatePower(msg.sender, userLock.amount + amount, userLock.end);
// Update checkpoints
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Transfer additional tokens and mint veTokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}

The problem arises because _updateBoostState internal function is called before _votingState.calculateAndUpdatePower in both functions.

updateBoostState function is defined as follows:

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();
}

It will first calculate the voting power of the user at the current timestamp with _votingState.calculatePowerAtTimestamp.

The issue is that _votingState.calculateAndUpdatePower should be called first to create a new point for the user, which will reflect his current voting power (including current lock creation or increase).

Vulnerability Details

Because _votingState.calculateAndUpdatePower is called after _updateBoostState, current lock or lock increase is not taken into account when computing the current boost for the user.

Impact

The impact of this issue is high as it leads to incorrect computation of boost for users and loss of potential rewards.

Tools Used

Manual review

Recommendations

Make sure to first call _votingState.calculateAndUpdatePower to update the voting power of the user and then call _updateBoostState to update the boost state accordingly.

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.