Summary
Users can lock RAAC tokens in order to obtain veRAAC tokens. veRAACToken contract implements that with lock
fn. Unfortunately, the fn doesnt check if the user has already lock, which will cause the override previous lock details and lose the ability to withdraw previous locked tokens.
Vulnerability Details
The lock() function lacks validation for existing user locks. When a user calls lock() multiple times:
Previous lock data gets overwritten
Original locked tokens become permanently trapped
Total locked token accounting becomes inaccurate
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);
Impact
Tools Used
Manual review
Recommendations
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();
+ if (_lockState.locks[msg.sender].amount > 0) revert ExistingLockFound();
// Do the transfer first - this will revert with ERC20InsufficientBalance if user doesn't have enough tokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);