Core Contracts

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

Lack of Mechanism to Prevent Overwriting Existing Locks in `veRAACToken::lock` Function

Summary

The createLock function in the LockManager library lacks a mechanism to prevent users from overwriting their existing locks. If a user calls the lock function multiple times, their existing lock will be overwritten, resulting in the loss of previously locked RAAC tokens. This issue arises because the function does not check whether the user already has an active lock before creating a new one. This could lead to unintended loss of funds.

Vulnerability Details

The lock function creates a new lock for a user without checking if they already have an active lock. If a user calls the lock function multiple times, the existing lock is overwritten, and the previously locked RAAC tokens are lost.

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();
// Do the transfer first - this will revert with ERC20InsufficientBalance if user doesn't have enough tokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
// Calculate unlock time
uint256 unlockTime = block.timestamp + duration;
// 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);
emit LockCreated(msg.sender, amount, unlockTime);
}

The function does not check if the user already has an active lock, allowing their existing lock to be overwritten, when a new lock is created, the previously locked RAAC tokens are effectively lost, as they are not returned to the user or accounted for in the new lock.users may unintentionally overwrite their locks, leading to financial losses for users

function createLock(LockState storage state, address user, uint256 amount, uint256 duration) internal returns (uint256 end) {
if (state.minLockDuration != 0 && state.maxLockDuration != 0) {
if (duration < state.minLockDuration || duration > state.maxLockDuration)
revert InvalidLockDuration();
}
if (amount == 0) revert InvalidLockAmount();
end = block.timestamp + duration;
state.locks[user] = Lock({
amount: amount,
end: end,
exists: true
});
state.totalLocked += amount;
emit LockCreated(user, amount, end);
return end;
}

The function overwrites the existing lock without any checks, leading to potential loss of funds.

Example:

// Step 1: User locks 100 RAAC tokens for 1 year
veToken.lock(100e18, 365 days); // Successfully locks 100 RAAC tokens
// Step 2: User mistakenly locks another 50 RAAC tokens for 1 year
veToken.lock(50e18, 365 days); // Overwrites the existing lock, losing the 100 RAAC tokens
// Step 3: Check the user's locked balance
uint256 lockedBalance = veToken.getLockedBalance(user); // Returns 50 RAAC tokens (100 RAAC tokens are lost)

Impact

  • Loss of Funds: Users may lose their locked RAAC tokens if they accidentally call the lock function multiple times.

Tools Used

Manual Review

Recommendations

Ensure the Lock function checks if the user already has an active lock before creating a new one.

Updates

Lead Judging Commences

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

veRAACToken::lock called multiple times, by the same user, leads to loss of funds

Support

FAQs

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