Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed LI-CF PreLiquidation #1

Merged
merged 192 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 191 commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
1404b08
feat: initial commit
peyha Aug 29, 2024
9f84b3e
fix: stack too deep
peyha Aug 30, 2024
4536541
fix: handle empty callback
peyha Aug 30, 2024
14637df
fix: correct callback arg
peyha Aug 30, 2024
8db8b63
feat: first tests
peyha Aug 30, 2024
3d40d22
forge install: solmate
peyha Aug 30, 2024
65dd2b9
feat: use solmate erc20 lib
peyha Aug 30, 2024
675ce0d
fix: remove unused arg
peyha Aug 30, 2024
afc0f96
style: adapt linter
peyha Aug 30, 2024
e273bc6
style: rename variable
peyha Aug 30, 2024
282763c
doc: natspec
peyha Aug 30, 2024
b0cc6cc
feat: licence
peyha Aug 30, 2024
738e3d3
style: linter
peyha Aug 30, 2024
c942d2c
fix: variable name
peyha Aug 30, 2024
e36f99d
doc: natspec for accrueInterest
peyha Sep 2, 2024
cbfa384
feat: move isValid attribue to SubscriptionParams
peyha Sep 2, 2024
8f06d8f
chore: run forge fmt
QGarchery Sep 3, 2024
a0a598c
refactor: simplify CI
QGarchery Sep 3, 2024
26ff870
chore: use consistent naming for ci file
QGarchery Sep 3, 2024
e9af672
refactor: use camel case for test names
QGarchery Sep 3, 2024
4cc9e14
refactor: test contract naming
QGarchery Sep 3, 2024
bd87eac
refactor: store IMorpho directly
QGarchery Sep 3, 2024
6982647
refactor: remove borrower and market id from params
QGarchery Sep 3, 2024
968785a
feat: remove auto-unsubscribe in liquidate
peyha Sep 2, 2024
2643e33
fix: callback calls liquidator instead of msg.sender
peyha Sep 2, 2024
5577356
feat: improve SubscriptionParams for gas opti
peyha Sep 3, 2024
a40be1b
feat: implement events
peyha Sep 3, 2024
692849a
fix: setup CI RPC
QGarchery Sep 3, 2024
730cb9d
chore: use createSelectFork
QGarchery Sep 3, 2024
925b873
fix: import ALCHEMY_KEY secret
QGarchery Sep 3, 2024
32c12d9
refactor: remove key length
QGarchery Sep 3, 2024
bdb7078
refactor: remove isValid flag
QGarchery Sep 3, 2024
98acabd
feat: accrue interest on morpho in liquidate
peyha Sep 3, 2024
0735a2d
feat: use public mapping
peyha Sep 3, 2024
2a87359
refactor: use nbSubscription again
QGarchery Sep 3, 2024
30db15d
refactor: only check close factor for validity
QGarchery Sep 3, 2024
f162395
refactor: use computeSubscriptionId
QGarchery Sep 3, 2024
f9d6b45
fix: complete Unsubscribe event
QGarchery Sep 3, 2024
171ed69
feat: require morpho as sender in repay callback
peyha Sep 4, 2024
16655cf
feat: use subscriptionId in Liquidate event
peyha Sep 4, 2024
27e6d3c
feat: remove bad debt parameter from Liquidate
peyha Sep 4, 2024
3ef9ca5
feat: implement constructor to pass morpho address
peyha Sep 4, 2024
aadb464
feat: remove repaidAssets from liquidate
peyha Sep 4, 2024
8e8b5ba
style: forge fmt
peyha Sep 4, 2024
f41c875
fix: trim subscription params
QGarchery Sep 5, 2024
5e23835
Merge pull request #5 from morpho-org/fix/trim-subscription-params
peyha Sep 5, 2024
5ce2b2e
feat: require close factor on borrow shares instead of collateral
peyha Sep 5, 2024
c234e35
refactor: rename slltv into prelltv
peyha Sep 6, 2024
41e3906
fix: close factor require condition
peyha Sep 6, 2024
9f5e68e
feat: change indexed event for Liquidate
peyha Sep 6, 2024
1a03539
refactor: newline
peyha Sep 6, 2024
a3827af
fix: stack too deep
peyha Sep 6, 2024
946f2cc
refactor: increment trick
peyha Sep 6, 2024
76f228e
feat: use marketParams in subscribe for gas opti
peyha Sep 6, 2024
e80f558
feat: factorize market id
peyha Sep 6, 2024
59b1210
feat: replace OZ IERC20 by Solmate ERC20
peyha Sep 6, 2024
3a42f44
feat: use custom errors with solidity 0.8.27
peyha Sep 6, 2024
d7e9229
feat: improve refactor of market id
peyha Sep 6, 2024
7553359
refactor: rename assets into repaidAssets
QGarchery Sep 8, 2024
6a645a6
fix: complete rename of slltv into prelltv
QGarchery Sep 8, 2024
4a67f67
refactor: one slot storage
QGarchery Sep 8, 2024
d2685dc
refactor: add parameter name to errors
QGarchery Sep 8, 2024
073b145
refactor: public to external when not needed
QGarchery Sep 8, 2024
0427c95
refactor: consistent parameter order for events
QGarchery Sep 8, 2024
dd4b492
refactor: a couple of renaming
QGarchery Sep 8, 2024
ac751bc
refactor: remove subscriptionId from errors
QGarchery Sep 9, 2024
b4b76aa
chore: remove subscriptionId from errors in tests
QGarchery Sep 9, 2024
1ff45cd
refactor: improve errors
peyha Sep 9, 2024
8591e9e
Merge branch 'feat/licence' into refactor/single-storage
peyha Sep 9, 2024
f5548d8
style: forge fmt
peyha Sep 9, 2024
faea158
fix: check invalid subscription using boolean array
peyha Sep 9, 2024
e07360c
Merge pull request #6 from morpho-org/refactor/single-storage
peyha Sep 9, 2024
abce0a0
feat: implement ILiquidationProtection
peyha Sep 10, 2024
d1ecbba
feat: implement factory contract
peyha Sep 10, 2024
ca8bdba
refactor: change variable name in test
peyha Sep 10, 2024
97eb391
feat: implement CreateSubscription event
peyha Sep 10, 2024
7fa0cd3
feat: approve morpho at contract creation
peyha Sep 10, 2024
8b1168a
refactor: remove unused arg
peyha Sep 10, 2024
3da07b1
style: rename variable and function
peyha Sep 10, 2024
f3f65ae
feat: implement factory interface
peyha Sep 10, 2024
285338f
refactor: import
peyha Sep 10, 2024
7cfeb90
style: renaming
peyha Sep 11, 2024
9942b46
test: remove fork in test and redeploy contracts from scratch
peyha Sep 11, 2024
e1a4dee
feat: immutable market id
peyha Sep 11, 2024
17f1e59
refactor: remove unused arg
peyha Sep 11, 2024
cdff984
feat: implement mapping in factory
peyha Sep 11, 2024
5e1ca49
feat: deconstruct subscription params for immutability
peyha Sep 11, 2024
91c2c05
feat: deconstruct market params for immutability
peyha Sep 12, 2024
cff7db6
feat: use getPreLiquidationid as pure fn
peyha Sep 12, 2024
c7a4dbb
style: rename LiquidationTooLarge error
peyha Sep 12, 2024
a533cf6
style: rename HealthyPosition error to NotPreLiquidatablePosition
peyha Sep 12, 2024
574546b
style: rename liquidationIncentive
peyha Sep 12, 2024
10ac40d
refactor: little improvements
MathisGD Sep 12, 2024
e48f9cc
Merge branch 'feat/factory' into refactor/small-improvements
peyha Sep 13, 2024
e52f4e0
Merge pull request #11 from morpho-org/refactor/small-improvements
peyha Sep 13, 2024
01fc6ea
style: rename liquidationIncentive
peyha Sep 13, 2024
f3c4c92
style: rename maxBorrow
peyha Sep 13, 2024
abbb45d
style: rename callback
peyha Sep 13, 2024
9c45be1
style: rename liquidate into preliquidate
peyha Sep 13, 2024
f92fc2b
test: implement fuzz test
peyha Sep 13, 2024
ab62aa0
style: rename Liquidate event
peyha Sep 13, 2024
61b0b67
feat: enable ir in foundry config
peyha Sep 13, 2024
1e076fd
style: rename preliquidate
peyha Sep 13, 2024
cefddb0
style: rename maxBorrow
peyha Sep 13, 2024
481b88c
refactor: implement setSubscription
peyha Sep 13, 2024
6adab2d
feat: complete interface
peyha Sep 13, 2024
25b80bf
test: improve factory tests
peyha Sep 13, 2024
16f7f46
refactor: rename liquidationProtection
peyha Sep 13, 2024
404b931
refactor: rename test function
peyha Sep 13, 2024
ea06a08
doc: remove comment
peyha Sep 13, 2024
57318a8
test: improve factory test
peyha Sep 13, 2024
31a0c15
refactor: rename factory mapping
peyha Sep 13, 2024
ac62622
refactor: small improvement
peyha Sep 13, 2024
612cd99
refactor: rename SetSubscribe event
peyha Sep 13, 2024
69865de
doc: natspec
peyha Sep 13, 2024
fd3af59
refactor: rename SubscriptionParams => PreLiquidationParams
peyha Sep 13, 2024
17aa460
feat: remove subscription from PreLiquidation
peyha Sep 13, 2024
76cba25
refactor: remove unused event
peyha Sep 13, 2024
f3ceea2
refactor: renaming
peyha Sep 16, 2024
06afb2b
feat: change getSubscriptionId into public
peyha Sep 16, 2024
9e1b21e
Merge pull request #9 from morpho-org/feat/factory
peyha Sep 16, 2024
1937397
test(preliquidation): improve tests
peyha Sep 16, 2024
dead6a3
doc: remove outdated comment
peyha Sep 17, 2024
830d0ba
doc: remove comment
peyha Sep 17, 2024
a1b4f8e
refactor: remove file
peyha Sep 17, 2024
f95e854
refactor: change event and error
peyha Sep 17, 2024
a0cd90d
refactor: move require
peyha Sep 17, 2024
c9a53bd
doc: remove outdated comment
peyha Sep 17, 2024
b5532a9
refactor: inequality
peyha Sep 17, 2024
eb4e088
fix: require params
peyha Sep 17, 2024
6b9e1bd
refactor: remove arg from InconsistentInput error
peyha Sep 18, 2024
da099a0
feat: implement NonexistentMarket error
peyha Sep 18, 2024
276ed5d
doc: remove comment
peyha Sep 18, 2024
3083486
test: implement callback test
peyha Sep 19, 2024
af51a56
refactor: minor improvements
MathisGD Sep 20, 2024
12b5f82
chore: useless import
MathisGD Sep 20, 2024
4beb752
Merge pull request #18 from morpho-org/refactor/minor-improvements
peyha Sep 20, 2024
374ecdb
feat: implement preliquidation oracle
peyha Sep 20, 2024
ec17452
doc: natspec
peyha Sep 20, 2024
c75e608
refactor: naming
peyha Sep 23, 2024
4f08e8e
doc: wrong title
peyha Sep 23, 2024
6de296d
doc: natspec
peyha Sep 23, 2024
d9b1936
feat: remove MathLib for uint128
peyha Sep 23, 2024
1ba3aaf
refactor: prevent redundant data call
peyha Sep 23, 2024
4f8bf10
refactor: errors
peyha Sep 23, 2024
81f3f78
feat: create2 in factory
peyha Sep 23, 2024
732c171
feat: implementing create2 and UtilsLib
peyha Sep 23, 2024
bb869fc
feat: implement create2 with test
peyha Sep 23, 2024
9a1c56f
feat: remove PreLiquidationAlreadyExist error
peyha Sep 23, 2024
45ab92c
feat: use salt in factory
peyha Sep 23, 2024
c51b45c
refactor: encode struct
peyha Sep 23, 2024
f7d9836
test: redundant pre liquidation
peyha Sep 23, 2024
2dedab6
doc: remove natspec
peyha Sep 23, 2024
dfc6011
refactor: remove constantsLib and hardcode salt
peyha Sep 23, 2024
69d3fc4
feat: error
peyha Sep 23, 2024
90b18ad
test: add revert data
peyha Sep 23, 2024
329b07c
refactor: move UtilsLib to periphery
peyha Sep 23, 2024
5827c73
doc: redundant preliquidation natspec
peyha Sep 23, 2024
c9bfa30
test: isolate create2 test
peyha Sep 23, 2024
4a3a87a
refactor: reorder constant arg
peyha Sep 23, 2024
2ad38b7
doc: natspec improvement
peyha Sep 23, 2024
c809d5b
refactor: remove return variable
peyha Sep 23, 2024
66af3cc
refactor: rename UtilsLib
peyha Sep 23, 2024
b4558b6
doc: lib natspec
peyha Sep 23, 2024
e129848
refactor: factorize immutable getters
QGarchery Sep 23, 2024
5352c32
doc: improve natspec
peyha Sep 24, 2024
a422573
doc: natspec
peyha Sep 24, 2024
7f009ee
doc: natspec
peyha Sep 24, 2024
f2695db
Merge pull request #24 from morpho-org/feat/create2
peyha Sep 24, 2024
aa84ba1
refactor: rename to pre liquidation incentive factor
QGarchery Sep 24, 2024
148db67
refactor: rename getter to remove get prefix
QGarchery Sep 24, 2024
bfcff08
merge: feat/licence
QGarchery Sep 24, 2024
92e975e
feat: solidity version
peyha Sep 24, 2024
5f579a3
style: fmt
peyha Sep 24, 2024
5a7f4be
Merge pull request #27 from morpho-org/refactor/factorize-immutable-g…
QGarchery Sep 24, 2024
0fc011b
doc: preliquidation natspec
peyha Sep 24, 2024
1ca70cf
refactor: event naming
peyha Sep 24, 2024
6c953e2
build: remove api key from ci and improve foundry config
peyha Sep 24, 2024
ff50b6e
doc: move natspec from interface to contract
peyha Sep 24, 2024
66a1573
style: renaming event
peyha Sep 24, 2024
34eba76
refactor: fmt
peyha Sep 24, 2024
9f718c5
refactor: move accrue interest before market
peyha Sep 24, 2024
30d6786
test: implement interest test
peyha Sep 24, 2024
cf57d42
test: improvement
peyha Sep 24, 2024
9d47d95
doc: natspec improvements
peyha Sep 24, 2024
59eb52d
refactor: inline health check
peyha Sep 25, 2024
fbaf3ce
style: format
peyha Sep 25, 2024
ac11183
feat: pre-liquidation incentive factor require
peyha Sep 25, 2024
698ea9c
feat: close factor require
peyha Sep 25, 2024
2178f35
refactor: fetch price before accrue interest
peyha Sep 25, 2024
ccfd8f1
refactor: import
peyha Sep 25, 2024
fc5728d
doc: improvements
peyha Sep 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/foundry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Foundry

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

