Skip to content

Commit

Permalink
Merge pull request #295 from morpho-labs/feat/return-values-liquidate
Browse files Browse the repository at this point in the history
Add return values liquidate
  • Loading branch information
MerlinEgalite committed Aug 14, 2023
2 parents d0ba1ed + b050b66 commit 25f50cc
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 31 deletions.
21 changes: 12 additions & 9 deletions src/Morpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,10 @@ contract Morpho is IMorpho {
/* LIQUIDATION */

/// @inheritdoc IMorpho
function liquidate(Market memory market, address borrower, uint256 seized, bytes calldata data) external {
function liquidate(Market memory market, address borrower, uint256 seized, bytes calldata data)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid)
{
Id id = market.id();
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(seized != 0, ErrorsLib.ZERO_ASSETS);
Expand All @@ -338,13 +341,13 @@ contract Morpho is IMorpho {

require(!_isHealthy(market, id, borrower, collateralPrice), ErrorsLib.HEALTHY_POSITION);

uint256 repaid =
assetsRepaid =
seized.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE).wDivUp(liquidationIncentiveFactor(market.lltv));
uint256 repaidShares = repaid.toSharesDown(totalBorrow[id], totalBorrowShares[id]);
sharesRepaid = assetsRepaid.toSharesDown(totalBorrow[id], totalBorrowShares[id]);

borrowShares[id][borrower] -= repaidShares;
totalBorrowShares[id] -= repaidShares;
totalBorrow[id] -= repaid;
borrowShares[id][borrower] -= sharesRepaid;
totalBorrowShares[id] -= sharesRepaid;
totalBorrow[id] -= assetsRepaid;

collateral[id][borrower] -= seized;

Expand All @@ -361,11 +364,11 @@ contract Morpho is IMorpho {

IERC20(market.collateralToken).safeTransfer(msg.sender, seized);

emit EventsLib.Liquidate(id, msg.sender, borrower, repaid, repaidShares, seized, badDebtShares);
emit EventsLib.Liquidate(id, msg.sender, borrower, assetsRepaid, sharesRepaid, seized, badDebtShares);

if (data.length > 0) IMorphoLiquidateCallback(msg.sender).onMorphoLiquidate(repaid, data);
if (data.length > 0) IMorphoLiquidateCallback(msg.sender).onMorphoLiquidate(assetsRepaid, data);

IERC20(market.borrowableToken).safeTransferFrom(msg.sender, address(this), repaid);
IERC20(market.borrowableToken).safeTransferFrom(msg.sender, address(this), assetsRepaid);
}

/* FLASH LOANS */
Expand Down
44 changes: 24 additions & 20 deletions src/interfaces/IMorpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,16 @@ interface IMorpho is IFlashLender {
/// @dev Either `assets` or `shares` should be zero.
/// Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to have `assets` tokens pulled from their balance,
/// but the possibility to mint a specific assets of shares is given
/// but the possibility to mint a specific amount of shares is given
/// for full compatibility and precision.
/// @dev Supplying a large amount can overflow and revert without any error message.
/// @param market The market to supply assets to.
/// @param assets The assets of assets to supply.
/// @param shares The assets of shares to mint.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will receive the position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The assets of assets supplied.
/// @return sharesSupplied The assets of shares supplied.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares supplied.
function supply(Market memory market, uint256 assets, uint256 shares, address onBehalf, bytes memory data)
external
returns (uint256 assetsSupplied, uint256 sharesSupplied);
Expand All @@ -141,12 +141,12 @@ interface IMorpho is IFlashLender {
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will underflow and revert without any error message.
/// @param market The market to withdraw assets from.
/// @param shares The assets of assets to withdraw.
/// @param shares The assets of shares to burn.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the withdrawn assets.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The assets of assets withdrawn.
/// @return sharesWithdrawn The assets of shares withdrawn.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares withdrawn.
function withdraw(Market memory market, uint256 assets, uint256 shares, address onBehalf, address receiver)
external
returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
Expand All @@ -155,17 +155,17 @@ interface IMorpho is IFlashLender {
/// @dev Either `assets` or `shares` should be zero.
/// Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to borrow `assets` of tokens,
/// but the possibility to burn a specific assets of shares is given
/// but the possibility to burn a specific amount of shares is given
/// for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can overflow and revert without any error message.
/// @param market The market to borrow assets from.
/// @param assets The assets of assets to borrow.
/// @param shares The assets of shares to mint.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address of the owner of the debt.
/// @param receiver The address that will receive the debt.
/// @return assetsBorrowed The assets of assets borrowed.
/// @return sharesBorrowed The assets of shares borrowed.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares borrowed.
function borrow(Market memory market, uint256 assets, uint256 shares, address onBehalf, address receiver)
external
returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
Expand All @@ -176,12 +176,12 @@ interface IMorpho is IFlashLender {
/// To repay the whole debt, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will underflow and revert without any error message.
/// @param market The market to repay assets to.
/// @param assets The assets of assets to repay.
/// @param shares The assets of shares to burn.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The assets of assets repaid.
/// @return sharesRepaid The assets of shares repaid.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares repaid.
function repay(Market memory market, uint256 assets, uint256 shares, address onBehalf, bytes memory data)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid);
Expand Down Expand Up @@ -212,8 +212,12 @@ interface IMorpho is IFlashLender {
/// @param market The market of the position.
/// @param borrower The owner of the position.
/// @param seized The assets of collateral to seize.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed
function liquidate(Market memory market, address borrower, uint256 seized, bytes memory data) external;
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares repaid.
function liquidate(Market memory market, address borrower, uint256 seized, bytes memory data)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid);

/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
Expand Down
6 changes: 4 additions & 2 deletions test/forge/Morpho.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ contract MorphoTest is

// Liquidate
vm.prank(LIQUIDATOR);
morpho.liquidate(market, BORROWER, toSeize, hex"");
(uint256 assetsRepaid,) = morpho.liquidate(market, BORROWER, toSeize, hex"");

uint256 liquidatorNetWorthAfter = netWorth(LIQUIDATOR);
uint256 collateralPrice = IOracle(market.oracle).price();
Expand All @@ -650,6 +650,7 @@ contract MorphoTest is
toSeize.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE).wDivUp(liquidationIncentiveFactor);
uint256 expectedNetWorthAfter =
liquidatorNetWorthBefore + toSeize.mulDivDown(collateralPrice, ORACLE_PRICE_SCALE) - expectedRepaid;
assertEq(assetsRepaid, expectedRepaid, "wrong return repaid value");
assertEq(liquidatorNetWorthAfter, expectedNetWorthAfter, "LIQUIDATOR net worth");
assertApproxEqAbs(borrowBalance(BORROWER), assetsBorrowed - expectedRepaid, 100, "BORROWER balance");
assertEq(morpho.collateral(id, BORROWER), assetsCollateral - toSeize, "BORROWER collateral");
Expand Down Expand Up @@ -686,7 +687,7 @@ contract MorphoTest is

// Liquidate
vm.prank(LIQUIDATOR);
morpho.liquidate(market, BORROWER, toSeize, hex"");
(uint256 assetsRepaid,) = morpho.liquidate(market, BORROWER, toSeize, hex"");

uint256 liquidatorNetWorthAfter = netWorth(LIQUIDATOR);
uint256 collateralPrice = IOracle(market.oracle).price();
Expand All @@ -695,6 +696,7 @@ contract MorphoTest is
toSeize.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE).wDivUp(liquidationIncentiveFactor);
uint256 expectedNetWorthAfter =
liquidatorNetWorthBefore + toSeize.mulDivDown(collateralPrice, ORACLE_PRICE_SCALE) - expectedRepaid;
assertEq(assetsRepaid, expectedRepaid, "wrong return repaid value");
assertEq(liquidatorNetWorthAfter, expectedNetWorthAfter, "LIQUIDATOR net worth");
assertEq(borrowBalance(BORROWER), 0, "BORROWER balance");
assertEq(morpho.collateral(id, BORROWER), 0, "BORROWER collateral");
Expand Down

0 comments on commit 25f50cc

Please sign in to comment.