Liquidation Auctions
State
avl_storage
: data structure containing a mapping from pointers to auctions and liquidation slices, serving as a memory.queued_slices
: a pointer to the queue of liquidation slices awaiting inclusion in an auction.current_auction
: information about the current auction if there is an active auction.contents
: a pointer to the set of slices in the current auction.auction_state
: whether the auction is in the descending or ascending phase, and data used to calculate the current price.
completed_auctions
: a queue (represented as a doubly-linked list) of completed auctions, each auction containing:a set of untouched slices
the result of an auction, containing the amount of tez sold, amount of kit gained and the winner of an auction.
At any point in time, any liquidation slice is in only one of the above
sets, and they always move from queued_slices
, to
current_auction
and then to completed_auctions
, (then they
disappear). Additionally, this move always happens in order, so an older
liquidation_slice is always further in the process than a younger one.
NOTE: Per-burrow liquidation_slices We need to have access to the
liquidation slices for a specific burrow; so slices for a burrow form a
doubly-linked list, each burrow storing a pair of pointers called
liquidation_slices
, pointing to the first and the last liquidation
slice of that burrow (if they exist).
See <./avl_diagram.drawio> file for an illustration.
Initiating a liquidation
When liquidation of a burrow is triggered, the amount of tez to be
liquidated form a liquidation_slice
. * For details about this
process, see <./burrow-state-liquidations.md>.
The new slice is added to the back of the queued_slices
queue.
NOTE: This operation also updates the per-burrow linked list.
Cancelling a liquidation slice
Burrows can cancel auctioning off their liquidation slices on certain
conditions. When cancelling a slice, we check if the slice belongs to
the queued_slices
, if so, remove it from the set (returning contents
back to the burrow). If not, the process fails.
NOTE: This operation also updates the per-burrow linked list.
NOTE: This requires a the queue to have an efficient membership test.
NOTE: This requires a the queue to support efficient random deletes.
Lot auction
At any time checker is touched, when there is no auction running and there is at least one queued slice, we start an auction.
Our aim is to take a prefix of the queued_slices
queue which
contains exactly this amount of tez:
min
total_queued_tez
(max
Constant.max_lot_size
(total_queued_tez * Constants.min_lot_auction_queue_fraction))
However, it is likely that in this process the slices will not add up to
the exact amount. In this case, we take the liquidation_slice causing
the overload, split it into two, and push the halves to the end of the
new auction and in front of the queued_slices
.
NOTE: This splitting process has to be efficient, since a single auction likely consists of many small slices. So it needs to be done without traversing the entire prefix. This pretty much forces us to use a tree-like structure with branches containing the aggregate tez information of their sub-trees.
Then we start an auction. An auction has minimum_bid value that is a function of current time and the latest bid.
Every bid should be of at least minimum_bid
amount of kit. The bidding
process debits the bid’s kit from the contract’s kit ledger and credits back
the kit of the previously winning bid if one exists.
The auction is initially a descending auction, with the minimum bid calculated as:
amount_of_tez_inside_auction
* tz_minting
* q
* ((1 - Constants.auction_decay_rate) ^ time_elapsed_since_auction_start)
After the first bid, it becomes an ascending auction, with the minimum bid calculated as:
leading_bid * (1+Constants.bid_improvement_factor)
The auction finishes when the longer of 20 blocks or 20 minutes are passed after the last bid.
Touching a liquidation_slice
“Touching the liquidation slice” is the process of propagating the result of a completed auction back to the burrows. When it is triggered, we:
Check if the given slice belongs to a completed auction, ignore otherwise.
Remove the slice from the contents of the relevant completed_auction.
Remove the slice from the linked list at relevant burrows
liquidation_slices
.
Claiming a winning bid
If a bid is the winning bid of a completed auction where all the liquidation_slices are touched (in other words, its contents are empty), the bidder can claim the auction’s winnings. This process is the final step of an auction, and after that the auction itself is cleaned up.
Maintenance
Every time the main checker contract is touched, it touches
Constants.number_of_slices_to_process
amount of oldest
liquidation_slice’s automatically.