Links

Liquidations

Learn how to participate in the liquidations market
This documentation is a work in progress!

Overview

Liquidations of unhealthy CDP's within the protocol can be done by anyone and the protocol incentivizes the ones doing so.
Liquidators must acquire equal amount of the Kresko Asset that is repaid on behalf of the liquidatee. These Kresko Assets are burned and the debt balance of the liquidatee is reduced accordingly. Protocol then calculates the amount of collateral to seize, removes it from the liquidatees collateral deposits and transfers it to the liquidators address.
When a liquidator repays debt on the unhealthy CDP, in return they receive the liquidatees collateral at a discount according to a state variable Liquidation Incentive Multiplier. This rewards the liquidators in exchange for the service provided.

Liquidation Threshold

Thing to understand in liquidations is the difference between Liquidation Threshold (LT) and the Minimum Collateralization Ratio (MCR).
An account in the protocol is considered liquidatable when the ratio of collateral to debt is less than the LT. MCR is used to decide whether the CDP is allowed to take on more debt. While MCR is similar to the LT, it won't make an account liquidatable. The possible gap between these ratios is a safety buffer and it prevents users from creating extremely risky positions which would get liquidated in the slightest market movement.
TL;DR
  • Accounts can be liquidated below LT.
  • Accounts can only be liquidated up to the LT.

Acquiring Kresko Assets

Three main options exist to acquire Kresko Assets
  1. 1.
    Borrowing the assets from the protocol against collateral.
  2. 2.
    Using the AMM to perform a flash swap to acquire the assets with no upfront capital.
  3. 3.
    Buy the assets from an AMM pair.
Liquidation call does not touch liquidators debt, as it would be a double spend.
This means using the protocol to acquire Kresko Assets will leave the liquidator with a regular CDP after the liquidation call.

Acquiring Information About Accounts

All protocol code is public on GitHub

Finding Active Accounts

It is up to the liquidator to find the most efficient way to list out all the active accounts in the protocol but one simple way is to use the KreskoAssetMinted event.
/**
* @notice Emitted when an account mints a Kresko asset.
* @param account The address of the account minting the Kresko asset.
* @param kreskoAsset The address of the Kresko asset.
* @param amount The amount of the Kresko asset that was minted.
*/
event KreskoAssetMinted(address indexed account, address indexed kreskoAsset, uint256 indexed amount);

Get Account Liquidatable Status

To check if an account is liquidatable a call can be made to the view isAccountLiquidatable in LiquidationFacet.
function isAccountLiquidatable(address _account) external view returns (bool) {
return ms().isAccountLiquidatable(_account);
}

Get Account Collateral & Kresko Asset Addresses

Minted Kresko Assets of an account can be acquired using getMintedKreskoAssets in the AccountStateFacet.
/**
* @notice Gets an array of Kresko assets the account has minted.
* @param _account The account to get the minted Kresko assets for.
* @return An array of addresses of Kresko assets the account has minted.
*/
function getMintedKreskoAssets(address _account) external view returns (address[] memory) {
return ms().mintedKreskoAssets[_account];
}
Deposited Collateral Assets of an account can be acquired using getDepositedCollateralAssets in the AccountStateFacet.
/**
* @notice Gets an array of collateral assets the account has deposited.
* @param _account The account to get the deposited collateral assets for.
* @return An array of addresses of collateral assets the account has deposited.
*/
function getDepositedCollateralAssets(address _account) external view returns (address[] memory) {
return ms().depositedCollateralAssets[_account];
}

Get Account Collateral & Kresko Asset amounts

kreskoAssetDebt can be used to acquire the debt amount.
/**
* @notice Get `_account` debt amount for `_asset`
* @param _asset The asset address
* @param _account The account to query amount for
* @return Amount of debt for `_asset`
*/
function kreskoAssetDebt(address _account, address _asset) external view returns (uint256) {
return ms().getKreskoAssetDebtScaled(_account, _asset);
}
collateralDeposits can be used to acquire the deposited collateral amount
/**
* @notice Get `_account` collateral deposit amount for `_asset`
* @param _asset The asset address
* @param _account The account to query amount for
* @return Amount of collateral deposited for `_asset`
*/
function collateralDeposits(address _account, address _asset) external view returns (uint256) {
return ms().getCollateralDeposits(_account, _asset);
}

Get Account Complete Data

