Core Contracts

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

Inconsistent token minting between RAACMinter.tick() and RAACMinter.mintRewards()

Minting of RAAC token can be triggered within certain intervals through tick which mints to the stability pool according to the emission rate and updates the excessTokens held by the contract.

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/minters/RAACMinter/RAACMinter.sol#L271

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);
}
}
}

The issue is that the token is minted to stabilityPool but excessTokens counter assumes the token is held by the contract itself.

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/minters/RAACMinter/RAACMinter.sol#L191

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);
emit RAACMinted(amount);
}

when mintRewards is invoked it check if the contract has enough amount(excessTokens) if not it mints additional token to add up but the excessToken is not held by the contract itself making the call to safeTransfer to revert.

Impact

MintRewards would revert due to inconsistent state

Recommendation

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);
+ raacToken.mint(address(this), amountToMint);
emit RAACMinted(amountToMint);
}
}
}
Updates

Lead Judging Commences

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

RAACMinter wrong excessTokens accounting in tick function

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