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

Basket weights define how tokens are proportioned within a Folio. During rebalancing, weight ranges allow the AUCTION_LAUNCHER to progressively adjust token ratios within bounds set by governance.

Basket Unit (BU)

A Basket Unit (BU) is a theoretical unit of account representing a standardized bundle of the underlying tokens:
// D18{BU/share}
struct RebalanceLimits {
    uint256 low;   // (0, 1e27] Buy assets up to this limit
    uint256 spot;  // (0, 1e27] Point estimate for unrestricted calls
    uint256 high;  // (0, 1e27] Sell assets down to this limit
}
Typical usage: BUs are defined 1:1 with shares (1e18), but the protocol supports ranges up to 1e27.

Calculating Total Baskets

For a Folio with total supply of shares:
// {BU} = {share} * D18{BU/share} / D18
uint256 totalBaskets = (totalSupply * basketLimit) / 1e18;

Weight Ranges

// D27{tok/BU}
struct WeightRange {
    uint256 low;   // [0, 1e54] Minimum weight (buy target)
    uint256 spot;  // [0, 1e54] Point estimate
    uint256 high;  // [0, 1e54] Maximum weight (sell target)
}
Weights define how many token quanta comprise one basket unit.

Example: 60/40 Portfolio

// Target: 60% WETH / 40% USDC by value
// Assume: WETH = $3000, USDC = $1
// Portfolio value: $100,000

// WETH: $60,000 / $3000 = 20 WETH
// USDC: $40,000 / $1 = 40,000 USDC

// Per BU (assume 100 shares outstanding, 1 BU/share):
WeightRange memory wethWeight = WeightRange({
    low:  0.19e27,  // 0.19 WETH/BU
    spot: 0.20e27,  // 0.20 WETH/BU
    high: 0.21e27   // 0.21 WETH/BU
});

WeightRange memory usdcWeight = WeightRange({
    low:  38000e27,  // 38,000 USDC/BU (remember: 6 decimals)
    spot: 40000e27,  // 40,000 USDC/BU
    high: 42000e27   // 42,000 USDC/BU
});

Weight Control

The weightControl flag in RebalanceControl determines whether the AUCTION_LAUNCHER can adjust weights:
struct RebalanceControl {
    bool weightControl;           // If AUCTION_LAUNCHER can move weights
    PriceControl priceControl;   // Price control mode
}

Without Weight Control

  • AUCTION_LAUNCHER must use the exact spot weights from REBALANCE_MANAGER
  • All auction weight ranges collapse to the spot value
  • Suitable for Folios with fixed monthly/quarterly targets

With Weight Control

  • AUCTION_LAUNCHER can progressively narrow weight ranges
  • Cannot expand beyond initial low and high bounds
  • Suitable for Folios maintaining specific percentage breakdowns over time

Surplus and Deficit Calculations

During auctions, tokens are classified as surplus or deficit based on current balances vs. target ranges:

Surplus

A token is in surplus when the Folio holds more than needed at the high limit:
// {tok}
uint256 targetBalance = (totalSupply * high_BU_limit * weight.high) / (1e18 * 1e27);

if (currentBalance > targetBalance) {
    uint256 surplus = currentBalance - targetBalance;
    // Can sell surplus in auctions
}

Deficit

A token is in deficit when the Folio holds less than needed at the low limit:
// {tok}
uint256 targetBalance = (totalSupply * low_BU_limit * weight.low) / (1e18 * 1e27);

if (currentBalance < targetBalance) {
    uint256 deficit = targetBalance - currentBalance;
    // Must buy deficit in auctions
}

Auction Pair Eligibility

A token pair is eligible for auction only if:
  1. Sell token is in surplus (using high limit)
  2. Buy token is in deficit (using low limit)

Lot Sizing

Auction sell amounts are calculated as the minimum of:
  1. Surplus constraint: How much sell token is surplus
  2. Deficit constraint: How much buy token is needed (converted via price)
  3. Max auction size: Governance-set maximum per token
function _getBid(...) internal view returns (uint256 sellAmount, ...) {
    // Calculate sell token surplus
    uint256 sellSurplus = sellBalance - 
        (totalSupply * limits.high * sellWeight.high) / (1e18 * 1e27);
    
    // Calculate buy token deficit
    uint256 buyDeficit = 
        (totalSupply * limits.low * buyWeight.low) / (1e18 * 1e27) - buyBalance;
    
    // Convert buy deficit to sell terms
    uint256 sellForDeficit = (buyDeficit * sellPrice) / buyPrice;
    
    // Take minimum, capped by maxAuctionSize
    sellAmount = Math.min(
        Math.min(sellSurplus, sellForDeficit),
        maxAuctionSize
    );
}

