Comment on page
Liquidations in the Borrowing Module
Tutorial to participate in liquidations in Angle Borrowing Module
The health of Angle Protocol borrowing module is dependent on the health of the positions (or vaults) within the system, also known as the health factor. When the health factor of a vault is below 1, anyone can make a
liquidatecall to the
VaultManagercontract where the vault is, paying back a portion of the debt owed by the vault and receiving discounted collateral in return.
This incentivises third parties to participate in the health of the overall protocol, by acting on their own interest (to receive the discounted collateral) and as a result, ensure AgTokens in circulation from this module are sufficiently collateralised.
Liquidations are quite-common in DeFi. There are however some peculiarities within the Angle system liquidators should have in mind before engaging with the Angle Protocol:
- It is possible to liquidate multiple positions/vaults in just one transaction with Angle. If different positions of the same
VaultManagercan be liquidated, then both of them can liquidated in one transaction with just one stablecoin transfer from the liquidator and collateral transfer to it.
- Liquidations have been designed to be capital-efficient meaning that you can liquidate with no upfront capital: discounted collateral is given first to the liquidator which can in the same transaction swap it to stablecoins to then repay the debt. This is however an optional feature and liquidators could proceed as they normally do in other protocols.
- The protocol proposes two different liquidation interfaces for liquidators: one that lets them specify a contract address and data to process a swap if needed, and one which enables them to proceed without this logic. The two different options correspond to the two different
liquidatefunctions in the
- Discount given to liquidators is not fixed and is a dynamic variable of the health ratio of a vault. Basically the smaller a health ratio, the bigger the discount of a liquidator is.
- In some situations, there may be boosts that is to say higher discounts given to liquidators which own veANGLE tokens.
When making a
liquidate()call, you must:
- Know the vaults (i.e. the
uint256defining the ID of vaults) which health factor are below 1.
- Know the
VaultManager(that is the contract corresponding to a collateral type-stablecoin pair in Angle Borrowing Module) in which liquidation should take place: this is the contract in which you will have to call the
- Choose if you want to swap the collateral obtained from liquidations to stablecoins using some sort of
Swappercontract or directly bring the stablecoins to repay. In the first case, you may want to look at our guide here to see how to use
Swappercontract in your Angle execution flow.
- Know the amount of stablecoins you want to repay in these vaults. There are several ways in which you can estimate this. The optimal way is to rely on the function
checkLiquidationdefined in each
VaultManagercontract. When called on a given
vaultIDthat is liquidable, this function returns several elements which can be used in a subsequent liquidation call:
maxStablecoinAmountToRepay: Maximum stablecoin amount that can be repaid by liquidators upon liquidating the vault
maxCollateralAmountToGive: This is the amount of collateral you would receive if you were to repay
thresholdRepayAmount: For some vaults, if liquidators were to liquidate a certain portion of their debt, then these vaults may end up with a "dusty" amount of debt of collateral in it. The protocol prevents liquidators from putting vaults in situations like that. As such, a non-null
thresholdRepayAmountmeans that you can repay an amount of the debt either smaller to this
thresholdRepayAmountor exactly equal to the
discount: Discount you will get on the oracle value price of the collateral
currentDebt: Total amount of debt in the vault
These values may vary in time, as such if you're running a smart contract you may want to embed your call to
checkLiquidationin the same transaction as the
liquidatecall. If you're not sure about the
maxStablecoinAmountToRepay, the protocol will round the
amountvalue you pass in the liquidation function to the
maxStablecoinAmountToRepayif it is superior to the
thresholdRepayAmountin case it is not null or to the
Only vaults that have a health factor below 1 can be liquidated. There are multiple ways you can get the health factor of a vault.
The easiest way to identify liquidable vaults is to call in a given
checkLiquidationfor all existing vaults (you may simply iterate over the
vaultIDCountvariable to get all these vaults). Since this just requires repeatedly calling a view function, it does not incur any cost.
As explained above, There are two functions that you can call to liquidate:
uint256 memory vaultIDs,
uint256 memory amounts,
) external returns (LiquidatorData memory)
uint256 memory vaultIDs,
uint256 memory amounts,
bytes memory data
) public returns (LiquidatorData memory liqData)
Upon choosing the amount of debt of a vault you want to repay, you have the possibility to specify a
fromaddress from which stablecoins should be taken. This address should have approved for the stablecoin the address used to trigger the liquidation. You can also specify a
toaddress to which collateral will be sent.
In the second option, you can specify a
whocontract as well as some
datato swap the obtained collateral for stablecoins (or just a portion of it to minimize slippage) efficiently.
If you are using a smart contract to liquidate, then you may want to process the results obtained from the liquidation you performed. You basically get different returned values:
stablecoinAmountToReceive: This is the amount of stablecoins you have given for the liquidation
collateralAmountToGive: Current amount of collateral you've gotten from the contract
Note that these returned values are denominated from a protocol perspective and they could be named differently. The contract also returns some utility values which may be less useful to the liquidator:
badDebtFromLiquidation: Bad debt accrued across the liquidation process
oracleValue: Oracle value at which the liquidation took place
newInterestAccumulator: Value of the
interestAccumulatorat the time of the call (this is a value used to track vaults outstanding debt)
Depending on your environment, preferred programming tools and languages, your bot should:
- Ensure it has enough (or access to enough) funds when liquidating or that it is able to correctly swap the collateral obtained for stablecoins
- Calculate the profitability of liquidating loans vs gas costs, taking into account the most lucrative collateral to liquidate.
- Ensure it has access to the latest protocol data.
- Have the usual fail safes and security you'd expect for any production service.
- Calculating profitability vs gas cost.
- Be able to estimate slippage in the case where collateral is swapped for stablecoins (or used to mint stablecoins).
The health factor of a vault is computed from the vault's collateral amount (in stablecoin value) multiplied by the current collateral factor divided by the vault's current debt. This debt can be obtained on-chain by querying the function:
The forumula for the health factor is then the following:
To get the necessary values, you can do the following:
const collateralAmount = (await vaultManager.vaultData(vaultID))
const oracleValue = await(await vaultManager.oracle()).read()
const collatBase = await collateral.decimals()
const collateralFactor = await vaultManager.collateralFactor()
const collateralAmountInStablecoinValue = collateralAmount
.div(10 ** collatBase)
const debt = await vaultManager.getVaultDebt(vaultID)
const healthFactor = collateralAmountInStablecoinValue
The liquidation discount given to liquidators is a function of the health factor of the liquidated vault.
This discount is always capped by a maximum discount value defined in each
Governance has the opportunity to make the function
f(veANGLE delegated balance)constant for all liquidators. To see if this is not the case, you should check the
yLiquidationBoostfields of the corresponding