Description:
The function `RaacMinter:tick` increments the excessTokens count. This tokens will be discounted from the total to mint in the `RaacMinter:mintRewards` and transfered to the reciver. The proble is that the funcion `tick` do not mint the tokens in the `RaacMinter`, it's minting it in the `StabilityPool` and they are never transfered to the `RaacMinter`.
Impact:
If there are excees Tokens, the function `RaacMinter:mintRewards` will always revert with `ERC20 Insufficient Balance`, because tokens are owner by the `StabilityPool`.
Proof of Concept:
**Here are the steps to run the Foundry PoC:**
<details><sumarry>Proof of Code</summary>
1. Open the `linux terminal`, `wsl` in windows.
2. `nomicfoundation` installation:
- If you have `npm` installed run this command:
- `npm install --save-dev @nomicfoundation/hardhat-foundry`
- If you have `yarn` installed run this command:
- `yarn add --dev @nomicfoundation/hardhat-foundry`
- If you have `pnpm` installed run this command:
- `pnpm add --save-dev @nomicfoundation/hardhat-foundry`
3. open the `hardhat.config.cjs`
- Paste this at the begining of the code:
- `require("@nomicfoundation/hardhat-foundry");`
4. run `npx hardhat init-foundry`
- This task will create a `foundry.toml` file with the right configuration and install `forge-std`
5. In the `test/` forlder create a new folder called `ProofOfCodes`
6. In this `test/ProofOfCodes` folder create a new file and paste the following code
7. To run the test you should run `forge test --mt test_exessTokenBalanceIsAlwaysZeroAndUserWontReciveThem -vvvv`
<details><summary>NOTE</summary>
Just for the sake of simplifying the test, I paste this function in the RaacMinter, which is doing exactly the same thing as the tick function by minting tokens and adding excess tokens.
```solidity
function getSomeExessBalance(uint256 amountToMint) external {
excessTokens += amountToMint;
lastUpdateBlock = block.number;
raacToken.mint(address(stabilityPool), amountToMint);
}
```
add this function to the end of the contract.
</details>
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test,console2} from "lib/forge-std/src/Test.sol";
import {DebtToken} from "contracts/core/tokens/DebtToken.sol";
import {LendingPool} from "contracts/core/pools/LendingPool/LendingPool.sol";
import {StabilityPool} from "contracts/core/pools/StabilityPool/StabilityPool.sol";
import {RAACMinter} from "contracts/core/minters/RAACMinter/RAACMinter.sol";
import {RAACToken} from "contracts/core/tokens/RAACToken.sol";
import {RToken} from "contracts/core/tokens/RToken.sol";
import {RAACNFT} from "contracts/core/tokens/RAACNFT.sol";
import {RAACHousePrices} from "contracts/core/primitives/RAACHousePrices.sol";
import {ERC20Mock, ERC20} from "contracts/mocks/core/tokens/ERC20Mock.sol";
contract RAACMinterPoC is Test {
StabilityPool stabilityPool;
RAACMinter raacMinter;
RAACToken raacToken;
ERC20Mock crvUsdMock;
RToken rToken;
RAACHousePrices housePrices;
RAACNFT raacNft;
LendingPool reservePool;
DebtToken debtToken;
address initialOwner = makeAddr("initalOwner");
address reciver = makeAddr("reciver");
function setUp() external {
vm.roll(block.number + 100);
vm.warp(block.timestamp + 10 days);
crvUsdMock = new ERC20Mock("crv", "crv");
housePrices = new RAACHousePrices(initialOwner);
raacNft = new RAACNFT(address(crvUsdMock), address(housePrices), initialOwner);
debtToken = new DebtToken("DebtToken", "DT", initialOwner);
rToken = new RToken("RToken", "RT", initialOwner, address(crvUsdMock));
reservePool = new LendingPool(address(crvUsdMock), address(rToken), address(debtToken), address(raacNft), address(housePrices), 1);
stabilityPool = new StabilityPool(initialOwner);
raacToken = new RAACToken(initialOwner, 0, 0);
raacMinter = new RAACMinter(address(raacToken), address(stabilityPool), address(reservePool), initialOwner);
vm.startPrank(initialOwner);
raacToken.setMinter(address(raacMinter));
raacMinter.setStabilityPool(address(stabilityPool));
vm.stopPrank();
}
function test_exessTokenBalanceIsAlwaysZeroAndUserWontReciveThem() external {
vm.roll(block.number + 10);
vm.warp(block.timestamp + 1 days);
raacMinter.getSomeExessBalance(1e18);
assert(raacMinter.getExcessTokens() > 0);
vm.prank(address(stabilityPool));
vm.expectRevert();
raacMinter.mintRewards(reciver, 10e18);
}
}
```
</details>
Recommended Mitigation:
1. Delete the excess tokens functionality and mint always the amount to mint.
2. Mint the tokens to the RAACMinter and update StabilityPool logic.
3. Make some mintRewards function in the stability pool where call this funcion and approve the excess balance.