Progressive Rebalancing

The AUCTION_LAUNCHER can run multiple auctions, progressively tightening both limits and weights:
// Auction 1: Wide ranges
WeightRange memory weth1 = WeightRange(0.19e27, 0.20e27, 0.21e27);
RebalanceLimits memory limits1 = RebalanceLimits(0.95e18, 1.0e18, 1.05e18);

// Auction 2: Narrower ranges (within original bounds)
WeightRange memory weth2 = WeightRange(0.195e27, 0.20e27, 0.205e27);
RebalanceLimits memory limits2 = RebalanceLimits(0.98e18, 1.0e18, 1.02e18);

// Auction 3: Collapsed to spot (rebalance complete)
WeightRange memory weth3 = WeightRange(0.20e27, 0.20e27, 0.20e27);
RebalanceLimits memory limits3 = RebalanceLimits(1.0e18, 1.0e18, 1.0e18);
Weights can only be narrowed, never expanded. Attempting to widen ranges beyond the initial low/high values will revert.

Dynamic vs Static Rebalancing

Static Targets (weightControl = false)

Use when:
  • Rebalancing to a specific token composition (e.g., “own 1000 WETH and 1M USDC”)
  • Target composition is known ahead of time
  • Rebalances are infrequent (monthly, quarterly)
RebalanceControl memory control = RebalanceControl({
    weightControl: false,
    priceControl: PriceControl.NONE
});

Dynamic Targets (weightControl = true)

Use when:
  • Maintaining a percentage-based portfolio (e.g., “always 60/40 WETH/USDC”)
  • Token ratios must adapt as prices change
  • Rebalances are frequent or continuous
RebalanceControl memory control = RebalanceControl({
    weightControl: true,
    priceControl: PriceControl.PARTIAL  // Often paired
});

Units and Precision

Weight Units

  • Format: D27{tok/BU} (27 decimal fixed point)
  • Range: [0, 1e54]
  • Calculation: 1e27 = 1 token quantum per BU

Example with Different Decimals

// WETH (18 decimals): 0.5 WETH per BU
uint256 wethWeight = 0.5e27;  // 0.5 * 1e27

// USDC (6 decimals): 1500 USDC per BU
uint256 usdcWeight = 1500e27; // 1500 * 1e27

// Target balance for 100e18 shares at 1e18 BU/share:
// WETH: (100e18 * 1e18 * 0.5e27) / (1e18 * 1e27) = 50e18 WETH
// USDC: (100e18 * 1e18 * 1500e27) / (1e18 * 1e27) = 150000e6 USDC

Handling Zero Weights

Zero weights are used to remove tokens from the basket:
// Remove USDT from basket
WeightRange memory usdtWeight = WeightRange({
    low:  0,  // Sell down to zero
    spot: 0,
    high: 0
});

// After rebalancing completes:
// - USDT balance will be zero
// - Can call removeFromBasket() permissionlessly

Common Patterns

Equal-Weighted Portfolio

// 3 tokens, equal weight by value
// Assume all tokens = $1 each for simplicity

WeightRange memory weight = WeightRange({
    low:  0.32e27,  // Allow some flexibility
    spot: 0.333333e27,
    high: 0.35e27
});

// Apply same weight to all 3 tokens

Capped Exposure

// Want 70% WETH, but cap at 1000 WETH total

WeightRange memory wethWeight = WeightRange({
    low:  6.5e18,   // 65% of target (per BU)
    spot: 7.0e18,   // 70% target
    high: 7.5e18    // 75% max
});

uint256 maxAuctionSize = 1000e18;  // Hard cap at 1000 WETH

Validation Rules

// Weights must be ordered: low ≤ spot ≤ high
require(
    weight.low <= weight.spot && weight.spot <= weight.high,
    "Invalid weight range"
);

// All weights are valid: [0, 1e54]
require(weight.low >= 0 && weight.high <= 1e54, "Weight out of bounds");

// When narrowing, must stay within original bounds
require(
    newWeight.low >= originalWeight.low &&
    newWeight.high <= originalWeight.high,
    "Cannot expand weight range"
);

Gas Optimization

Weight calculations happen on every getBid() call. To optimize:
  1. Use collapsed ranges (low == spot == high) for final auctions
  2. Limit the number of tokens in rebalance (affects calculation loops)
  3. Consider maxAuctionSize caps to prevent excessive lot sizing calculations

Build docs developers (and LLMs) love