getAccountData UI helper can be used to simplify the process of getting the account data. You can find the staking address from the deployment addresses.
function getAccountData(
address _account,
address[] memory _tokens,
address _staking
)
external
view
returns (
LibUI.KreskoUser memory user,
LibUI.Balance[] memory balances,
LibUI.StakingData[] memory stakingData
)
{
user = LibUI.kreskoUser(_account);
balances = LibUI.getBalances(_tokens, _account);
stakingData = LibUI.getStakingData(_account, _staking);
}

Get Account Asset Indexes

You can simply use the indexes from the arrays received in Get accounts Collateral & Kresko Asset addresses but a few views also exist

Get Deposited Collateral Asset Index

/**
* @notice Gets an index for the collateral asset the account has deposited.
* @param _account The account to get the index for.
* @param _collateralAsset The asset lookup address.
* @return i = index of the minted collateral asset.
*/
function getDepositedCollateralAssetIndex(address _account, address _collateralAsset)
external
view
returns (uint256 i)

Get Minted Kresko Asset Index

/**
* @notice Gets an index for the Kresko asset the account has minted.
* @param _account The account to get the minted Kresko assets for.
* @param _kreskoAsset The asset lookup address.
* @return index of the minted Kresko asset.
*/
function getMintedKreskoAssetsIndex(address _account, address _kreskoAsset) external view returns (uint256) {
return ms().getMintedKreskoAssetsIndex(_account, _kreskoAsset);
}

Get Maximum Liquidatable Value

Protocol allows liquidations in a single call up to the Maximum Liquidatable Value for an asset pair.
It can be obtained using the calculateMaximumLiquidatableValueForAssets function in LiquidationFacet. You can use this value as a starting point to derive the amount of Kresko Assets used for the liquidation.
/**
* @dev Calculates the total value that can be liquidated for a liquidation pair
* @param _account address to liquidate
* @param _repayKreskoAsset address of the kreskoAsset being repaid on behalf of the liquidatee
* @param _collateralAssetToSeize address of the collateral asset being seized from the liquidatee
* @return maxLiquidatableUSD USD value that can be liquidated, 0 if the pair has no liquidatable value
*/
function calculateMaxLiquidatableValueForAssets(
address _account,
address _repayKreskoAsset,
address _collateralAssetToSeize
) public view returns (FixedPoint.Unsigned memory maxLiquidatableUSD) {
return ms().calculateMaxLiquidatableValueForAssets(_account, _repayKreskoAsset, _collateralAssetToSeize);
}

Calling Liquidate

Liquidation Call Requirements

To perform a succesfull liquidation it needs to pass the following require statements.
// No zero repays
require(_repayAmount > 0, Error.ZERO_REPAY);
// Borrower cannot liquidate themselves
require(msg.sender != _account, Error.SELF_LIQUIDATION);
// krAsset exists
require(s.kreskoAssets[_repayKreskoAsset].exists, Error.KRASSET_DOESNT_EXIST);
// Check that this account is below liquidation threshold.
require(s.isAccountLiquidatable(_account), Error.NOT_LIQUIDATABLE);
// Collateral exists
require(s.collateralAssets[_collateralAssetToSeize].exists, Error.COLLATERAL_DOESNT_EXIST);
// Repay amount cannot be greater than debt
require(krAssetDebt >= _repayAmount, Error.KRASSET_BURN_AMOUNT_OVERFLOW);
// Repay value cannot be greater than maximum value allowed
require(repayAmountUSD.isLessThanOrEqual(maxLiquidation), Error.LIQUIDATION_OVERFLOW);

Liquidation Call

With the acquired information the liquidator needs to supply the arguments required by the liquidation function which is defined as follows
Protocol charges the close fee on a liquidation call from the liquidatee
/**
* @notice Attempts to liquidate an account by repaying the portion of the account's Kresko asset
* princpal debt, receiving in return a portion of the account's collateral at a discounted rate.
* @param _account The account to attempt to liquidate.
* @param _repayKreskoAsset The address of the Kresko asset to be repaid.
* @param _repayAmount The amount of the Kresko asset to be repaid.
* @param _collateralAssetToSeize The address of the collateral asset to be seized.
* @param _mintedKreskoAssetIndex The index of the Kresko asset in the account's minted assets array.
* @param _depositedCollateralAssetIndex Index of the collateral asset in the account's collateral assets array.
*/
function liquidate(s
address _account,
address _repayKreskoAsset,
uint256 _repayAmount,
address _collateralAssetToSeize,
uint256 _mintedKreskoAssetIndex,
uint256 _depositedCollateralAssetIndex
) external nonReentrant