Skip to content

Commit

Permalink
feat: restrict ltv < LLTV
Browse files Browse the repository at this point in the history
  • Loading branch information
QGarchery committed Oct 4, 2024
1 parent 8c07dde commit e257eed
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 26 deletions.
11 changes: 5 additions & 6 deletions src/PreLiquidation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ contract PreLiquidation is IPreLiquidation, IMorphoRepayCallback {
// The following require is equivalent to checking that borrowed > collateralQuoted.wMulDown(PRE_LLTV).
require(ltv > PRE_LLTV, ErrorsLib.NotPreLiquidatablePosition());

uint256 preLIF = UtilsLib.min(
(ltv - PRE_LLTV).wDivDown(LLTV - PRE_LLTV).wMulDown(PRE_LIF_2 - PRE_LIF_1) + PRE_LIF_1, PRE_LIF_2
);
require(ltv <= LLTV, ErrorsLib.LiquidatablePosition());

uint256 preLIF = (ltv - PRE_LLTV).wDivDown(LLTV - PRE_LLTV).wMulDown(PRE_LIF_2 - PRE_LIF_1) + PRE_LIF_1;

if (seizedAssets > 0) {
uint256 seizedAssetsQuoted = seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE);
Expand All @@ -163,9 +163,8 @@ contract PreLiquidation is IPreLiquidation, IMorphoRepayCallback {

// Note that the pre-liquidation close factor can be greater than WAD (100%).
// In this case the position can be fully pre-liquidated.
uint256 preLCF = UtilsLib.min(
(ltv - PRE_LLTV).wDivDown(LLTV - PRE_LLTV).wMulDown(PRE_LCF_2 - PRE_LCF_1) + PRE_LCF_1, PRE_LCF_2
);
uint256 preLCF = (ltv - PRE_LLTV).wDivDown(LLTV - PRE_LLTV).wMulDown(PRE_LCF_2 - PRE_LCF_1) + PRE_LCF_1;

uint256 repayableShares = uint256(position.borrowShares).wMulDown(preLCF);
require(repaidShares <= repayableShares, ErrorsLib.PreLiquidationTooLarge(repaidShares, repayableShares));

Expand Down
2 changes: 2 additions & 0 deletions src/libraries/ErrorsLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ library ErrorsLib {

error NotPreLiquidatablePosition();

error LiquidatablePosition();

error PreLiquidationTooLarge(uint256 repaidShares, uint256 repayableShares);

error NotMorpho();
Expand Down
18 changes: 6 additions & 12 deletions test/BaseTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -136,21 +136,15 @@ contract BaseTest is Test {
view
returns (uint256)
{
return UtilsLib.min(
(ltv - preLiquidationParams.preLltv).wDivDown(marketParams.lltv - preLiquidationParams.preLltv).wMulDown(
preLiquidationParams.preLCF2 - preLiquidationParams.preLCF1
) + preLiquidationParams.preLCF1,
preLiquidationParams.preLCF2
);
return (ltv - preLiquidationParams.preLltv).wDivDown(marketParams.lltv - preLiquidationParams.preLltv).wMulDown(
preLiquidationParams.preLCF2 - preLiquidationParams.preLCF1
) + preLiquidationParams.preLCF1;
}

function _preLIF(PreLiquidationParams memory preLiquidationParams, uint256 ltv) internal view returns (uint256) {
return UtilsLib.min(
(ltv - preLiquidationParams.preLltv).wDivDown(marketParams.lltv - preLiquidationParams.preLltv).wMulDown(
preLiquidationParams.preLIF2 - preLiquidationParams.preLIF1
) + preLiquidationParams.preLIF1,
preLiquidationParams.preLIF2
);
return (ltv - preLiquidationParams.preLltv).wDivDown(marketParams.lltv - preLiquidationParams.preLltv).wMulDown(
preLiquidationParams.preLIF2 - preLiquidationParams.preLIF1
) + preLiquidationParams.preLIF1;
}

function _getBorrowBounds(
Expand Down
12 changes: 6 additions & 6 deletions test/PreLiquidationErrorTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ contract PreLiquidationErrorTest is BaseTest {
preLiqOracle: marketParams.oracle
});

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.PreLltvTooHigh.selector));
vm.expectRevert(ErrorsLib.PreLltvTooHigh.selector);
factory.createPreLiquidation(id, preLiquidationParams);
}

Expand All @@ -53,7 +53,7 @@ contract PreLiquidationErrorTest is BaseTest {
});
preLiquidationParams.preLCF2 = bound(preLiquidationParams.preLCF2, 0, preLiquidationParams.preLCF1 - 1);

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.PreLCFDecreasing.selector));
vm.expectRevert(ErrorsLib.PreLCFDecreasing.selector);
factory.createPreLiquidation(id, preLiquidationParams);
}

