Liquidatable
Note that the ExpiringMultiParty
code simply inherits Liquidatable
and adds no additional functionality. Therefore, these two names essentially describe the same thing. All of the code can be viewed in Liquidatable
.
How Liquidations Work
If a sponsor is holding a synthetic asset position that Alice believes is undercollateralized, she can start a liquidation for this position by calling createLiquidation
(see below). A liquidation can target the entire position or just a part of it; this is determined by how much synthetic asset Alice transfers during the call (set by maxTokensToLiquidate
). Alice must also include ooReward
collateral to pay for the Optimistic Oracle’s price request in the case of a dispute (but she gets this back if there is no dispute or if the dispute is ruled in her favour).
Note that as soon as a liquidation has begun in this way, the position is immediately reduced for the amount of the liquidation; even if it’s ultimately successfully disputed the position will be reduced (or removed); in that case, the holder of the position would be compensated with any excess collateral of the liquidated portion, as well as a reward that scales with the size of the liquidation based on sponsorDisputeRewardPercentage
(see below).
The liquidation stays open to disputes for a time period called liquidationLiveness.
If no disputes come in during this time, the contract “optimistically” assumes Alice was correct. Alice would then receive a proportional amount of collateral from the position: if she had submitted 50% of the position.tokensOutstanding
debt, she would receive 50% of the collateral in the position.
As a natural consequence, the higher the collateralRequirement
is, the more rewarded Alice is: if 1.5 (aka 150%), Alice would have essentially traded in the synthetic token for 150% of its value in the collateral token (this assumes the position was only barely undercollateralized). She could then of course trade this on the open market and return with more of the synthetic asset to perform more liquidations if there were still any liquidatable positions.
Anyone who can pay the disputer bond and their own ooReward
can dispute this liquidation, before liquidationLiveness
has passed. Disputing triggers a price request for the asset from UMA’s OptimisticOracle, which uses priceIdentifier
and ancillaryData
to determine which asset to price and how to price it.
withdrawLiquidation
can be called either when liquidationLiveness
has passed without any disputes, or once the OptimisticOracle has a price available for a dispute’s price request. This function settles a dispute if there is one by comparing the price to the position’s balances, and sends out rewards to various parties (disputer, liquidator, sponsor).
Interaction with “Slow Withdrawals”
The behaviour of liquidations and slow withdrawals (see requestWithdrawal
from 2. PricelessPositionManager) interrelate in a few ways.
Any slow withdrawal is also reduced by the same proportion the position was reduced by, as a result of starting the liquidation.
Upon dispute, the position health is determined after taking into account any pending slow withdrawals, as if they have already gone through. Thus a position that is undergoing a slow withdrawal for most of its collateral is more likely to be ruled insolvent and punished. This allows liquidators to react to slow withdrawals which, unlike fast withdrawals, are not limited to the amount of collateral they can withdraw.
Liquidations over the “griefing threshold” (currently arbitrarily set to
minSponsorPosition
) cause the countdown timer on withdrawals to reset. The purpose of this behaviour is to allow liquidators time to gather funds and liquidate chunks of a position that’s undergoing massive withdrawals while preventing small “troll” liquidations to be able to trigger this timer reset.
State Variables
liquidations
contains, for each sponsor address, an array of LiquidationData
objects. When a liquidation is created, a LiquidataionData
object is appended to the array of liquidations for that sponsor. These objects track the lifetime of a liquidation, through any possible dispute, and are zeroed out when the liquidation resolves one way or another. Some of these members are clear enough from the code/comments; here are some helpful comments for the rest:
state
simply tracks the state in aStatus
enum. Any active liquidation will never actually be in theUninitialized
state.liquidationTime
is the timestamp of when the liquidation started. This timestamp is also used when sending price requests to the optimistic oracle for any possible disputes. It’s the price “at this time” that is the subject of this liquidation.tokensOutstanding
andlockedCollateral
represent how much of the position is being liquidated, in terms of synthetic token debt and collateral, respectively.lockedCollateralAfterWithdrawals
: The amount of collateral that would be locked in the liquidation if all pending slow withdrawals went through. The sole purpose of this variable is to be used during disputes: by considering the amount of collateral a position will have after withdrawals go through, liquidations can occur for positions that attempt to withdraw so much that their CR would go belowcollateralRequirement
.finalFee
: The liquidator and disputer must each include this as a bond. If there is no dispute, the liquidator gets this back. If there is a dispute, then the contract will have receivedfinalFee*2
in total.finalFee
is sent along to the oracle as a reward, andfinalFee
whoever wins the dispute (liquidator or disputer) getsfinalFee
back.
liquidationCollateral
stores the total amount of collateral in all liquidations; liquidationCollateral + totalPositionCollateral
should always equal the sum of all actual collateral held in the EMP contract.
Immutable (set at construction) Variables
liquidationLiveness
is the minimum amount of time a liquidation stays open for dispute. If no dispute occurs before this time, the liquidator can withdraw the liquidation, and no call to the optimistic oracle is made.
collateralRequirement
is the ratio of collateralization under which a position can be legitimately liquidated. In contrast to the GCR described in PricelessPositionManager, this ratio is ultimately calculated with the worth of the synthetic token debt versus the collateral held (during a dispute, when the price is available). If this value is set to 1.25, this means that any position that has less than 125% of the debt value deposited as collateral, can be legitimately liquidated by liquidators.
The next three variables are all expressed as a FixedPoint
decimal, where i.e. 0.1 indicates 10%.
disputeBondPercentage
determines the amount the disputer has to put up as a bond, as a percentage of the liquidations lockedCollateral
. Note that this is not the only fee the disputer has to pay; see finalFee
above in the LiquidationData
struct.
sponsorDisputeRewardPercentage
: In the case of a successful dispute, this is the reward paid to the sponsor (whose position has just been liquidated), expressed as a percentage of the amount that was under liquidation.
disputerDisputeRewardPercentage
: In the case of a successful dispute, this is the reward paid to the disputer, expressed as a percentage of the amount that was under liquidation.
External/Public State-Changing Functions
createLiquidation
starts a liquidation claim on any sponsor’s position. The sender must provide some amount of the synthetic asset (maxTokensToLiquidate
) as well as ooReward
collateral as a bond that will get refunded except in the case of a successful dispute. The next two arguments, minCollateralPerToken
and maxCollateralPerToken
dictate a max and min value for the ratio of collateral the liquidator expects to get back, for each of the synthetic tokens provided (specified in FixedPoint
decimals; i.e. 10^18 = 1.0). The last argument specifies a deadline after which the transaction will fail. All of these last three arguments are guards built for the convenience of the caller, to dictate under which terms he is willing to initiate the liquidation.
dispute
can be called on any open liquidation. The caller must supply collateral equal to (disputeBondPercentage * position.lockedCollateral) + ooReward
, both of which are returned (plus a reward) upon a successful dispute. This function requests a price from the OptimisticOracle.
withdrawLiquidation
can be called for a liquidation if either:
No dispute has occurred for the liquidation and the
liquidationLiveness
period has passed.If a dispute has occurred, and the OptimisticOracle has a price ready in response to the request made when
dispute
was called.
This function calls _settle
(see below) to settle a dispute if there is one. It then rewards the three parties accordingly to the outcome of any dispute.
_settle
is called in withdrawLiquidation
to settle any active dispute for a given liquidation, using the OptimisticOracle’s returned price. If the oracle has no price available, the function reverts. Otherwise, it fetches the price and stores it in liquidation.settlementPrice
, calculates requiredCollateral
by multiplying the price by the liquidation.tokensOutstanding
debt, and checks to see if liquidation.lockedCollateralAfterWithdrawals
meets this obligation.
Last updated