Liquidation
Liquidations are an integral part of any money market protocol. Fundamentally, they work simply by having liquidators repay unhealthy debts and withdraw backing collateral with a bonus as incentive. However, this is complicated by the fact that Mirage has to preserve information about healthy positions.
How liquidation works
In a typical non-confidential money market protocol, liquidators would index all collateral and debt data off-chain and search for the most profitable opportunity. Unfortunately, this efficient means of unhealthy position discovery is impossible for Mirage, as publicly available debt data are not associated with lenders.
A reference liquidator implementation will be open source after Mirage mainnet launch to lower the barrier of running a liquidator.
Identifying unhealthy positions
Mirage only exposes data for users with unhealthy debt positions. Since it's impossible to know ahead of time which lenders are unhealthy, the only way to discovery unhealthy positions would be to first index the complete list of lender addresses, and call isUserUndercollateralized() on those addresses until true is returned.
Despite the inherent inefficiency, it's possible to optimize this process by using a Multicall contract, and also prioritizing lenders with the most collateral. With a sufficiently decentralized liquidator community, the health of Mirage can be properly maintained.
Fetching unhealthy position data
Once an undercollateralized position is identified, liquidators can invoke the getUserDeposit() and getUndercollateralizedUserDebt() functions to fetch user collateral and debt data, respectively. Combined with token price data fetched from the oracle, a complete liquidation transaction can be constructed.
Liquidation limit and incentives
When a user's debt position becomes unhealthy, a liquidator can repay a certain amount of the user's debts in exchange for the backing collateral. Mirage imposes a limit on the proportion of debt value against the user's total debt value that can be repaid in a single liquidate call. This is known as the liquidation limit. The latest liquidation limit value can be obtained by calling the liquidationLimit() function on the Mirage contract.
When a liquidation happens, the liquidator will be rewarded with their collateral of choice. First, the base amount is determined by simply calculating the amount of collateral token that would be of the same value as the debt amount repaid. Then, a proportion known as liquidation bonus is added to the base amount to arrive at a final amount.
The liquidation bonus setting is per-collateral, meaning that certain tokens could have a higher liquidation bonus than others, and thus be preferred by liquidators.
Example
Assume the current price of ETH is 1,000 USD; and the price of USDC is 1 USD. The collateral ratio of ETH is configured to be 0.8. The global liquidation limit is set to 0.3, whereas the liquidation bonus of USDC is 0.1. The following events happen:
-
Alice deposits
1ETH, which gives her800USD worth of borrowing power. She then takes out a loan of410USDC. -
Then, the price of ETH drops to
500USD. Alice's total borrowing power becomes400USD, which is now lower than her debt value. -
Bob discovers Alice's unhealthy position, as her position is no longer confidential due to being undercollateralized.
-
Bob could repay up to
123USDC in a single transaction, but he decides to only liquidate100USDC due to the lack of liquidity. Bob callsliquidate()to repay100USDC of Alice's debt, and receives0.22ETH from Alice's collateral. -
Now Alice has
0.78ETH left in collateral, which has a borrowing power of312USD. She only has310USDC in debt, so her position is healthy again, and hence no longer exposed by the protocol.
Zero leakage of healthy positions
As detailed in this page, liquidations in money market protocols could be susceptible to side-channel attacks. Despite this, Mirage is able to achieve zero leakage on healthy positions, while still allowing liquidations to function as expected.
This is achieved by making the 3 liquidation-related functions, namely isUserUndercollateralized(), getUndercollateralizedUserDebt(), and liquidate(), either completed constant-gas, or constant-gas-reverted. Check out this page for more details.