jobs:
test:
strategy:
fail-fast: true

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Run forge fmt
run: forge fmt --check

- name: Run forge build
run: forge build --sizes

- name: Run forge tests
run: forge test -vvv
45 changes: 0 additions & 45 deletions .github/workflows/test.yml

This file was deleted.

6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/morpho-blue"]
path = lib/morpho-blue
url = [email protected]:morpho-org/morpho-blue.git
[submodule "lib/solmate"]
path = lib/solmate
url = https://github.com/transmissions11/solmate
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
src = "src"
out = "out"
libs = ["lib"]
via_ir = true
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
optimizer_runs = 999999 # Etherscan does not support verifying contracts with more optimization runs.

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
2 changes: 1 addition & 1 deletion lib/forge-std
1 change: 1 addition & 0 deletions lib/morpho-blue
Submodule morpho-blue added at 044840
1 change: 1 addition & 0 deletions lib/solmate
Submodule solmate added at 97bdb2
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

164 changes: 164 additions & 0 deletions src/PreLiquidation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.27;

import {Id, MarketParams, IMorpho, Position, Market} from "../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {IOracle} from "../lib/morpho-blue/src/interfaces/IOracle.sol";
import {UtilsLib} from "../lib/morpho-blue/src/libraries/UtilsLib.sol";
import {ORACLE_PRICE_SCALE} from "../lib/morpho-blue/src/libraries/ConstantsLib.sol";
import {WAD, MathLib} from "../lib/morpho-blue/src/libraries/MathLib.sol";
import {SharesMathLib} from "../lib/morpho-blue/src/libraries/SharesMathLib.sol";
import {SafeTransferLib} from "../lib/solmate/src/utils/SafeTransferLib.sol";
import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {IPreLiquidationCallback} from "./interfaces/IPreLiquidationCallback.sol";
import {IPreLiquidation, PreLiquidationParams} from "./interfaces/IPreLiquidation.sol";
import {IMorphoRepayCallback} from "../lib/morpho-blue/src/interfaces/IMorphoCallbacks.sol";

