Auction Module

General Purpose

  • Auction Module stores, tracks, and updates Onomy stablecoin auctions and bidding processes.

Parameters

  • The Auction Module will set the following params:

type Params struct {
    // defines how long (either in blocktime or blockheight)
    // between each auction
    auction_periods time.Time|uint64

    // defines how long the auction will takes
    auction_durations time.Duration|uint64

    // period between each price reduction
    reduce_step time.Time|uint64

    // rate compared with the collaterals price from the
    // oracle at which the auction will start with
    starting_rate float64

    // rate compared with the initial price that the price
    // can drop to
    lowest_rate float64

    // rate that are decrease every reduce_step
    discount_rate float64

}

Required API

Vault Module

Vault Module needs to be exposed to the following APIs:

  • ShouldStartAuction checks the vault status and returns information needed for the auction if needed.

  • LiquidateVaults return the auction results back to vault once the auction is over.

High Level Design

Auction Module is implementing the Dutch Auction method which mean the price are decrease until a user bid for that price or the price reach floor price.

Auction Initialization

At the beginning of each block auction module, we check for auction periods. If a new auction period is reached, the auction module calls over vault module to check if any vaults are in debt, with assets needing to be liquidated. Vault module returns the information needed to create an auction.

For example:

func (k auctionKeeper) CreateAuction(ctx context, item sdk.Coins, startTime, duration time.duration, initialPrice sdk.Coin) error

An auction is defined as:

type Auction struct {
    start_time time.Time

    // to delete if no bidder found
    ExpiredTime time.Time

    auction_id string

    // biddingItem here are the collateral are being
    // auctioned of
    bidding_item sdk.Coins

    // price are based on usd ~ IST stable coin
    initial_price sdk.Coin

    // queue of bid entries map between bidder address
    // and the Bid entry
    bid_queue map[string]Bid
}

type Bid struct {
    amount sdk.Coin
}

Auction Update Per Block

For each beginning block, we update the auctions' information accordingly.

This includes:

  • Checks for auction start time to start the process and open for bidding.

  • Checks for auction expired time - at this point, the auction will be closed for bid entries to start the final logic.

  • Check if the auction has reached the next reduce_step to update the price based on discount_rate. If the price dips to lowest_rate, it stops the discount process even if the next reduce_step is reached.

  • Checks if there are any bid entries matching the current price. If there is, it then updates the auction status.

Bidding Process

The bidder can submit transactions to participate in auctions.

For example:

message MsgBid {
    string auction_id = 1
    string bidder = 2
    sdk.Coin amount = 3
}
  • The bidding process occurs throughout the auction process. Users can submit entries that indicate the amount they are willing to pay.

  • Uses a queue to store all bid entries. There can be a single entry with X amount. Other entries with the same amount will be rejected since there is already an earlier entry submitted.

  • Each user can only submit one entry. To update the entry, user can submit a message MsgUpdateBid. Trying to call MsgBid will return an error if the user has already submitted an entry.

For example:

message MsgUpdateBid {
    string auction_id = 1
    string bidder = 2
    sdk.Coin amount = 3
}
  • Upon updating the entry, user will transfer or receive the difference in the amount.

  • TBD: Users can only update bid a number of times before a period or there will be a minimum step of amount update-able to prevent spamming.

  • When the price is dropped to an amount that is less than or equal to the highest bid in the queue, then that bid is considered the winner. The auction status is updated and further msgBids submitted to this auction will return an error.

  • The amount bidder put in the message will then transfer to an auction module account. If the bid goes through and the bidder won, the bid amount will then transfer from the auction module back to vault module's account.

Note: As oUSD is the first stablecoin to be released, bidders will only be able to use this token for bidding. As more Onomy stables are minted, this may change.

End Process

By the end of the auction, all the winning collateral is transferred to the winner. The auction module will return the auction results back to vault module for further assessment, with the result including:

  • The amountof $NOM raised in each auction

  • The remaining collateral

The vault module then checks whether it's enough to pay off the vault debt. Depend on the result, we split into two main cases:

Auction results will be defined as a struct:

type AuctionResults struct {
    results []AuctionResult
}

type AuctionResult struct {
    // IST token
    raised_token sdk.Coin

    // id of the auction that the result belongs to
    auction_id string

    // remainning collaterals
    unsold_collateral sdk.Coins
}

  1. The auction has raised enough to cover the debt

  • The vault module burns the $NOM raised in the auction.

  • Any remaining collateral will be used to calculate the liquidation penalty and transfer to the reserve account.

  • Then, it transfers those that remain back to the vault holder account.

  • Transfers the bidding amount back to vault module for processing.

  1. The auction hasn't raised enough to cover the debt

Option 1: All collateral sold and the debt is not covered

  • The vault module burns the $NOM raised in the auction.

  • The reserve module is called to store the shortfall information, then the DAO can handle the situation through the reserve module.

Option 2: Collateral remains but debt is still not covered by $NOM raised by the end of the auction

  • vault module burns the $NOM raised in the auction.

  • Any remaining collateral will be used to calculate the liquidation penalty and transfer to the reserve account.

The Vault module iterates through the vaults that were liquidated and attempts to reconstitute them (minus collateral from the liquidation penalty) starting from the best CR to worst.

  • Reconstitution means full prior debt AND full prior collateral minus collateral used from penalty.

  • Collateral used for penalty = vault debt / total debt * total liquidation penalty.

  • Debt that is given back to a vault should be subtracted from the vault module's view of remaining liquidation debt (i.e., it shouldn't be double counted)

  • Reconstituted vaults are set to OPEN status (i.e., they are live again and able to be interacted with

  • When the vault module reaches a vault it cannot fully reconstitute (both full debt and collateral as described above), it marks that vault as liquidated. It then marks all other lower CR vaults as liquidated.

  • Any remaining collateral is transferred to the reserve account.

  • Any remaining debt (subtracting debt that was given back to reconstituted vaults, as described above) is informed to the reserve module as shortfall.

Last updated