DEVNETYou are on Solana devnet. Funds are not real. Behavior matches mainnet.

Auctions overview

Auctions are how Milky resolves a loan that didn't get repaid in time. The goal of an auction is simple: sell the collateral card for enough to repay the lender, take a protocol cut of any surplus, and do it through a transparent on-chain process anyone can audit.

In production, every default auction is a Dutch auction with a short duration and a defined starting price. The protocol also supports English auctions at the on-chain level — they exist as an option in the program — but the keeper that triggers production defaults uses the Dutch format exclusively.

This page covers the shared lifecycle. Format-specific behavior lives in Dutch auctions and English auctions.

When does an auction start?

An auction can start as soon as a loan becomes eligible for default — that is, when the current cluster time is greater than maturity_ts + grace_period_secs. Until then, the borrower can still repay on the original terms.

Once the loan is default-eligible, the loan_mark_default_and_start_auction instruction can be submitted by anyone. It atomically:

  • Marks the loan as Defaulted.
  • Initializes a new Auction account for that loan.
  • Opens a USDC bid escrow vault tied to the auction.
  • Sets the auction's start and end timestamps based on the requested duration parameter.

Because anyone can call this instruction, in practice it is a keeper bot operated by Milky (or a third party) that watches for newly default-eligible loans and submits the transaction. The starter pays the rent for the new accounts, but is reimbursed at settlement (or at no-bid cancel), giving keepers a small economic incentive to be timely.

What an auction account holds

A live Auction account stores:

  • A reference to the loan it's resolving (and therefore to the collateral NFT and the pool).
  • The reserve price — the full payoff (principal + fixed_interest_due) the auction must clear to fully repay the lender.
  • Timingstart_ts, end_ts, duration_secs.
  • Format — Dutch or English (auction_type).
  • Bid state — for English: highest bidder and amount; for Dutch: whether a bid has landed yet (which immediately ends the auction).
  • A bid escrow vault — the USDC vault holding the current high bidder's funds.
  • Anti-sniping config (English only) — the window before end_ts in which a bid extends end_ts, and a cap on total extensions.

The collateral during the auction

The card stays in the protocol's collateral vault (the loan's collateral account) for the entire auction. The loan's loan_authority PDA remains the delegate, so when settlement happens the protocol can sign the transfer to the auction winner without needing the borrower's signature.

The borrower has no on-chain claim on the card from the moment the default instruction lands — that's the entire point of the default transition.

What ends an auction

There are three ways an auction reaches a terminal state:

  • A bid lands and settlement runs (English: at end_ts; Dutch: on bid). The card transfers to the winner; USDC is split per the settlement waterfall; the loan account, locks, and auction account close and refund their rent.
  • No bid is received before end_ts and auction_cancel_if_no_bids is called. The card moves to a pool-held custody account; loan and auction accounts close. See no-bid outcome.
  • The auction is "stuck" — for example, if no keeper triggers either settlement or no-bid cancel. The auction account remains open until someone does. The protocol does not have an automatic timeout.

Permissioning

Different auction operations have different signers:

  • Starting the auction. Anyone can submit loan_mark_default_and_start_auction once the loan is default-eligible.
  • Bidding. Anyone can bid (English) or accept the current Dutch price.
  • Settlement. The winner must sign the settlement transaction (it transfers the card to them). The Milky app bundles bid + settle in a single Dutch transaction so this is invisible to the bidder.
  • No-bid cancellation. Anyone can submit auction_cancel_if_no_bids after the auction expires with zero bids; the rent refund creates a small keeper incentive.
  • Pause behavior. New bids are blocked while the protocol is globally paused; settlement is intentionally not pause-blocked, so winners can always claim cards they've legitimately bought.