If the time passed and multiple deposits were done, if the user tries to repay all the debt, some scaledDebtBalance would be left, which wouldn't allow to withdraw the NFt
pragma solidity ^0.8.19;
import {Test, console} from "lib/forge-std/src/Test.sol";
import "contracts/core/pools/LendingPool/LendingPool.sol";
import "contracts/core/tokens/RToken.sol";
import "contracts/core/tokens/DebtToken.sol";
import "contracts/core/tokens/RAACNFT.sol";
import "contracts/core/tokens/RAACToken.sol";
import "contracts/core/minters/RAACMinter/RAACMinter.sol";
import "contracts/core/pools/StabilityPool/StabilityPool.sol";
import "contracts/core/pools/StabilityPool/StabilityPool.sol";
interface ITokenERC20{
function approve(address spender, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract ArsenTest is Test{
RToken public rToken;
DebtToken public dToken;
RAACNFT public raacNFT;
RAACToken public raacToken;
RAACMinter public raacMinter;
HousePrices public housePrices;
PriceOracle public priceOracle;
LendingPool public lendingPool;
StabilityPool public stabilityPool;
address public attacker = address(8888);
address public user_1 = address(1111);
address public user_2 = address(2222);
address CRV_USD = address(0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E);
string ETH_RPC_URL = "https://mainnet.infura.io/v3/2cef90f9f3f44a1fb5201d8547183d42";
function setUp() public{
uint256 ethFork = vm.createFork(ETH_RPC_URL);
vm.selectFork(ethFork);
housePrices = new HousePrices();
priceOracle = new PriceOracle();
rToken = new RToken(
"rToken",
"RTOKEN",
address(this),
CRV_USD
);
dToken = new DebtToken(
"Debt Token",
"DBTTOKEN",
address(this)
);
raacNFT = new RAACNFT(
CRV_USD,
address(housePrices),
address(this)
);
raacToken = new RAACToken(
address(this),
500,
500
);
lendingPool = new LendingPool(
CRV_USD,
address(rToken),
address(dToken),
address(raacNFT),
address(priceOracle),
100000000000000000000000000
);
stabilityPool = new StabilityPool(address(this));
raacMinter = new RAACMinter(
address(raacToken),
address(stabilityPool),
address(lendingPool),
address(this)
);
stabilityPool.initialize(
address(rToken),
address(dToken),
address(raacToken),
address(raacMinter),
CRV_USD,
address(lendingPool)
);
rToken.setReservePool(address(lendingPool));
dToken.setReservePool(address(lendingPool));
}
function test_deposit() public{
deal(CRV_USD, attacker, 1_000_000e18);
vm.startPrank(attacker);
ITokenERC20(CRV_USD).approve(address(lendingPool), 1_000_000e18);
lendingPool.deposit(1_000_000e18);
assertEq(ITokenERC20(CRV_USD).balanceOf(address(rToken)), 1_000_000e18);
assertEq(rToken.balanceOf(attacker), 1_000_000e18);
vm.stopPrank();
deal(CRV_USD, user_1, 10_000e18);
vm.startPrank(user_1);
ITokenERC20(CRV_USD).approve(address(raacNFT), 10_000e18);
raacNFT.mint(1, 10_000e18);
raacNFT.approve(address(lendingPool), 1);
lendingPool.depositNFT(1);
vm.stopPrank();
vm.startPrank(user_1);
lendingPool.borrow(10_000e18);
assertEq(dToken.balanceOf(user_1), 10_000e18);
vm.stopPrank();
for(uint i = 2; i < 50; i++){
address user = vm.addr(i);
deal(CRV_USD, user, 10_000e18);
vm.startPrank(user);
ITokenERC20(CRV_USD).approve(address(raacNFT), 10_000e18);
raacNFT.mint(i, 10_000e18);
raacNFT.approve(address(lendingPool), i);
lendingPool.depositNFT(i);
lendingPool.borrow(10_000e18);
vm.stopPrank();
}
vm.warp(block.timestamp + 365 days);
lendingPool.updateState();
vm.startPrank(user_1);
ITokenERC20(CRV_USD).approve(address(lendingPool), 10_000e18);
lendingPool.repay(10_000e18);
vm.stopPrank();
assertEq(ITokenERC20(CRV_USD).balanceOf(user_1), 0);
assertGt(dToken.balanceOf(user_1), 60e18);
vm.prank(user_1);
vm.expectRevert();
lendingPool.withdrawNFT(1);
}
}
contract HousePrices{
function tokenToHousePrice(uint256 _tokenId) external view returns (uint256){
return 10_000e18;
}
}
contract PriceOracle{
function getLatestPrice(uint256 _tokenId) external view returns (uint256, uint256){
return(10_000e18, block.timestamp);
}
}