Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/reserve-protocol/reserve-index-dtf/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Folio auctions use a Dutch auction mechanism where prices move from optimistic to pessimistic over time. All token pairs trade simultaneously, and bidders can participate by:
  1. Direct bidding - Swap tokens at the current auction price
  2. Callback bidding - Execute custom logic before transferring tokens
  3. Trusted fills - Use aggregators like CowSwap for complex routing
Auctions have a 30-second warmup period to ensure fair competition. This is skipped for atomic swaps where start price equals end price.

Understanding Auction Mechanics

Surplus and Deficit

Auctions only allow trading between:
  • Surplus tokens: Tokens above the high basket limit
  • Deficit tokens: Tokens below the low basket limit
// Example: Check if a pair is tradeable
(uint256 sellAmount, uint256 bidAmount, uint256 price) = folio.getBid(
    auctionId,
    IERC20(weth),  // Must be in surplus
    IERC20(usdc),  // Must be in deficit
    type(uint256).max
);

if (sellAmount == 0) {
    // No surplus/deficit for this pair
}

Price Discovery

Prices follow an exponential decay curve:
  • Start: Most optimistic prices (favorable to Folio)
  • End: Most pessimistic prices (favorable to bidders)
  • Current: Interpolated based on time elapsed

Direct Bidding

The simplest way to participate in auctions.
1

Query Available Bids

Find profitable opportunities:
// Get current bid for selling WETH to buy USDC
(uint256 sellAmount, uint256 bidAmount, uint256 price) = folio.getBid(
    auctionId,
    IERC20(weth),    // Sell token
    IERC20(usdc),    // Buy token
    10e18            // Max WETH you want to receive
);

// Price is in D27 format: {buyToken/sellToken}
// Example: price = 2300e27 means 1 WETH = 2300 USDC
Compare the auction price against external markets (Uniswap, etc.) to identify arbitrage opportunities.
2

Approve Tokens

The Folio needs allowance to pull buy tokens from you:
IERC20(usdc).approve(address(folio), bidAmount);
3

Execute Bid

Submit your bid:
uint256 actualBidAmount = folio.bid(
    auctionId,
    IERC20(weth),      // Sell token (you receive)
    IERC20(usdc),      // Buy token (you pay)
    sellAmount,        // Exact amount of WETH you want
    bidAmount,         // Max USDC you're willing to pay
    false,             // withCallback = false for direct bid
    ""                 // No callback data needed
);

// You now have 'sellAmount' of WETH
// Folio took 'actualBidAmount' of USDC from you
After the bid:
  • Your WETH balance increases by sellAmount
  • Your USDC balance decreases by actualBidAmount
  • actualBidAmount should be ≤ bidAmount (your max)
4

Arbitrage on External Markets

Immediately trade your received tokens for profit:
// Example: Sell WETH on Uniswap for more USDC
ISwapRouter(uniswapRouter).exactInputSingle(
    ISwapRouter.ExactInputSingleParams({
        tokenIn: address(weth),
        tokenOut: address(usdc),
        fee: 3000,
        recipient: msg.sender,
        deadline: block.timestamp,
        amountIn: sellAmount,
        amountOutMinimum: bidAmount + minProfit,
        sqrtPriceLimitX96: 0
    })
);

Callback Bidding

For advanced strategies, use callbacks to execute custom logic within the bid transaction.
1

Implement IBidderCallee Interface

Your contract must implement the callback interface:
import { IBidderCallee } from "@interfaces/IBidderCallee.sol";

contract MyArbitrageur is IBidderCallee {
    function bidderCallback(
        IERC20 sellToken,
        IERC20 buyToken,
        uint256 sellAmount,
        uint256 buyAmount,
        bytes calldata data
    ) external override {
        // 1. Receive sellToken from Folio
        // 2. Execute your strategy (e.g., swap on DEX)
        // 3. Transfer buyToken back to Folio

        // Example: Flash arbitrage
        // Sell received sellToken on Uniswap
        _swapOnUniswap(sellToken, buyToken, sellAmount);

        // Transfer buyAmount back to Folio
        buyToken.transfer(msg.sender, buyAmount);
    }
}
2

Call Bid with Callback

bytes memory strategyData = abi.encode(
    uniswapPoolAddress,
    minProfitThreshold
);

folio.bid(
    auctionId,
    IERC20(weth),
    IERC20(usdc),
    sellAmount,
    bidAmount,
    true,          // withCallback = true
    strategyData   // Passed to your callback
);
Callback Flow:
  1. Folio transfers sellAmount of sell token to you
  2. Folio calls bidderCallback() on your contract
  3. Your callback executes and transfers buyAmount to Folio
  4. Folio verifies it received the tokens
