Core Contracts

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

Incorrect Duration Parameter Interpretation Can Lead to Unintended Lock Extensions in extend::veRAACToken

Finding Description and Impact

extend() :: veRAACToken takes a newDuration parameter, which, based on its description, seems to represent the total lock duration. However, the extendLock() :: LockManager function, which it calls, expects an incremental extension duration (i.e., how much additional time should be added to the existing lock).

This mismatch can cause unintended behavior:

  • If a user inputs newDuration as the total desired lock duration, the function will incorrectly extend the lock longer than intended.

  • If the calculated total lock duration exceeds maxLockDuration, the transaction will revert unexpectedly, even if the user intended a valid extension.

  • This logic flaw can lead to a poor user experience and potential loss of voting power due to failed extensions.

Snippet from Documentation and Relevant Code

From the offical documents of the protocol, one would assume that the function accepts a new total lock duration, instead of a incremental value as required...

extend() function

Again from the NatSpec it would seem a new total lock duration is required...

/**
* @notice Extends the duration of an existing lock
* @dev Increases the lock duration which results in updated voting power
* @param newDuration The new total duration extension for the lock, in seconds -
*/
function extend(uint256 newDuration) external nonReentrant whenNotPaused {
// Extend lock using LockManager
uint256 newUnlockTime = _lockState.extendLock(msg.sender, newDuration); // @audit this passes the new duration

  • Here, newDuration is passed directly to extendLock().

extendLock() function

function extendLock(
LockState storage state,
address user,
uint256 extensionDuration
) internal returns (uint256 newEnd) {
Lock storage lock = state.locks[user];
if (!lock.exists) revert LockNotFound();
if (lock.end <= block.timestamp) revert LockExpired();
uint256 remainingDuration = lock.end - block.timestamp;
uint256 totalNewDuration = remainingDuration + extensionDuration; // Misinterpretation issue
if (totalNewDuration > state.maxLockDuration) revert InvalidLockDuration();
newEnd = block.timestamp + totalNewDuration;
lock.end = newEnd;
emit LockExtended(user, newEnd);
return newEnd;
}

  • The function adds extensionDuration to the remaining duration, assuming it’s an increment, not the total duration.

  • If extend() provides a total lock duration, extendLock() will overextend the lock unexpectedly.

Example of Unexpected Behavior

  1. Assume:

    • lock.end = block.timestamp + 1 year

    • maxLockDuration = 4 years

  2. User calls extend(3 years), expecting the lock to be extended to 3 years from now.

  3. extendLock() misinterprets 3 years as an additional extension, not a total duration.

  4. New lock end time becomes 4 years from now instead of 3 years.

  5. If the lock was already 3 years, this would incorrectly exceed maxLockDuration, causing a reversion.

Recommended Mitigation Steps

  • Clarify Documentation: Update the extend() function’s description to specify that it expects an incremental duration, not a total duration.

  • Adjust Parameter Naming: Rename newDuration to extensionDuration in extend() to prevent confusion.

This fix will prevent unintended lock extensions and improve user experience by ensuring the intended duration is applied correctly.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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