Summary
The tick()
function in RAACMinter.sol
does following :-
| Triggers the minting process and updates the emission rate if the interval has passed
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 problem is that if lastUpdateBlock
is reset to less value as it was originally, by calling setLastUpdateBlock()
by admin. extra minting of tokens to stability pool will occur, due to block/ block number overlap. Let's analyse.
In this duration
tokens minted twice.
| |
t1 t2 | t3 t4
|--------------------------|-------------|------------|--------------------|
block.number[t1] block.number[t2] | block.number[t3] block.number[t4]
|
block.number[<t3]
tick() function can be called at t1, t2, t3, t4.
where, t1, t2, t3, t4 are block.timestamps representing lastEmissionUpdateTimestamp.
At time t3.
uint256 blocksSinceLastUpdate = currentBlock - lastUpdateBlock;
The blockSinceLastUpdate = block.number[t3] - block.number[t2] = X
At time t4. [Typical case]
uint256 blocksSinceLastUpdate = currentBlock - lastUpdateBlock;
The blockSinceLastUpdate_1 = block.number[t4] - block.number[t3] = Y
Suppose admin updates the lastUpdateBlock value less then block.number[t3], let's call
it block.number[<t3], by executing setLastUpdateBlock(<t3) or emergencyShutdown() function.
Now at time t4, [Buggy case]
the blockSinceLastUpdate_2 = block.number[t4] - block.number[<t3] = Z
clearly, Z > Y
Tokens has been minted for X.
Now tokens will be minted from block.number[<t3] - block.number[t4].
The problem is that raacTokens are minted again for block duration between block.number[<t3] and block.number[t3].
So extra tokens is being minted to stability pool.
Vulnerability Details
Similar to summary section.
Impact
Extra tokens is being minted to stability pool.
Inside stability pool contract there is function calculateRaacRewards()
to calculate raac rewards, -
function calculateRaacRewards(address user) public view returns (uint256) {
uint256 userDeposit = userDeposits[user];
uint256 totalDeposits = deToken.totalSupply();
uint256 totalRewards = raacToken.balanceOf(address(this));
if (totalDeposits < 1e6) return 0;
@-> return (totalRewards * userDeposit) / totalDeposits;
}
Tools Used
Manual
Recommendations
Implement a functionality such that if there is block number overlap, or reward minted 2 ice for certain duration, then burn those extra minted raac tokens.