Core Contracts

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

The current implementation of the lock mechanism in the veRAACToken contract can lead to a permanent lock of RAAC tokens

Summary

The current implementation of the lock mechanism in the veRAACToken contract can lead to a permanent lock of RAAC tokens.

Vulnerability Details

The veRAACToken.sol::lock is used to lock RAAC tokens and gain voting power. It invokes the LockManager::createLock function in that process to create a Lock for the user locking RAAC tokens. Here's is how the LockManager::createLock function is implemented.

File: contracts/libraries/governance/LockManager.sol#L117-L143
function createLock(
LockState storage state,
address user,
uint256 amount,
uint256 duration
) internal returns (uint256 end) {
// Validation logic remains the same
if (state.minLockDuration != 0 && state.maxLockDuration != 0) {
if (duration < state.minLockDuration || duration > state.maxLockDuration)
revert InvalidLockDuration();
}
end = block.timestamp + duration;
// @audit erase and override the previous amount locked
state.locks[user] = Lock({
amount: amount,
end: end,
exists: true
});
state.totalLocked += amount;
emit LockCreated(user, amount, end);
return end;
}

When users create a lock position for RAAC tokens using , a Lock is created, the amount to lock is sent
function to mint the equivalent amount of veRAACToken to the.

When a user creates a lock position using the veRAACToken::lock function, the veRAACToken gets the amount of RAAC token from the user and invokes the LockManager::createLock to create a Lock that stores the amount locked and the time by which the lock position ends.

The issue here is that there is no way to ensure that the veRAACToken::lock function is called only once by a same address. Which means if a user locks twice (maybe he didn't know creating a second lock will erase override the first or just forgot he already created a lock), the amount of the first time will be permanently locked since the second lock will erase the lock's amount (the 1st amount) and overrides its value.
Also, there is no way to recover those locked tokens since all the methods that allow a user to unlock his RAAC tokens only convert the amount of the lock and do not take into account the user's veRAACToken balance.

Impact

Permanent lock of user funds

Tools Used

Manual review.

Recommendations

Check whether the user has already created a Lock or not.

function createLock(
LockState storage state,
address user,
uint256 amount,
uint256 duration
) internal returns (uint256 end) {
// Validation logic remains the same
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;
+ require(!state.locks[user].exists, "User has already created a Lock");
state.locks[user] = Lock({
amount: amount,
end: end,
exists: true
});
state.totalLocked += amount;
emit LockCreated(user, amount, end);
return end;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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.