Core Contracts

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

veRAACToken#lock() no check for a very small amount.

Severity: Medium

Impact: Medium

Likelihood: Medium

Summary

In the case a user will call lock() with a dust amout, and a minimum duration then he will not get a veTokens at all.

Description

The function lock() can accept a dust amount and the duration 365 days.

2025-02-raac/contracts/core/tokens/veRAACToken.sol at 89ccb062e2b175374d40d824263a4c0b601bcb7f · Cyfrin/2025-02-raac · GitHub

function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
if (amount == 0) revert InvalidAmount();
if (amount > MAX_LOCK_AMOUNT) revert AmountExceedsLimit();
if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
if (duration < MIN_LOCK_DURATION || duration > MAX_LOCK_DURATION)
revert InvalidLockDuration();
// Do the transfer first - this will revert with ERC20InsufficientBalance if user doesn't have enough tokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
// Calculate unlock time
uint256 unlockTime = block.timestamp + duration;
// Create lock position
_lockState.createLock(msg.sender, amount, duration);
_updateBoostState(msg.sender, amount);
// Calculate initial voting power
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
msg.sender,
amount,
unlockTime
);
// Update checkpoints
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Mint veTokens
_mint(msg.sender, newPower);
emit LockCreated(msg.sender, amount, unlockTime);
}

Then calculateAndUpdatePower() will calculate values for bias and slope as a zero.

2025-02-raac/contracts/libraries/governance/VotingPowerLib.sol at 89ccb062e2b175374d40d824263a4c0b601bcb7f · Cyfrin/2025-02-raac · GitHub

function calculateAndUpdatePower(
VotingPowerState storage state,
address user,
uint256 amount,
uint256 unlockTime
) internal returns (int128 bias, int128 slope) {
if (amount == 0 || unlockTime <= block.timestamp) revert InvalidPowerParameters();
uint256 MAX_LOCK_DURATION = 1460 days; // 4 years
// FIXME: Get me to uncomment me when able
// bias = RAACVoting.calculateBias(amount, unlockTime, block.timestamp);
// slope = RAACVoting.calculateSlope(amount);
// Calculate initial voting power that will decay linearly to 0 at unlock time
uint256 duration = unlockTime - block.timestamp;
uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION; // Normalize by max duration
bias = int128(int256(initialPower));
slope = int128(int256(initialPower / duration)); // Power per second decay
uint256 oldPower = getCurrentPower(state, user, block.timestamp);
state.points[user] = RAACVoting.Point({
bias: bias,
slope: slope,
timestamp: block.timestamp
});
_updateSlopeChanges(state, unlockTime, 0, slope);
emit VotingPowerUpdated(user, oldPower, uint256(uint128(bias)));
return (bias, slope);
}

initialPower will be calculated as a zero, as well as bias and slope. Then in the lock() a newPower will be zero and the user will receive no tokens.

// Mint veTokens
_mint(msg.sender, newPower);

Impact

The case when a user can send very small amount is uncommon. But this case must be considered otherwise user lose his funds and this will affect the contract reputation.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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