Core Contracts

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

`veRAACToken::lock()` is missing a check to prevent user from relocking funds with different duration causing fund loss for users.

Vulnerability Details

veRAACToken::lock() has a missing check which prevents users from creating new lock positions with different amount & duration .
Due to this it is possible create more lock positions for lesser duration but when withdraw() is called after lock duration ends, only the most recently locked funds are recieved and calling withdraw() again reverts with LockNotFound()error and all previously locked tokens are lost for user.

PoC

//SETUP
function setUp() public {
vm.startPrank(deployer);
raactoken = new RAACToken(deployer, 100, 50); //from Js test setup
vetoken = new veRAACToken(address(raactoken));
raactoken.setMinter(deployer);
raactoken.mint(user, 10000);
raactoken.mint(address(vetoken), 10000);
assertEq(raactoken.balanceOf(user), 10000);
vm.stopPrank();
}
function test_lock() public {
vm.startPrank(user);
uint256 high_duration = 4 * 365 * 24 * 60 * 60; // 4years
uint256 low_duration = 365 * 24 * 60 * 60; // 1 year
//balances 10000 raactokens each
console.log("user bal", raactoken.balanceOf(user));
console.log("vetoken_contract bal", raactoken.balanceOf(address(vetoken)));
raactoken.approve(address(vetoken), 10000);
//lock raac in veraac
vetoken.lock(1000, high_duration);
console.log("First lock user bal", raactoken.balanceOf(user));
console.log("First lock vetoken_contract bal", raactoken.balanceOf(address(vetoken)));
//Lock again
vetoken.lock(1000, low_duration);
console.log("Second lock", raactoken.balanceOf(user));
console.log("Second lock vetoken_contract bal", raactoken.balanceOf(address(vetoken)));
//warp setup
uint256 timenow = vm.getBlockTimestamp();
uint256 four_Year_FutureTime = timenow + high_duration + 10;
uint256 one_Year_FutureTime = timenow + low_duration + 10;
//Withdraw() only withdraws most recent lock
vm.warp(one_Year_FutureTime);
vetoken.withdraw();
console.log("First Withdraw", raactoken.balanceOf(user));
console.log("First withdraw vetoken_contract bal", raactoken.balanceOf(address(vetoken)));
//Reverts and previously locked tokens are lost for user
//expect revert with LockNotFound()
vm.expectRevert();
vm.warp(four_Year_FutureTime);
vetoken.withdraw();
console.log("Second Withdraw", raactoken.balanceOf(user));
console.log("Second withdraw vetoken_contract bal", raactoken.balanceOf(address(vetoken)));
vm.stopPrank();
}

Impact

  • TimeLock in VeTokens lock() can be overriden.

  • Tokens are lost for users if they create multiple position.

  • Different Lock postions can be made with different amount and durations which will also affect functionality of voting Power calculation.

Recommendations

  • Prevent user from making multiple lock positions.

  • Prevent user from changing duration/amount without extend(),increase() functions

Updates

Lead Judging Commences

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