Security Considerations:
  • Always validate msg.sender is the Folio in your callback
  • Set slippage limits to protect against sandwich attacks
  • Ensure callback execution is atomic (reverts return everything)

Trusted Filler Integration

Trusted fillers enable async execution using specialized solvers like CowSwap.
1

Create Trusted Fill

Instead of bidding directly, create a trusted fill order:
IBaseTrustedFiller filler = folio.createTrustedFill(
    auctionId,
    IERC20(weth),        // Sell token
    IERC20(usdc),        // Buy token
    cowSwapFillerAddr,   // Target filler (e.g., CowSwapFiller)
    keccak256(abi.encode(msg.sender, block.timestamp)) // Unique salt
);

// Folio has approved the filler to spend sellToken
// Filler now has entire block to execute the swap
The Folio will automatically close and claim tokens from the trusted filler at the next state-changing call.
2

Execute Fill (Solver Side)

The trusted filler contract handles the actual swap:
// CowSwap example: Create order on CoW Protocol
GPv2Order.Data memory order = GPv2Order.Data({
    sellToken: weth,
    buyToken: usdc,
    sellAmount: sellAmount,
    buyAmount: buyAmount,
    // ... other CowSwap parameters
});

// Submit to CowSwap for async settlement
cowSettlement.settle(orders, ...);
3

Monitor Fill Status

Check if the async swap is still active:
(bool syncActive, bool asyncActive) = folio.stateChangeActive();

if (asyncActive) {
    // Trusted fill is still executing
    // Wait before performing state-dependent operations
}

Bidding Requirements

If bidsEnabled is true for the rebalance, anyone can bid on auctions.
(, , , , , bool bidsEnabled) = folio.getRebalance();
require(bidsEnabled, "Permissionless bids disabled");
Bids cannot be placed on deprecated Folios:
require(!folio.isDeprecated(), "Folio deprecated");
Bids are only valid during the auction’s active period:
  • After warmup period (30 seconds, or 0 for atomic swaps)
  • Before end time
// getBid() will revert if auction is not ongoing
(uint256 sellAmt, , ) = folio.getBid(...);
require(sellAmt > 0, "No surplus/deficit");
You can only trade pairs where:
  • Sell token is in surplus (above high limit)
  • Buy token is in deficit (below low limit)
Not all tokens in an auction can be traded together at all times.

Advanced Strategies

Multi-Hop Arbitrage

Bid on multiple pairs in sequence:
// 1. Get WETH from Folio auction (pay USDC)
folio.bid(auctionId, IERC20(weth), IERC20(usdc), ...);

// 2. Trade WETH for DAI on Uniswap
uniswapRouter.swap(weth, dai, ...);

// 3. Get more USDC from Folio auction (pay DAI)
folio.bid(auctionId, IERC20(usdc), IERC20(dai), ...);

// Net: Started with X USDC, ended with X + profit USDC

Flash Loan Arbitrage

Use flash loans to amplify profits:
function executeFlashArbitrage() external {
    // 1. Flash borrow USDC from Aave
    aaveLendingPool.flashLoan(
        address(this),
        [address(usdc)],
        [borrowAmount],
        ...
    );
}

function executeOperation(
    address[] calldata assets,
    uint256[] calldata amounts,
    uint256[] calldata premiums,
    ...
) external override returns (bool) {
    // 2. Bid on Folio auction
    folio.bid(..., IERC20(weth), IERC20(usdc), ...);

    // 3. Sell WETH on external market
    _swapWETHForUSDC(...);

    // 4. Repay flash loan + premium
    IERC20(usdc).approve(address(aaveLendingPool), amounts[0] + premiums[0]);

    return true;
}

Monitoring Events

Listen to auction events for opportunities:
event AuctionOpened(
    uint256 indexed rebalanceNonce,
    uint256 indexed auctionId,
    address[] tokens,
    WeightRange[] weights,
    PriceRange[] prices,
    RebalanceLimits limits,
    uint256 startTime,
    uint256 endTime
);

event AuctionBid(
    uint256 indexed auctionId,
    address indexed sellToken,
    address indexed buyToken,
    uint256 sellAmount,
    uint256 buyAmount
);

Code Reference

  • Bid execution: contracts/Folio.sol:794-813
  • Get bid parameters: contracts/Folio.sol:776-783
  • Trusted fill creation: contracts/Folio.sol:816-847
  • Bid callback interface: contracts/interfaces/IBidderCallee.sol

Next Steps

Managing Rebalances

Learn how to start and configure rebalances

Minting & Redeeming

Understand how to mint and redeem Folio shares

Build docs developers (and LLMs) love