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

English auctions

The Milky on-chain program supports a second auction format alongside Dutch: the English auction, where bidders place ascending bids and the highest bidder at the end timestamp wins. This format is fully implemented and audited at the program level, but it is not the format the production keeper uses to liquidate defaulted loans today.

This page documents what English auctions look like for two audiences:

  • People exploring the on-chain program who want to understand all the paths it supports.
  • Future operators who may want to launch a Milky pool that uses English auctions for default resolution.

If you're a borrower or a casual auction participant, the format you'll actually encounter is Dutch. See Dutch auctions.

How the format works

English auctions are the classical ascending-bid format:

  • The auction opens with a reserve price equal to the loan's full payoff. The first bid must be at least the reserve.
  • Each subsequent bid must beat the current high bid by at least min_increment_bps of the current high amount (in basis points), or by 1 smallest token unit if that's larger.
  • The auction runs until end_ts. The bidder with the highest bid at that moment wins.

There is no notion of a "first acceptable bid wins" here — bids accumulate, and only the highest at the end matters.

Refunds

Each new bid both refunds the previous high bidder and pulls the new full bid amount into the auction's escrow vault, atomically in one instruction. This means:

  • A losing bidder gets their USDC back automatically when they're outbid.
  • There's no separate "claim refund" step in the normal path.
  • The escrow vault always holds exactly the current high bid and nothing else.

A BidCredit account type also exists in the program as a documented fallback for cases where the direct refund path can't run (rare). The production English path uses direct escrow refunds.

Anti-sniping

Unlike Dutch, English auctions support an anti-sniping mechanism that prevents last-second bids from winning without giving competitors time to react.

  • An anti-sniping window (configurable; the protocol's reference default is 5 minutes) defines how close to end_ts a bid is "late".
  • Late bids automatically extend end_ts by the anti_sniping_extend_secs value (also configurable; reference default is roughly equal to the window size).
  • A max_extensions counter caps how many times an auction can be extended this way (default cap: 3).

This balances the tradeoff between giving bidders fair reaction time and preventing an auction from running indefinitely.

Pricing dynamics

Because English auctions discover price upward through bidder competition, they tend to:

  • Clear at higher prices than Dutch auctions on the same card, if there are several active bidders.
  • Take longer in wall-clock time to resolve (English defaults run for hours or days; Dutch in production runs in minutes).
  • Be more sensitive to market depth — a single bidder can win at exactly the reserve price.

For a default-recovery use case, the choice between Dutch and English trades off speed (Dutch wins) against potentially higher recovery amounts (English can win on liquid collections with many active bidders).

Why production uses Dutch

The Milky team chose Dutch for the production default flow because:

  • Speed of resolution. A 5-minute Dutch auction settles defaults much faster than a multi-day English auction, freeing capital and reducing the duration of NAV uncertainty for LPs.
  • Simpler bidder UX. Dutch is "see price, accept price"; English requires monitoring and re-bidding.
  • Predictable operational tempo. Default resolution can be measured in minutes, which simplifies keeper operations and dashboarding.

That said, English remains a first-class format in the program: a future operator running their own pool with their own keeper can opt into it by passing auction_type: english (and the corresponding anti_sniping_* and min_increment_bps parameters) when they trigger default.