Core Contracts

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

Incorrect Handling of Minted Rewards in `RAACMinter` Leads to Transfer Failure

Summary

The RAACMinter contract contains a flaw in how it tracks and distributes minted rewards. The mintRewards function assumes that the contract holds the excessTokens balance. However, the tick function mints tokens directly to the stabilityPool instead of the contract. As a result, when mintRewards attempts to transfer the tokens, the safeTransfer call fails because the contract does not own the minted tokens.

Vulnerability Details

function mintRewards(address to, uint256 amount) external nonReentrant whenNotPaused {
if (msg.sender != address(stabilityPool)) revert OnlyStabilityPool();
uint256 toMint = excessTokens >= amount ? 0 : amount - excessTokens;
excessTokens = excessTokens >= amount ? excessTokens - amount : 0;
if (toMint > 0) {
raacToken.mint(address(this), toMint);
}
@> raacToken.safeTransfer(to, amount);
// @audit-issue if excess tokens were minted using tick, then the minted tokens
// will be owned by the stabilityPool and the safeTransfer function will revert
emit RAACMinted(amount);
}
function tick() external nonReentrant whenNotPaused {
if (emissionUpdateInterval == 0 || block.timestamp >= lastEmissionUpdateTimestamp + emissionUpdateInterval) {
updateEmissionRate();
}
uint256 currentBlock = block.number;
uint256 blocksSinceLastUpdate = currentBlock - lastUpdateBlock;
if (blocksSinceLastUpdate > 0) {
uint256 amountToMint = emissionRate * blocksSinceLastUpdate;
if (amountToMint > 0) {
excessTokens += amountToMint;
lastUpdateBlock = currentBlock;
@> raacToken.mint(address(stabilityPool), amountToMint);
emit RAACMinted(amountToMint);
}
}
}

Issue Breakdown

  1. In tick, new tokens are minted directly to stabilityPool:

    raacToken.mint(address(stabilityPool), amountToMint);

    This means the contract does not actually hold excessTokens, making the state inconsistent.

  2. In mintRewards, the function assumes that excessTokens are within the contract and attempts to transfer them:

    raacToken.safeTransfer(to, amount);

    If excessTokens originated from tick, they are held by stabilityPool, so the contract does not have enough balance, and safeTransfer reverts.

Impact

  • The mintRewards function fails if excessTokens originated from tick.

  • Users expecting rewards will not receive them, breaking reward distribution.

  • The system inconsistently tracks excessTokens, making the contract state unreliable.

Tools Used

Manual code review.

Recommendations

  1. Modify tick to mint tokens to this contract instead of stabilityPool:

    raacToken.mint(address(this), amountToMint);

    This ensures excessTokens are correctly accounted for and transferable by mintRewards.

  2. Alternatively, if tokens must be minted to stabilityPool, update mintRewards to pull tokens from stabilityPool:

    raacToken.transferFrom(stabilityPool, to, amount);

    This requires stabilityPool to approve transfers, adding complexity.

The first approach is cleaner and avoids unnecessary approvals while maintaining consistency in token ownership.

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACMinter wrong excessTokens accounting in tick function

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACMinter wrong excessTokens accounting in tick function

Support

FAQs

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

Give us feedback!