zkLend / zklend-v1-core

Core smart contracts of zkLend v1
https://zklend.com
Other
16 stars 7 forks source link

undercollateralized user borrowing position #86

Closed kristiann57 closed 2 weeks ago

kristiann57 commented 2 months ago

Hello team,

One question, for liquidations... Am I right to believe that in order to calculate the actual borrowing position of a user, I have to multiply the raw debt of the user by the debt accumulator? also, for the collateral balance, it is just fine to get the zTokenBalance or are there any other calculations that have to be performed afterward to the collateral position too?

many thanks

9oelM commented 1 month ago

@kristiann57 sorry about the late reply. I just noticed I am not subscribing to all updates in the repository.

  1. Yes, to get the 'face amount' or 'scaled up' amount of the debt, you need to multiply the raw debt by the latest debt accumulator.
  2. To get the 'face amount' or 'scaled up' amount of the deposit, you can just call balanceOf of zToken contract.

However, you also need to consider the collateral factor the context of liquidations. Each asset has a different collateral factor. That means you need to discount the zToken balance by multiplying it with the collateral factor. For example, if I have a zToken balance of ETH equivalent to 100 USD at a 80% collateral factor, that means my ETH collateral is only worth 80 USD when you want to back any borrowing.

The most relevant function when it comes to calculating the health factor is calculate_user_collateral_data_loop:

https://github.com/zkLend/zklend-v1-core/blob/787f3443f8c7beb0576690adfcde93341667e5da/src/market/internal.cairo#L536-L584

Essentially, what it does is to go over all tokens and calculate how much borrowing the user has against how much collaterals discounted by each collateral factor the user has and to return struct UserCollateralData { collateral_value: felt252, collateral_required: felt252 }. If collateral_required <= collateral_value, the position is healthy and has an health factor greater than or equal to 1 (health factor is just collateral_value/collateral_required). This is all you need to see if a user's position is liquidable.

At the end of the liquidation, we call assert_not_overcollateralized:

https://github.com/zkLend/zklend-v1-core/blob/787f3443f8c7beb0576690adfcde93341667e5da/src/market/internal.cairo#L468-L474

As awkward as it may seem to assert the position is still not 'overcollateralized', it actually makes sense because this ensures that liquidation should only work for undercollateralized positions and only restores the health factor back to 1 and not more. If the position can be overcollateralized after liquidation, that means the liquidator repays too much for the unhealthy position. The goal of liquidation is to make the health factor as close to 1 (from below 1) as possible, but above 1.

You can take a look at the section about liquidation on my blog post on zkLend's smart contracts. It walks you through one hypothetical example of a liquidation with real numbers.

You also can refer to the zkLend documentation on the health factor for more information.