Core Contracts

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

Lock Overwrite Vulnerability: Users Can Lose Funds Due to Missing Existing Lock Check

Summary

The createLock function in the contract does not check if a user already has an existing lock before allowing them to create a new one. Since the implementation does not support multiple locks per user, any new lock creation will overwrite the existing lock, leading to potential fund loss for users who expect multiple locks to be stored separately.

Affected code: veRAACToken::lock

Vulnerability Details

Paste the following code into the veRAACToken.test.js file

Proof of Concept (PoC)

it.only("should overwrite the first lock when creating a new lock", async () => {
const amount1 = ethers.parseEther("1000");
const amount2 = ethers.parseEther("2000");
const duration1 = 365 * 24 * 3600; // 1 year
const duration2 = 370 * 24 * 3600; // Slightly more than 1 year
// Create the first lock
const tx1 = await veRAACToken.connect(users[0]).lock(amount1, duration1);
await tx1.wait();
const firstLock = await veRAACToken.getLockPosition(users[0].address);
console.log("First lock created:", {
amount: firstLock.amount.toString(),
power: firstLock.power.toString(),
unlockTime: firstLock.end.toString(),
});
// Create a second lock (which should overwrite the first lock)
const tx2 = await veRAACToken.connect(users[0]).lock(amount2, duration2);
await tx2.wait();
const secondLock = await veRAACToken.getLockPosition(users[0].address);
console.log("Second lock created, overwriting first lock:", {
amount: secondLock.amount.toString(),
power: secondLock.power.toString(),
unlockTime: secondLock.end.toString(),
});
// Validate that the second lock replaced the first lock
expect(secondLock.amount).to.equal(amount2);
});
  1. First lock creation: A user locks 1000 tokens for 1 year.

  2. Second lock creation: The same user locks 2000 tokens for 1 year + 5 days.

  3. Expected behavior: If multiple locks were supported, the user should have two separate locks.

  4. Actual behavior: The second lock completely replaces the first one, overriding the amount, unlock time, and voting power.

  5. Verification: The PoC confirms this by logging the lock details and asserting that only the most recent lock remains.

Impact

  • Loss of locked funds: If a user mistakenly assumes multiple locks are supported, they could lose access to their previous lock.

  • Unexpected user experience: Users may believe they have multiple active locks when, in reality, only the most recent one remains.

Tools Used

  • Manual Review

Recommendations

  1. Prevent Overwriting: Before creating a new lock, check if the user already has an active lock.

    require(locks[msg.sender].amount == 0, "Existing lock must be withdrawn before creating a new one");
  2. Support Multiple Locks: Modify the contract to store locks in a mapping(address => Lock[]) to allow multiple simultaneous locks per user.

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.