pragma solidity 0.8.20;
import { Test } from "forge-std/Test.sol";
import { ThunderLoan } from "../../src/protocol/ThunderLoan.sol";
import { AssetToken } from "../../src/protocol/AssetToken.sol";
import { ERC20Mock } from "@openzeppelin/contracts/mocks/ERC20Mock.sol";
import { MockPoolFactory } from "../../test/mocks/MockPoolFactory.sol";
import { MockFlashLoanReceiver } from "../../test/mocks/MockFlashLoanReceiver.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract ExchangeRateUnitMismatchPoC is Test {
ThunderLoan private thunderLoan;
MockPoolFactory private poolFactory;
ERC20Mock private token;
MockFlashLoanReceiver private receiver;
address private lp = address(0x3333);
function setUp() public {
ThunderLoan impl = new ThunderLoan();
poolFactory = new MockPoolFactory();
token = new ERC20Mock();
poolFactory.createPool(address(token));
ERC1967Proxy proxy = new ERC1967Proxy(address(impl), "");
thunderLoan = ThunderLoan(address(proxy));
thunderLoan.initialize(address(poolFactory));
vm.prank(thunderLoan.owner());
thunderLoan.setAllowedToken(token, true);
receiver = new MockFlashLoanReceiver(address(thunderLoan));
}
function testExchangeRateDriftsAboveBackingAfterMultipleFees() public {
uint256 depositAmount = 100e18;
uint256 amountBorrow = 100e18;
token.mint(lp, depositAmount);
vm.startPrank(lp);
token.approve(address(thunderLoan), depositAmount);
thunderLoan.deposit(token, depositAmount);
vm.stopPrank();
token.mint(address(receiver), 10e18);
thunderLoan.flashloan(address(receiver), token, amountBorrow, "");
thunderLoan.flashloan(address(receiver), token, amountBorrow, "");
AssetToken asset = thunderLoan.getAssetFromToken(token);
uint256 expectedRate =
(token.balanceOf(address(asset)) * asset.EXCHANGE_RATE_PRECISION()) / asset.totalSupply();
uint256 actualRate = asset.getExchangeRate();
assertGt(actualRate, expectedRate);
}
}