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
Price control determines how much authority the AUCTION_LAUNCHER has over auction pricing within the bounds set by the REBALANCE_MANAGER. The three modes provide different tradeoffs between decentralization, execution quality, and MEV risk.
Price Control Modes
enum PriceControl {
NONE, // Cannot change prices
PARTIAL, // Can set auction prices within bounds
ATOMIC_SWAP // PARTIAL + ability to set startPrice = endPrice
}
NONE: Governance-Only Pricing
Behavior
AUCTION_LAUNCHER cannot modify price ranges
- All auctions use the initial price ranges set by
REBALANCE_MANAGER
- Auction length is fixed to
maxAuctionLength
- Most decentralized but least flexible
Configuration
RebalanceControl memory control = RebalanceControl({
weightControl: false,
priceControl: PriceControl.NONE
});
folio.setRebalanceControl(control);
Use Case
Ideal for Folios that:
- Prioritize maximum decentralization
- Can tolerate wider price ranges set via governance
- Have long timelock delays where precision matters less
- Rebalance infrequently (e.g., quarterly)
Example: Opening Auction with NONE
// REBALANCE_MANAGER sets wide price ranges
PriceRange[] memory prices = new PriceRange[](2);
prices[0] = PriceRange(0.99e27, 1.01e27); // USDC: 1% range
prices[1] = PriceRange(2900e27, 3100e27); // WETH: ~7% range
rebalanceManager.startRebalance(tokens, limits, 3 days, 7 days);
// AUCTION_LAUNCHER must use exact prices from rebalance
// auctionLength must equal maxAuctionLength
auctionLauncher.openAuction(
rebalanceNonce,
tokens,
newWeights,
prices, // Must match initial prices exactly
newLimits,
maxAuctionLength // Fixed length
);
With PriceControl.NONE, the AUCTION_LAUNCHER cannot adapt to market movements. If prices move outside the governance-approved range, value leakage to MEV searchers is possible. The AUCTION_LAUNCHER should monitor markets and end the rebalance if necessary.
PARTIAL: Subset Price Control
Behavior
AUCTION_LAUNCHER can narrow price ranges within initial bounds
- Cannot expand ranges beyond what governance approved
- Can set auction length between
MIN_AUCTION_LENGTH and maxAuctionLength
- Enables better execution but introduces MEV risk
Configuration
RebalanceControl memory control = RebalanceControl({
weightControl: true, // Often paired with weight control
priceControl: PriceControl.PARTIAL
});
folio.setRebalanceControl(control);
Use Case
Ideal for Folios that:
- Want to balance decentralization and execution quality
- Have a semi-trusted
AUCTION_LAUNCHER (multisig)
- Need to adapt to market conditions within approved bounds
- Prioritize better pricing over absolute trustlessness
Example: Narrowing Price Ranges
// REBALANCE_MANAGER sets outer bounds
PriceRange memory usdcPrice = PriceRange(0.98e27, 1.02e27); // 4% range
// AUCTION_LAUNCHER can narrow to improve execution
PriceRange memory narrowedPrice = PriceRange(0.995e27, 1.005e27); // 1% range
// But cannot expand:
PriceRange memory invalid = PriceRange(0.97e27, 1.03e27); // ❌ Reverts
Calculating Start and End Prices
For a token pair, auction prices are calculated from individual token ranges:
// D27{buyTok/sellTok}
// startPrice = most optimistic (highest sell value / lowest buy value)
// endPrice = most pessimistic (lowest sell value / highest buy value)
startPrice = (sellToken.high * D27) / buyToken.low;
endPrice = (sellToken.low * D27) / buyToken.high;
MEV Risk
With PARTIAL control, a dishonest AUCTION_LAUNCHER can:
- Set auction start prices that leak value to MEV searchers
- Cause immediate value extraction when auctions begin
- Cannot guarantee they receive the leaked value (goes to MEV bots)
The AUCTION_LAUNCHER should act in good faith and price auctions to clear near the efficient market price.
ATOMIC_SWAP: Full Price Control
Behavior
- All capabilities of
PARTIAL mode
- Additionally can set
startPrice == endPrice (flat price)
- Enables atomic swaps without the 30-second warmup period
- Allows
AUCTION_LAUNCHER to internalize MEV
Configuration
RebalanceControl memory control = RebalanceControl({
weightControl: true,
priceControl: PriceControl.ATOMIC_SWAP
});
folio.setRebalanceControl(control);
Use Case
Ideal for Folios that:
- Fully trust the
AUCTION_LAUNCHER to execute at fair prices
- Want to eliminate MEV leakage entirely
- Can verify fair execution through other means (e.g., bundle inspection)
- Prioritize execution quality above all else
Example: Atomic Swap Execution
// Set fixed price (no price curve)
PriceRange memory fixedPrice = PriceRange(1.0e27, 1.0e27);
// Open auction with atomic swap
folio.openAuction(
rebalanceNonce,
tokens,
newWeights,
[fixedPrice, fixedPrice], // startPrice == endPrice
newLimits,
0 // Can use very short auction length
);
// Fill immediately in same transaction
folio.bid(
auctionId,
sellToken,
buyToken,
sellAmount,
maxBuyAmount,
true, // Use callback
data
);
// End rebalance to prevent further exploitation
folio.endRebalance();
Best Practices for ATOMIC_SWAP
When using ATOMIC_SWAP, the AUCTION_LAUNCHER MUST:
- Fill the auction atomically in the same transaction as opening it
- End the rebalance immediately after all fills complete
- Execute as a bundle to prevent frontrunning
Failure to follow this pattern allows the AUCTION_LAUNCHER to extract value AND benefit from it directly.
Choosing a Price Control Mode
| Mode | Decentralization | Execution Quality | MEV Risk | Best For |
|---|
| NONE | Highest | Lowest | Low | Infrequent rebalances, long timelocks |
| PARTIAL | Medium | Medium | Medium | Balanced approach, semi-trusted launcher |
| ATOMIC_SWAP | Lowest | Highest | High* | Fully trusted launcher, MEV elimination |
*Risk is high if misused, but can be mitigated with proper execution
Validation Rules
NONE Mode
// Auction length must equal maxAuctionLength
require(auctionLength == maxAuctionLength, "Invalid length");
// Prices must match initial ranges exactly
require(
newPrices[i].low == rebalance.details[token].initialPrices.low &&
newPrices[i].high == rebalance.details[token].initialPrices.high,
"Prices must match"
);
PARTIAL Mode
// Auction length has flexibility
require(
auctionLength >= MIN_AUCTION_LENGTH &&
auctionLength <= maxAuctionLength,
"Invalid length"
);
// Prices must be within initial bounds
require(
newPrices[i].low >= rebalance.details[token].initialPrices.low &&
newPrices[i].high <= rebalance.details[token].initialPrices.high,
"Price out of bounds"
);
// startPrice cannot equal endPrice
require(startPrice != endPrice, "Use ATOMIC_SWAP for fixed prices");
ATOMIC_SWAP Mode
// All PARTIAL validations apply
// Plus: startPrice CAN equal endPrice
if (startPrice == endPrice) {
// Warmup period bypassed for atomic execution
}
RebalanceControl Structure
struct RebalanceControl {
bool weightControl; // If AUCTION_LAUNCHER can adjust weights
PriceControl priceControl; // Price control mode
}
The weightControl flag is independent and can be combined with any price control mode. See Basket Weights for details.
Governance Considerations
- Price control mode cannot be changed during an active rebalance
- Set via
setRebalanceControl() which requires DEFAULT_ADMIN_ROLE
- Should align with the trust level of your
AUCTION_LAUNCHER
- Can be different for different Folios in the same ecosystem