Natrium docs
  • ๐ŸงชOverview
    • ๐Ÿ“–Introducing Natrium
    • ๐Ÿ”ฎVision
  • โš™๏ธProtocol Overview
    • ๐ŸŒProtocol architecture
      • โšœ๏ธNatrium Core & Enterprise
    • ๐ŸŒŠLiquidations
    • ๐Ÿ“ˆInterest Rate Models
    • โšกOracles
    • โš–๏ธProtocol Fees
  • ๐Ÿ’ฐTokenomics
    • ๐Ÿš€Presale & Launch
    • ๐ŸงฌNTM & NaCl
  • โš’๏ธDev Docs
    • ๐Ÿ”‘Contract specs
      • Isolated Pools (Layer 1)
        • Bucket config
        • Supply underlying asset
        • Withdraw underlying asset
        • Deposit OverCollateralized asset
        • Borrow
        • Repay
        • Withdraw OverCollaterlized asset
        • Liquidate
      • Shufflers (Layer 2)
        • Contract functionalities
          • Shuffler Creation
          • Shuffler Management
          • Supply Cap Management
          • Risk Exposure Management
      • Error Library
        • Error lib
  • ๐Ÿ“šLibrary
    • Brand Assets
    • Community Links
    • Legal Disclaimer
Powered by GitBook
On this page
  1. โš’๏ธDev Docs
  2. ๐Ÿ”‘Contract specs
  3. Isolated Pools (Layer 1)

Liquidate

PreviousWithdraw OverCollaterlized assetNextShufflers (Layer 2)

Last updated 1 year ago

CtrlK

The liquidate function is to allow an external entity (referred to as the liquidator) to liquidate a borrower's position in a lending market. This happens when the borrower's position becomes risky or unhealthy, typically due to a decline in the value of the collateral relative to the borrowed assets

function liquidate(
        MarketParams memory marketParams,
        address borrower,
        uint256 seizedAssets,
        uint256 repaidShares,
        bytes calldata data
    ) external returns (uint256, uint256) {
        Id id = marketParams.id();
        require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
        require(UtilsLib.exactlyOneZero(seizedAssets, repaidShares), ErrorsLib.INCONSISTENT_INPUT);

        _accrueInterest(marketParams, id);

        uint256 collateralPrice = IOracle(marketParams.oracle).price();

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

        uint256 repaidAssets;
        {
            // The liquidation incentive factor is min(maxLiquidationIncentiveFactor, 1/(1 - cursor*(1 - lltv))).
            uint256 liquidationIncentiveFactor = UtilsLib.min(
                MAX_LIQUIDATION_INCENTIVE_FACTOR,
                WAD.wDivDown(WAD - LIQUIDATION_CURSOR.wMulDown(WAD - marketParams.lltv))
            );

            if (seizedAssets > 0) {
                repaidAssets =
                    seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE).wDivUp(liquidationIncentiveFactor);
                repaidShares = repaidAssets.toSharesDown(market[id].totalBorrowAssets, market[id].totalBorrowShares);
            } else {
                repaidAssets = repaidShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);
                seizedAssets =
                    repaidAssets.wMulDown(liquidationIncentiveFactor).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice);
            }
        }

        position[id][borrower].borrowShares -= repaidShares.toUint128();
        market[id].totalBorrowShares -= repaidShares.toUint128();
        market[id].totalBorrowAssets = UtilsLib.zeroFloorSub(market[id].totalBorrowAssets, repaidAssets).toUint128();

        position[id][borrower].collateral -= seizedAssets.toUint128();

        uint256 badDebtShares;
        if (position[id][borrower].collateral == 0) {
            badDebtShares = position[id][borrower].borrowShares;
            uint256 badDebt = UtilsLib.min(
                market[id].totalBorrowAssets,
                badDebtShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares)
            );

            market[id].totalBorrowAssets -= badDebt.toUint128();
            market[id].totalSupplyAssets -= badDebt.toUint128();
            market[id].totalBorrowShares -= badDebtShares.toUint128();
            position[id][borrower].borrowShares = 0;
        }

        IERC20(marketParams.collateralToken).safeTransfer(msg.sender, seizedAssets);

        // `repaidAssets` may be greater than `totalBorrowAssets` by 1.
        emit EventsLib.Liquidate(id, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets, badDebtShares);

        if (data.length > 0) INatriumLiquidateCallback(msg.sender).onNatriumLiquidate(repaidAssets, data);

        IERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), repaidAssets);

        return (seizedAssets, repaidAssets);
    }