/// @title PreLiquidation
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice The Fixed LI, Fixed CF pre-liquidation contract for Morpho.
peyha marked this conversation as resolved.
Show resolved Hide resolved
contract PreLiquidation is IPreLiquidation, IMorphoRepayCallback {
using SharesMathLib for uint256;
using MathLib for uint256;
using SafeTransferLib for ERC20;

/* IMMUTABLE */

/// @notice Morpho's address.
IMorpho public immutable MORPHO;
/// @notice The id of the Morpho Market specific to the PreLiquidation contract.
Id public immutable ID;

// Market parameters
address internal immutable LOAN_TOKEN;
address internal immutable COLLATERAL_TOKEN;
address internal immutable ORACLE;
address internal immutable IRM;
uint256 internal immutable LLTV;

// Pre-liquidation parameters
uint256 internal immutable PRE_LLTV;
uint256 internal immutable CLOSE_FACTOR;
uint256 internal immutable PRE_LIQUIDATION_INCENTIVE_FACTOR;
address internal immutable PRE_LIQUIDATION_ORACLE;

/// @notice The Morpho market parameters specific to the PreLiquidation contract.
function marketParams() public view returns (MarketParams memory) {
return MarketParams({
loanToken: LOAN_TOKEN,
collateralToken: COLLATERAL_TOKEN,
oracle: ORACLE,
irm: IRM,
lltv: LLTV
});
}

/// @notice The pre-liquidation parameters specific to the PreLiquidation contract.
function preLiquidationParams() external view returns (PreLiquidationParams memory) {
return PreLiquidationParams({
preLltv: PRE_LLTV,
closeFactor: CLOSE_FACTOR,
preLiquidationIncentiveFactor: PRE_LIQUIDATION_INCENTIVE_FACTOR,
preLiquidationOracle: PRE_LIQUIDATION_ORACLE
});
}

MathisGD marked this conversation as resolved.
Show resolved Hide resolved
/* CONSTRUCTOR */

/// @dev Initializes the PreLiquidation contract.
/// @param morpho The address of the Morpho protocol.
/// @param id The id of the Morpho market on which pre-liquidations will occur.
/// @param _preLiquidationParams The pre-liquidation parameters.
constructor(address morpho, Id id, PreLiquidationParams memory _preLiquidationParams) {
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
require(IMorpho(morpho).market(id).lastUpdate != 0, ErrorsLib.NonexistentMarket());
MarketParams memory _marketParams = IMorpho(morpho).idToMarketParams(id);
require(_preLiquidationParams.preLltv < _marketParams.lltv, ErrorsLib.PreLltvTooHigh());
colin-morpho marked this conversation as resolved.
Show resolved Hide resolved
require(_preLiquidationParams.closeFactor <= WAD, ErrorsLib.CloseFactorTooHigh());
require(
_preLiquidationParams.preLiquidationIncentiveFactor >= WAD, ErrorsLib.PreLiquidationIncentiveFactorTooLow()
);

peyha marked this conversation as resolved.
Show resolved Hide resolved
MORPHO = IMorpho(morpho);

ID = id;

LOAN_TOKEN = _marketParams.loanToken;
COLLATERAL_TOKEN = _marketParams.collateralToken;
ORACLE = _marketParams.oracle;
IRM = _marketParams.irm;
LLTV = _marketParams.lltv;

PRE_LLTV = _preLiquidationParams.preLltv;
CLOSE_FACTOR = _preLiquidationParams.closeFactor;
PRE_LIQUIDATION_INCENTIVE_FACTOR = _preLiquidationParams.preLiquidationIncentiveFactor;
PRE_LIQUIDATION_ORACLE = _preLiquidationParams.preLiquidationOracle;

ERC20(LOAN_TOKEN).safeApprove(morpho, type(uint256).max);
}
MathisGD marked this conversation as resolved.
Show resolved Hide resolved

/* PRE-LIQUIDATION */

/// @notice Pre-liquidates the given borrower on the market of this contract and with the parameters of this contract.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onPreLiquidate` callback. Pass empty data if not needed.
function preLiquidate(address borrower, uint256 seizedAssets, uint256 repaidShares, bytes calldata data) external {
require(UtilsLib.exactlyOneZero(seizedAssets, repaidShares), ErrorsLib.InconsistentInput());

MORPHO.accrueInterest(marketParams());

Market memory market = MORPHO.market(ID);
Position memory position = MORPHO.position(ID, borrower);

uint256 collateralPrice = IOracle(PRE_LIQUIDATION_ORACLE).price();
uint256 borrowed = uint256(position.borrowShares).toAssetsUp(market.totalBorrowAssets, market.totalBorrowShares);
uint256 borrowThreshold =
uint256(position.collateral).mulDivDown(collateralPrice, ORACLE_PRICE_SCALE).wMulDown(PRE_LLTV);

require(borrowed > borrowThreshold, ErrorsLib.NotPreLiquidatablePosition());

if (seizedAssets > 0) {
uint256 seizedAssetsQuoted = seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE);

repaidShares = seizedAssetsQuoted.wDivUp(PRE_LIQUIDATION_INCENTIVE_FACTOR).toSharesUp(
market.totalBorrowAssets, market.totalBorrowShares
);
} else {
seizedAssets = repaidShares.toAssetsDown(market.totalBorrowAssets, market.totalBorrowShares).wMulDown(
PRE_LIQUIDATION_INCENTIVE_FACTOR
).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice);
}

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

