Skip to main content

Overview

Reserve Folio uses Dutch auctions to rebalance portfolio holdings. Each auction runs on all surplus/deficit token pairs simultaneously, with prices decaying exponentially from optimistic to pessimistic estimates.

Auction Lifecycle

Auctions progress through several states:
1

Uninitialized

Auction hasn’t been created yet
  • startTime == 0
  • endTime == 0
2

Pending

Auction created but not yet started
  • block.timestamp < startTime
3

Warmup

30-second warmup period to ensure fair competition
  • block.timestamp >= startTime
  • block.timestamp < startTime + 30
  • No bidding allowed yet
Warmup is bypassed for atomic swaps when start and end prices are equal
4

Open

Active bidding period
  • block.timestamp >= startTime + 30
  • block.timestamp <= endTime
  • Anyone can bid
5

Closed

Auction has ended
  • block.timestamp > endTime

Opening Auctions

Auctions can be opened in two ways:

Restricted Opening (by AUCTION_LAUNCHER)

During the restricted period, only the AUCTION_LAUNCHER can open auctions:

Unrestricted Opening

After the restricted period, anyone can open auctions using spot values:
Unrestricted auctions use spot values for both limits and weights, with initial price ranges.

Price Curves

Auction prices decay exponentially over time between start and end prices.

How Prices are Calculated

Price Curve Visualization

Auction Price Curve
The first block may not have exactly startPrice if it doesn’t occur on the start timestamp. Similarly for endPrice and the final block.

Lot Sizing

Auction lot sizes are determined by surplus and deficit calculations relative to target basket limits and weights.

Surplus and Deficit

  • Surplus: Token balance exceeds high weight × high BU limit
  • Deficit: Token balance is below low weight × low BU limit

How Lot Size Changes

The sellAmount can increase or decrease over time:

Increasing Lot Size

When surplus of sell token is the limiting factorAs the auction progresses and some tokens are sold, the surplus decreases relative to progressively narrowing limits, allowing larger lots.

Decreasing Lot Size

When deficit of buy token is the limiting factorAs buy tokens are acquired, the deficit shrinks relative to progressively narrowing limits, requiring smaller lots.

Max Auction Size

Governance can set a maximum auction size per token:
This prevents overly large single auctions that could face excessive slippage.

Bidding on Auctions

Anyone can bid on an ongoing auction during the open period.

Getting Bid Information

Query current auction prices and lot sizes:

Submitting a Bid

Bid using allowances or callbacks:
Bids must be enabled for the rebalance. Check rebalance.bidsEnabled before attempting to bid.

Trusted Fillers

As an alternative to direct bidding, trusted fillers enable asynchronous swaps.

Creating a Trusted Fill

Trusted fillers must be enabled via trustedFillerEnabled and a valid registry must be set.

Trusted Filler Flow

1

Create Fill

Caller creates a trusted fill contract for the auction
2

Approve Tokens

Folio approves sell tokens to the trusted filler
3

Execute Swap

Trusted filler executes swap asynchronously (within same block)
4

Close Fill

Folio reclaims all token balances from the filler

Closing Auctions

Privileged roles can close auctions early:
Closing an auction before startTime would break the invariant that endTime > startTime, so closing very early auctions will not revert but may have unexpected behavior.

Multiple Auctions per Rebalance

A single rebalance can have many auctions, but only one runs at a time.

Sequential Auction Strategy

The AUCTION_LAUNCHER can overwrite an ongoing auction, but unpermissioned callers must wait for the current auction to close.

Price Control Modes

The level of price control granted to AUCTION_LAUNCHER affects auction behavior:
No Price ControlAUCTION_LAUNCHER cannot modify prices from initial ranges.
  • Auction length must be maxAuctionLength
  • Prices fixed to governance-set ranges
  • Most decentralized option
Higher price control modes grant more power to the AUCTION_LAUNCHER. Use ATOMIC_SWAP only with highly trusted operators.

Auction Best Practices

  • Progressively narrow BU limits to responsibly DCA into new basket
  • End rebalance when prices move outside initially-provided ranges
  • If weightControl=true: Progressively narrow weight ranges to maintain intent
  • If priceControl=PARTIAL: Provide narrowed price ranges that include current clearing price
  • If priceControl=ATOMIC_SWAP: Fill atomically and end rebalance immediately after
  • Monitor price decay to find optimal entry point
  • Account for gas costs in profitability calculations
  • Use maxBuyAmount to protect against slippage
  • Consider competing bidders and MEV searchers
  • For large bids, consider multiple smaller bids over time
  • Set price ranges conservative enough to avoid value leakage
  • Configure auction length appropriate for expected volatility
  • Set maxAuctionSize to prevent excessive single-auction slippage
  • Monitor AUCTION_LAUNCHER behavior and revoke if malicious
  • Use lower price control modes when possible