Core Contracts

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

Lock function can be called while having already a lock, leading to loss of the previous lock funds.

Summary

In veRAACToken.sol, the lock() function is used to lock RAACTokens for an amount of time to get VeRAACTokens and voting power in the protocol. This is done via veRAACToken contract and LockManager createLock(). The locks for a user are stored in a mapping from the user address to a struct Lock, that is created in the createLock() function. The problem arises in the lack of checks of an currently existing lock, leading to the possibility to create a Lock without having redeemed/waited for the previous lock. This could lead to the lose of the funds stored in the previous lock as the lock()function nor the createLock()function checks for an existing lock.

Vulnerability Details

This can be checked with the next test, in veRAACToken.test.js:

it("destroys lock if locking again", async () => {
const amount = ethers.parseEther("1000");
const duration = 365 * 24 * 3600; // 1 year
// Create lock first
const tx = await veRAACToken.connect(users[0]).lock(amount, duration);
// Wait for the transaction
const receipt = await tx.wait();
// Find the LockCreated event
const event = receipt.logs.find(
log => log.fragment && log.fragment.name === 'LockCreated'
);
// Get the actual unlock time from the event
const actualUnlockTime = event.args[2];
// Verify lock position
const position = await veRAACToken.getLockPosition(users[0].address);
expect(position.amount).to.equal(amount);
expect(position.end).to.equal(actualUnlockTime);
expect(position.power).to.be.gt(0);
// and do it again
const amount2 = ethers.parseEther("100");
const duration2 = 2 * 365 * 24 * 3600; // 2 year
// Create lock first
const tx2 = await veRAACToken.connect(users[0]).lock(amount2, duration2);
// Wait for the transaction
const receipt2 = await tx2.wait();
// Find the LockCreated event
const event2 = receipt2.logs.find(
log => log.fragment && log.fragment.name === 'LockCreated'
);
// Get the actual unlock time from the event
const actualUnlockTime2 = event2.args[2];
// Verify lock position
const position2 = await veRAACToken.getLockPosition(users[0].address);
expect(position2.amount).to.equal(amount2);
expect(position2.end).to.equal(actualUnlockTime2);
expect(position2.power).to.be.gt(0);
});

Impact

IMPACT: Medium -> users could lose a high amount of money if they overwrite a big lock

LIKELIHOOD: Medium/Low -> users can forget they had a lock/ mistakenly make a lock without redeeming the previous one kind of easily

Tools Used

Manual

Recommendations

Create a check for an existing lock in the lock()or createLock()functions

Updates

Lead Judging Commences

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