diff --git a/src/Morpho.sol b/src/Morpho.sol index 0fb6eb187..cace6d16f 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -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); @@ -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; @@ -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 */ diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index ac6d476d6..27ae16378 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -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); @@ -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); @@ -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); @@ -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); @@ -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. diff --git a/test/forge/Morpho.t.sol b/test/forge/Morpho.t.sol index 8acb6f8a7..cd628df74 100644 --- a/test/forge/Morpho.t.sol +++ b/test/forge/Morpho.t.sol @@ -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(); @@ -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"); @@ -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(); @@ -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");