bytes memory callbackData = abi.encode(seizedAssets, borrower, msg.sender, data);
(uint256 repaidAssets,) = MORPHO.repay(marketParams(), 0, repaidShares, borrower, callbackData);

emit EventsLib.PreLiquidate(ID, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets);
QGarchery marked this conversation as resolved.
Show resolved Hide resolved
}

/// @notice Morpho callback after repay call.
/// @dev During pre-liquidation, Morpho will call the `onMorphoRepay` callback function in `PreLiquidation` using the provided data.
/// This mechanism enables the withdrawal of the position’s collateral before the debt repayment occurs,
/// and can also trigger a pre-liquidator callback. The pre-liquidator callback can be used to swap
/// the seized collateral into the asset being repaid, facilitating liquidation without the need for a flashloan.
function onMorphoRepay(uint256 repaidAssets, bytes calldata callbackData) external {
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
require(msg.sender == address(MORPHO), ErrorsLib.NotMorpho());
(uint256 seizedAssets, address borrower, address liquidator, bytes memory data) =
abi.decode(callbackData, (uint256, address, address, bytes));
peyha marked this conversation as resolved.
Show resolved Hide resolved

MORPHO.withdrawCollateral(marketParams(), seizedAssets, borrower, liquidator);

if (data.length > 0) {
IPreLiquidationCallback(liquidator).onPreLiquidate(repaidAssets, data);
}

ERC20(LOAN_TOKEN).safeTransferFrom(liquidator, address(this), repaidAssets);
}
}
47 changes: 47 additions & 0 deletions src/PreLiquidationFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.27;

