Core Contracts

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

If a user calls the `lock` function again, their existing lock position will be lost.

Summary

Users can lock their raacToken and mint veRAACToken. However, the lock function does not check if the user already has an existing lock position, which may result in the loss of locked assets in the veRaacToken contract.

Vulnerability Details

A user can lock raacToken for a valid duration in the veRaacToken contract and mint new veToken by calling the lock function

/contracts/core/tokens/veRAACToken.sol:212
212: function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
...
220: // Do the transfer first - this will revert with ERC20InsufficientBalance if user doesn't have enough tokens
221: raacToken.safeTransferFrom(msg.sender, address(this), amount);
222:
223: // Calculate unlock time
224: uint256 unlockTime = block.timestamp + duration;
225:
226: // Create lock position
227: _lockState.createLock(msg.sender, amount, duration);
228: _updateBoostState(msg.sender, amount);
229:
230: // Calculate initial voting power
231: (int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
232: msg.sender,
233: amount,
234: unlockTime
235: );
236:
237: // Update checkpoints
238: uint256 newPower = uint256(uint128(bias));
239: _checkpointState.writeCheckpoint(msg.sender, newPower);
240:
241: // Mint veTokens
242: _mint(msg.sender, newPower);
243:
244: emit LockCreated(msg.sender, amount, unlockTime);
245: }

This function does not check whether the user already has an existing lock position before creating a new one. As a result, it could potentially override the current position, leading to the loss of the user's existing locked tokens.

POC

Add following test case to veRAACToken.test.js and run woth command npx hardhat test

it.only("user will lose lock token if lock is existing", async () => {
let amount = ethers.parseEther("1000");
const duration = 365 * 24 * 3600; // 1 year
// Create lock first
await veRAACToken.connect(users[0]).lock(amount, duration);
// Verify lock position
const position = await veRAACToken.getLockPosition(users[0].address);
amount = ethers.parseEther("100");// change amount to 100
// Override Existing position
await veRAACToken.connect(users[0]).lock(amount, duration);
const newPosition = await veRAACToken.getLockPosition(users[0].address);
expect(newPosition.amount).to.lt(position.amount);
expect(newPosition.amount).to.eq(amount);
});

Impact

If a user mistakenly calls the lock function again, they will lose their currently locked tokens.

Tools Used

Manual Review

Recommendations

Did not allow user to lock if already have lock position.

Updates

Lead Judging Commences

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

Give us feedback!