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:
221: raacToken.safeTransferFrom(msg.sender, address(this), amount);
222:
223:
224: uint256 unlockTime = block.timestamp + duration;
225:
226:
227: _lockState.createLock(msg.sender, amount, duration);
228: _updateBoostState(msg.sender, amount);
229:
230:
231: (int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
232: msg.sender,
233: amount,
234: unlockTime
235: );
236:
237:
238: uint256 newPower = uint256(uint128(bias));
239: _checkpointState.writeCheckpoint(msg.sender, newPower);
240:
241:
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;
await veRAACToken.connect(users[0]).lock(amount, duration);
const position = await veRAACToken.getLockPosition(users[0].address);
amount = ethers.parseEther("100");
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.