Surplus Auction House
1. Summary
The surplus auction is used to sell off a fixed amount of the surplus in exchange for protocol tokens. The surplus comes from the stability fees charged to SAFEs (and stored in the AccountingEngine
). Bidders submit increasing amounts of protocol tokens and the winner receives all auctioned surplus in exchange for their coins which are burned or transferred to another address.
2. Contract Variables & Functions
Variables
contractEnabled
- settlement flag (available only in the pre-settlement surplus auction house)AUCTION_HOUSE_TYPE
- flag set tobytes32("SURPLUS")
authorizedAccounts[usr: address]
- addresses allowed to callmodifyParameters()
anddisableContract()
.bids[id: uint]
- storage of allBid
s byid
safeEngine
- storage of theSAFEEngine
's addressprotocolToken
- address of the protocol tokenauctionsStarted
- total auction countbidDuration
- bid lifetime / max bid duration (default: 3 hours)bidIncrease
- minimum bid increase (default: 5%)totalAuctionLength
- maximum auction duration (default: 2 days)protocolTokenBidReceiver
- receiver of protocol tokens after an auction is settled. Only present in theRecyclingSurplusAuctionHouse
.
Data Structures
Bid
- state of a specific auctionbidAmount
- quantity being offered for theamountToSell
amountToSell
- amount of surplus soldhighBidder
bidExpiry
auctionDeadline
- when the auction will finish
Modifiers
isAuthorized
**** - checks whether an address is part ofauthorizedAddresses
(and thus can call authed functions).
Functions
modifyParameters(bytes32 parameter
,uint256 data)
- update auint256
parameter.modifyParameters(bytes32 parameter
,address addr)
- update anaddress
parameter. Only present in theRecyclingSurplusAuctionHouse
.startAuction(amountToSell: uint256
,initialBid: uint256)
- start a new surplus auction.restartAuction(id: uint256)
- restart an auction if there have been 0 bids and theauctionDeadline
has passed.increaseBidSize(id: uint256
,amountToBuy: uint256
,bid: uint256)
- submit a bid with an increasing amount of protocol tokens for a fixed amount of system coins.disableContract()
- disable the contract.settleAuction(id: uint256)
- claim a winning bid / settles a completed auction.terminateAuctionPrematurely(id: uint256)
- is used in case Governance wishes to upgrade (only) thePreSettlementSurplusAuctionHouse
or in caseGlobalSettlement
is triggered. It settlesincreaseBidSize
phase auctions, sending back the protocol tokens submitted by thehighBidder
.
Events
AddAuthorization
- emitted when a new address becomes authorized. Contains:account
- the new authorized account
RemoveAuthorization
- emitted when an address is de-authorized. Contains:account
- the address that was de-authorized
ModifyParameters
- emitted after a parameter is modifiedRestartAuction
- emitted after an auction is restarted. Contains:id
- the ID of the auction being restartedauctionDeadline
- the new auction deadline
IncreaseBidSize
- emitted when someone bids a higher amount of protocol tokens for the same amount of system coins. Contains:id
- the ID of the auction that's being bid onhighBidder
- the new high bidderamountToBuy
- the amount of system coins to buybidAmount
- the amount of protocol tokens bidbidExpiry
- the new deadline when the auction will end which can be before the originalauctionDeadline
StartAuction
- emitted whenstartAuction(uint256
,uint256)
is successfully executed. Contains:id
- auction idauctionsStarted
- total amount of auctions that have started up until nowamountToSell
- amount of system coins sold in the auction.initialBid
- starting bid for the auctionauctionDeadline
- the auction's deadline
SettleAuction
- emitted after an auction is settled. Contains:id
- the ID of the auction that was settled
DisableContract
- emitted after the contract is disabledTerminateAuctionPrematurely
- emitted after an auction is terminated before its deadline. Contains:id
- the ID of the auction that was terminatedsender
- the address that terminated the auctionhighBidder
- the auction's high bidderbidAmount
- the latest bid amount
3. Walkthrough
In a surplus auction, bidders compete for a fixed amountToSell
of system coins with increasing bidAmount
s of protocol tokens.
The surplus auction ends when the last bid's duration is passed (bidDuration
) without another bid getting placed or when the auction duration (totalAuctionLength
) has been surpassed. When the auction settles, the protocol tokens received are burnt in the case of a BurningSurplusAuctionHouse
or transferred to a separate address in the case of RecyclingSurplusAuctionHouse
.
In case governance disables the surplus auction house by calling disableContract
, anyone can call terminateAuctionPrematurely
in order to quickly settle an auction and return the protocol token bid to the highBidder
.
4. Gotchas (Potential source of user error)
Keepers
In the context of running a keeper (more info here) in order to perform bids within an auction, a primary failure mode could occur when a keeper specifies an unprofitable price for ODG.
- This failure mode is due to the fact that there is nothing the system can do to stop a user from paying significantly more than the fair market value for the token in an auction (this goes for all auction types,
collateral
,surplus
, anddebt
). - Keepers that are performing badly in a
surplus
auction run the risk of overpaying ODG for the Coin as there is no upper limit to thebidAmount
size other than their ODG balance.
Bid Increments During an Auction
During increaseBidSize
, bidAmount
amounts will increase by a bidIncrease
percentage with each new increaseBidSize
. The bidder must know the auction's id
, specify the right amount of amountToSell
for the auction, bid at least bidIncrease
% more than the last bid and must have a sufficient ODG balance.
One risk is "front-running" or malicious miners. In this scenario, an honest keeper's bid of [Past-bid + bidIncrease
%] would get committed after the dishonest keeper's bid for the same, thereby preventing the honest keeper's bid from being accepted and forcing them to rebid with a higher price ((Past-bid + bidIncrease) + bidIncrease)). The dishonest keeper would need to pay higher gas fees to try to get a miner to put their transaction in first or collude with a miner to ensure their transaction is first. This could become especially important as the bid reaches the current market rate for ODG Coin.
Quick Example:
The bidIncrease
could be set to 3%, meaning if the current bidder has placed a bid of 1 ODG, then the next bid must be at least 1.03 ODG. Overall, the purpose of the bid increment system is to incentivize early bidding and make the auction process move quickly.
Placing Bids Incorrectly
Bidders send ODG tokens from their addresses to the system/specific auction. If one bid is beat by another, the losing bid is refunded back to that bidder’s address. It’s important to note, however, that once a bid is submitted, there is no way to cancel it. The only possible way to have that bid returned is if it is outbid (or if the system goes into Global Settlement).
Illustration of the bidding flow:
- AccountingEngine
startAuction
's a new Surplus Auction. - Bidder 1 sends a bid (ODG) that increases the
bidAmount
above the initial 0 value set during thestartAuction
. Bidder 1's ODG balance is decreased and the SurplusAuctionHouse's balance is increased by the bid size.bid.highBidder
is reset from the AccountingEngine address to Bidder 1's andbid.bidExpiry
is reset tonow + bidDuration
. - Next, Bidder 2 makes a bid that increases Bidder 1's bid by at least
bidIncrease
. Bidder 2's ODG balance is decreased and Bidder 1's balance is increased by Bidder 1'sbidAmount
. The difference between Bidder 2's and Bidder 1'sbidAmount
is sent from Bidder 2 to the SurplusAuctionHouse. - Bidder 1 then makes a bid that increases Bidder 2's
bidAmount
by at leastbidIncrease
. Bidder 1's ODG balance is decreased and Bidder 2's ODG balance is increased by Bidder 2'sbidAmount
. The amount Bidder 1 increased the bid is then sent from Bidder 1 to the SurplusAuctionHouse. - Bidder 2, as well as all the other bidders participating within the auction, decide it is no longer worth it to continue to bid higher
bidAmount
s, so they stop making bids. Once theBid.bidExpiry
expires, Bidder 1 callssettleAuction
and the surplus Coin tokens are sent to the winning bidder's address (Bidder 1) in theSafeEngine
and the system then burns the ODG received from the winning bidder.gem.burn(address(this), bids[id].bid)
.
5. Failure Modes (Bounds on Operating Conditions & External Risk Factors)
- Resulting from when ODG is burned
- There is the possibility where a situation arises where the ODG token makes the transaction revert (e.g. gets stopped or the AccountingEngine's permission to call burn() is revoked). In a case like this, deal can't succeed until someone fixes the issue with the ODG token. In the case of stoppage, this could include the deploying of a new ODG token. This new deployment could be completed by any individual using the MCD System but governance would need to add it to the system. Next, it would need to replace the old surplus and debt auctions with the new ones using the new ODG token. Lastly, it is crucial to enable the possibility to vote with the new version as well.
- When there is massive surplus
- This would result in many SurplusAuctionHouse auctions occurring as the surplus over
surplusAuctionAmountToSell
+surplusBuffer
is always auctioned off insurplusAuctionAmountToSell
increments. However, auctions run concurrently, so this would "flood the keeper market" and possibly result in too few bids being placed on any auction. This could happen through keepers not bidding on multiple auctions at once, which would result in network congestion because all keepers are trying to bid on all of the auctions. This could also lead to possible keeper collusion (if the capital pool is large enough, they may be more willing to work together to split it evenly at the system's expense).
- This would result in many SurplusAuctionHouse auctions occurring as the surplus over