The RAACMinter contract mints RAAC tokens in two different ways:
In the tick() function, tokens are minted directly to the StabilityPool address while the contract’s internal variable excessTokens is incremented.
In the mintRewards() function, tokens are expected to be available in the RAACMinter’s own balance (or minted there if insufficient) so they can be transferred as rewards.
Because tokens minted in tick() never reside in RAACMinter’s balance (they go directly to StabilityPool), the internal accounting via excessTokens becomes inconsistent. Consequently, when mintRewards() is later invoked, the RAACMinter may attempt a transfer from an empty balance or mint additional tokens unnecessarily, leading to reward distribution anomalies.
Token Minting Mismatch:
Tick Process:
The tick() function computes an amount to mint and calls:
It then increases the internal excessTokens by amountToMint.
Reward Distribution:
Later, when the StabilityPool (authorized caller) invokes mintRewards(), the function uses excessTokens to decide whether to mint additional tokens and then calls:
However, since RAACMinter’s own balance wasn’t increased (the minted tokens reside at the StabilityPool), the transfer fails or triggers additional minting.
Exploitation Impact:
This inconsistency may lead to double-minting or reward transfers failing because the RAACMinter contract does not hold the tokens it believes it has “available” per its excessTokens variable.
Below is a fully working Foundry test that demonstrates the issue:
Fix:
Have both functions mint tokens to the same address—ideally the RAACMinter contract itself—so that the internal excessTokens variable correctly reflects tokens available for distribution. In short, change the destination in tick() from address(stabilityPool) to address(this).
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.