Expand All @@ -69,7 +69,7 @@ contract PreLiquidationErrorTest is BaseTest {
preLiqOracle: marketParams.oracle
});

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.PreLIFTooLow.selector));
vm.expectRevert(ErrorsLib.PreLIFTooLow.selector);
factory.createPreLiquidation(id, preLiquidationParams);
}

Expand All @@ -87,7 +87,7 @@ contract PreLiquidationErrorTest is BaseTest {
preLiquidationParams.preLIF2 =
bound(preLiquidationParams.preLIF2, WAD.wDivDown(marketParams.lltv) + 1, type(uint256).max);

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.PreLIFTooHigh.selector));
vm.expectRevert(ErrorsLib.PreLIFTooHigh.selector);
factory.createPreLiquidation(id, preLiquidationParams);
}

Expand All @@ -105,12 +105,12 @@ contract PreLiquidationErrorTest is BaseTest {

preLiquidationParams.preLIF2 = bound(preLiquidationParams.preLIF2, WAD, preLiquidationParams.preLIF1 - 1);

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.PreLIFDecreasing.selector));
vm.expectRevert(ErrorsLib.PreLIFDecreasing.selector);
factory.createPreLiquidation(id, preLiquidationParams);
}

function testNonexistentMarket(PreLiquidationParams memory preLiquidationParams) public virtual {
vm.expectRevert(abi.encodeWithSelector(ErrorsLib.NonexistentMarket.selector));
vm.expectRevert(ErrorsLib.NonexistentMarket.selector);
factory.createPreLiquidation(Id.wrap(bytes32(0)), preLiquidationParams);
}

Expand Down
46 changes: 44 additions & 2 deletions test/PreLiquidationTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,48 @@ contract PreLiquidationTest is BaseTest, IPreLiquidationCallback {
factory = new PreLiquidationFactory(address(MORPHO));
}

function testPreLiquidationLiquidatable(
PreLiquidationParams memory preLiquidationParams,
uint256 collateralAmount,
uint256 borrowAmount,
uint256 newPrice
) public virtual {
preLiquidationParams = boundPreLiquidationParameters({
preLiquidationParams: preLiquidationParams,
minPreLltv: WAD / 2,
maxPreLltv: marketParams.lltv - 1,
minPreLCF: WAD / 100,
maxPreLCF: WAD,
minPreLIF: WAD,
maxPreLIF: WAD.wDivDown(lltv),
preLiqOracle: marketParams.oracle
});

collateralAmount = bound(collateralAmount, minCollateral, maxCollateral);
(uint256 collateralQuoted, uint256 borrowPreLiquidationThreshold, uint256 borrowLiquidationThreshold) =
_getBorrowBounds(preLiquidationParams, marketParams, collateralAmount);
borrowAmount = bound(borrowAmount, borrowPreLiquidationThreshold + 1, borrowLiquidationThreshold);

_preparePreLiquidation(preLiquidationParams, collateralAmount, borrowAmount, LIQUIDATOR);

uint256 ltv = borrowAmount.wDivUp(collateralQuoted);
uint256 prevPrice = oracle.price();
newPrice = bound(newPrice, prevPrice / 10, prevPrice.wDivDown(marketParams.lltv).wMulDown(ltv));
oracle.setPrice(newPrice);

uint256 newLtv = borrowAmount.wDivUp(collateralAmount.mulDivDown(newPrice, ORACLE_PRICE_SCALE));
vm.assume(newLtv > marketParams.lltv);

vm.startPrank(LIQUIDATOR);
Position memory position = MORPHO.position(id, BORROWER);

uint256 closeFactor = _closeFactor(preLiquidationParams, newLtv);
uint256 repayableShares = uint256(position.borrowShares).wMulDown(closeFactor);

vm.expectRevert(ErrorsLib.LiquidatablePosition.selector);
preLiquidation.preLiquidate(BORROWER, 0, repayableShares, hex"");
}

function testPreLiquidationShares(
PreLiquidationParams memory preLiquidationParams,
uint256 collateralAmount,
Expand Down Expand Up @@ -191,7 +233,7 @@ contract PreLiquidationTest is BaseTest, IPreLiquidationCallback {

vm.startPrank(LIQUIDATOR);

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.NotPreLiquidatablePosition.selector));
vm.expectRevert(ErrorsLib.NotPreLiquidatablePosition.selector);
preLiquidation.preLiquidate(BORROWER, 0, 1, hex"");

vm.warp(block.timestamp + 12);
Expand Down Expand Up @@ -249,7 +291,7 @@ contract PreLiquidationTest is BaseTest, IPreLiquidationCallback {

vm.startPrank(LIQUIDATOR);

vm.expectRevert(abi.encodeWithSelector(ErrorsLib.NotPreLiquidatablePosition.selector));
vm.expectRevert(ErrorsLib.NotPreLiquidatablePosition.selector);
preLiquidation.preLiquidate(BORROWER, 0, 1, hex"");
}
}

0 comments on commit e257eed

Please sign in to comment.