import {IMorpho, Id} from "../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {PreLiquidation} from "./PreLiquidation.sol";
import {IPreLiquidation, PreLiquidationParams} from "./interfaces/IPreLiquidation.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import {IPreLiquidationFactory} from "./interfaces/IPreLiquidationFactory.sol";

/// @title PreLiquidationFactory
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice The Fixed LI, Fixed CF pre-liquidation factory contract for Morpho.
contract PreLiquidationFactory is IPreLiquidationFactory {
/* IMMUTABLE */

/// @notice The address of the Morpho contract.
IMorpho public immutable MORPHO;

/* CONSTRUCTOR */

/// @param morpho The address of the Morpho contract.
constructor(address morpho) {
require(morpho != address(0), ErrorsLib.ZeroAddress());

MORPHO = IMorpho(morpho);
}

/* EXTERNAL */

/// @notice Creates a PreLiquidation contract.
/// @param id The Morpho market for PreLiquidations.
/// @param preLiquidationParams The PreLiquidation params for the PreLiquidation contract.
/// @dev Warning: This function will revert without data if the pre-liquidation already exists.
function createPreLiquidation(Id id, PreLiquidationParams calldata preLiquidationParams)
external
returns (IPreLiquidation)
{
IPreLiquidation preLiquidation =
IPreLiquidation(address(new PreLiquidation{salt: 0}(address(MORPHO), id, preLiquidationParams)));

emit EventsLib.CreatePreLiquidation(address(preLiquidation), id, preLiquidationParams);

return preLiquidation;
}
}
28 changes: 28 additions & 0 deletions src/interfaces/IPreLiquidation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >= 0.5.0;

import {Id, IMorpho, MarketParams} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";

/// @notice The pre-liquidation parameters are:
/// - preLltv, the maximum LTV of a position before allowing pre-liquidation.
/// - closeFactor, the maximum proportion of debt that can be pre-liquidated at once.
/// - preLiquidationIncentiveFactor, the factor used to multiply repaid debt value to get the seized collateral value in a pre-liquidation.
/// - preLiquidationOracle, the oracle used to assess whether or not a position can be preliquidated.
struct PreLiquidationParams {
uint256 preLltv;
uint256 closeFactor;
uint256 preLiquidationIncentiveFactor;
address preLiquidationOracle;
}

interface IPreLiquidation {
function MORPHO() external view returns (IMorpho);

function ID() external view returns (Id);

function marketParams() external returns (MarketParams memory);

function preLiquidationParams() external view returns (PreLiquidationParams memory);

function preLiquidate(address borrower, uint256 seizedAssets, uint256 repaidShares, bytes calldata data) external;
peyha marked this conversation as resolved.
Show resolved Hide resolved
}
12 changes: 12 additions & 0 deletions src/interfaces/IPreLiquidationCallback.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >= 0.5.0;

/// @title IPreLiquidationCallback
/// @notice Interface that "pre-liquidators" willing to use the pre-liquidation callback must implement.
interface IPreLiquidationCallback {
/// @notice Callback called when a pre-liquidation occurs.
/// @dev The callback is called only if data is not empty.
/// @param repaidAssets The amount of repaid assets.
/// @param data Arbitrary data passed to the `preLiquidate` function.
function onPreLiquidate(uint256 repaidAssets, bytes calldata data) external;
}
Loading