AutoBalancer
The AutoBalancer is FYV's core optimization engine that continuously monitors yield positions and automatically rebalances when thresholds are exceeded. This document explains how AutoBalancers work, when they trigger, and how they maintain optimal position health.
What is an AutoBalancer?
An AutoBalancer is a resource that holds yield-bearing tokens in ERC4626 vaults, monitors the ratio between current value and historical deposits, automatically withdraws excess profits or requests deficit recovery, and self-schedules continuous rebalancing at 60-second intervals.
Every YieldVault has an associated AutoBalancer stored in contract storage, managed by the vault's strategy implementation.
Core Concept: Value Ratio Monitoring
The AutoBalancer tracks two key values to determine when rebalancing is needed:
Historical Deposit Value: The cumulative value of all tokens deposited to the ERC4626 vault over time (tracked at deposit time and never changes unless new deposits occur).
Current Value: The real-time value of yield tokens held in the ERC4626 vault (increases as yield accrues and decreases if vault experiences losses).
Value Ratio:
_10Ratio = Current Value / Historical Deposit Value
Rebalancing triggers:
_10Ratio > 1.05 (105%) → Excess profits, withdraw surplus_10Ratio < 0.95 (95%) → Deficit detected, request recovery_10Ratio 0.95-1.05 → Within target range, no action needed
Rebalancing Mechanics
Upper Threshold: Excess Profits (Ratio > 105%)
When yield accrues and pushes the ratio above 105%, the AutoBalancer harvests profits.
What happens:
- Calculate excess value above 105% baseline
- Withdraw excess yield tokens from ERC4626 vault
- Swap yield tokens to collateral (FLOW) via SwapConnectors
- Deposit collateral to ALP Position (increases collateral, improves health factor)
- Update tracking (historical value stays same, current value returns to ~100%)
Example:
_22Initial state:_22 - Historical deposit value: $1,000_22 - Current value: $1,080 (8% yield accrued)_22 - Ratio: 1,080 / 1,000 = 1.08 = 108%_22 - Threshold exceeded: 108% > 105% ✓_22_22Rebalancing calculation:_22 - Target value (105%): $1,000 × 1.05 = $1,050_22 - Excess: $1,080 - $1,050 = $30_22 - Withdraw: 30 YieldToken from vault_22_22Swap and deposit:_22 - Swap 30 YieldToken → 29.7 FLOW (1% slippage)_22 - Deposit 29.7 FLOW to Position_22 - Position collateral: 1000 → 1029.7 FLOW_22_22After rebalancing:_22 - Historical: $1,000 (unchanged)_22 - Current: $1,050 (back near target)_22 - Ratio: 1,050 / 1,000 = 1.05 = 105%_22 - Collateral increased by $29.70_22 - Profits locked in as additional safety buffer
Impact on position:
_12Before rebalancing:_12 - Collateral: 1000 FLOW @ $1 = $1,000_12 - EC (80% CF): $800_12 - Debt: 615.38 MOET_12 - HF: 800 / 615.38 = 1.30_12_12After rebalancing:_12 - Collateral: 1029.7 FLOW @ $1 = $1,029.70_12 - EC (80% CF): $823.76_12 - Debt: 615.38 MOET (unchanged)_12 - HF: 823.76 / 615.38 = 1.34 (improved!)_12 - Safety buffer increased
Lower Threshold: Deficit Recovery (Ratio < 95%)
When the vault experiences losses or value drops below 95%, the AutoBalancer requests recovery funds.
What happens:
- Calculate deficit below 95% baseline
- Request deficit value from ALP Position
- Position provides MOET (either from available liquidity or by borrowing more)
- Swap MOET to yield tokens via SwapConnectors
- Deposit yield tokens to ERC4626 vault
- Update tracking (current value returns to ~100%)
Example:
_22State after vault loss:_22 - Historical deposit value: $1,000_22 - Current value: $920 (8% loss in vault)_22 - Ratio: 920 / 1,000 = 0.92 = 92%_22 - Threshold breached: 92% < 95% ✓_22_22Rebalancing calculation:_22 - Target value (95%): $1,000 × 0.95 = $950_22 - Deficit: $950 - $920 = $30_22 - Request: $30 from Position_22_22Position response:_22 - Position has available liquidity: provides 30 MOET_22 - OR Position borrows additional 30 MOET if needed_22 - Swap 30 MOET → 29.7 YieldToken_22 - Deposit 29.7 YieldToken to vault_22_22After rebalancing:_22 - Historical: $1,000 (unchanged)_22 - Current: $920 + $29.70 = $949.70_22 - Ratio: 949.70 / 1,000 = 0.9497 ≈ 95%_22 - Deficit recovered
Impact on leveraged positions:
_12Before deficit recovery:_12 - Collateral: 1000 FLOW @ $1 = $1,000_12 - Debt: 615.38 MOET_12 - Vault value: $920 (loss)_12 - Total exposure: $1,000 + $920 = $1,920_12_12After deficit recovery (if Position borrowed more):_12 - Collateral: 1000 FLOW (unchanged)_12 - Debt: 615.38 + 30 = 645.38 MOET (increased)_12 - Vault value: $949.70 (recovered)_12 - Total exposure: $1,000 + $949.70 = $1,949.70_12 - HF: 800 / 645.38 = 1.24 (slightly lower but still safe)
Rebalancing Flow Diagram
_28graph TD_28 Start[Rebalance Triggered] --> GetBalance[Get current vault balance]_28 GetBalance --> GetHistorical[Get historical deposit value]_28 GetHistorical --> CalcRatio[Calculate ratio]_28 CalcRatio --> CheckRatio{Ratio?}_28_28 CheckRatio -->|> 1.05| Excess[Excess Profits]_28 CheckRatio -->|< 0.95| Deficit[Deficit Recovery]_28 CheckRatio -->|0.95-1.05| NoAction[No Action Needed]_28_28 Excess --> CalcExcess[Calculate excess amount]_28 CalcExcess --> WithdrawVault[Withdraw from ERC4626]_28 WithdrawVault --> SwapToFlow[Swap YieldToken → FLOW]_28 SwapToFlow --> DepositPos[Deposit FLOW to Position]_28 DepositPos --> Schedule[Schedule next rebalance]_28_28 Deficit --> CalcDeficit[Calculate deficit amount]_28 CalcDeficit --> RequestMOET[Request MOET from Position]_28 RequestMOET --> SwapToYield[Swap MOET → YieldToken]_28 SwapToYield --> DepositVault[Deposit to ERC4626]_28 DepositVault --> Schedule_28_28 NoAction --> Schedule_28 Schedule --> End[Complete]_28_28 style Excess fill:#bfb_28 style Deficit fill:#fbb_28 style NoAction fill:#bbf
Self-Scheduling Mechanism
AutoBalancers implement perpetual automation through self-scheduling, eliminating the need for external bots or keepers.
How It Works
Initial Schedule: When a YieldVault is created, the AutoBalancer is registered in the SchedulerRegistry and scheduled for its first execution via FlowTransactionScheduler at T+60 seconds.
Execution: At scheduled time, scheduler calls autoBalancer.rebalance(). The AutoBalancer performs its rebalancing logic (check ratio, execute if needed).
Reschedule: At the end of rebalance(), the AutoBalancer calls scheduleNextRebalance() to schedule the next execution 60 seconds later.
Perpetual Loop: This creates an infinite self-scheduling loop where each execution schedules the next one.
Sequence diagram:
_22sequenceDiagram_22 participant Scheduler_22 participant AB as AutoBalancer_22 participant Registry_22_22 Note over AB: Initial vault creation_22 AB->>Registry: registerAutoBalancer()_22 AB->>Scheduler: schedule(rebalance, T+60s)_22_22 Note over Scheduler: Wait 60 seconds_22_22 Scheduler->>AB: rebalance()_22 AB->>AB: Check ratio and execute logic_22 AB->>Scheduler: schedule(rebalance, T+60s)_22_22 Note over Scheduler: Wait 60 seconds_22_22 Scheduler->>AB: rebalance()_22 AB->>AB: Check ratio and execute logic_22 AB->>Scheduler: schedule(rebalance, T+60s)_22_22 Note over AB,Scheduler: Loop continues indefinitely...
Atomic Registration
Vault creation and AutoBalancer registration happen atomically:
_13transaction createVault() {_13 prepare(signer: AuthAccount) {_13 // All these steps happen in one transaction_13 let vault <- createYieldVault(...)_13 let autoBalancer <- createAutoBalancer(...)_13_13 registerInRegistry(autoBalancer) // Step 1_13 scheduleFirstRebalance(autoBalancer) // Step 2_13_13 // If ANY step fails, entire transaction reverts_13 // No orphaned or incomplete vaults_13 }_13}
This guarantees that every vault either has a fully functional AutoBalancer with scheduled execution or doesn't exist at all (no partial creation).
Configuration Parameters
AutoBalancers accept configuration to control their behavior:
_14pub struct AutoBalancerConfig {_14 // Rebalancing thresholds_14 pub let upperThreshold: UFix64 // Default: 1.05 (105%)_14 pub let lowerThreshold: UFix64 // Default: 0.95 (95%)_14_14 // Scheduling_14 pub let rebalanceIntervalSeconds: UInt64 // Default: 60_14_14 // Swap protection_14 pub let slippageTolerance: UFix64 // Default: 0.01 (1%)_14_14 // ERC4626 vault_14 pub let vaultAddress: Address // Target yield vault_14}
Tuning considerations:
Tighter thresholds (e.g., 1.02/0.98): More frequent rebalancing, higher gas costs, more precise optimization, better capital efficiency.
Wider thresholds (e.g., 1.10/0.90): Less frequent rebalancing, lower gas costs, more yield variance tolerance, lower capital efficiency.
Shorter intervals (e.g., 30s): More responsive to changes, higher gas costs, better for volatile vaults.
Longer intervals (e.g., 300s): Less responsive, lower gas costs, better for stable vaults.
Gas Optimization
AutoBalancers are designed to minimize gas costs while maintaining effectiveness:
No-Op When In Range: If ratio is within 95%-105%, the rebalance function returns early without executing swaps or transactions, costing minimal gas.
Batch Operations: When rebalancing is needed, all operations (withdraw, swap, deposit) happen in a single transaction.
Efficient Scheduling: Uses Flow's native transaction scheduler rather than external keeper networks.
Bounded Execution: Each rebalance has deterministic gas cost based on operations performed.
Example gas costs (approximate):
_10Rebalance (no action needed): ~0.0001 FLOW_10Rebalance (with excess withdrawal): ~0.001 FLOW_10Rebalance (with deficit recovery): ~0.0015 FLOW
Monitoring AutoBalancer State
Users can query AutoBalancer state to understand position health:
Scripts
Get current ratio:
_12import FlowYieldVaults from 0xFlowYieldVaults_12_12pub fun main(vaultID: UInt64): UFix64 {_12 let vault = FlowYieldVaults.getVault(id: vaultID)_12 let autoBalancer = vault.getAutoBalancer()_12_12 let current = autoBalancer.getCurrentValue()_12 let historical = autoBalancer.getHistoricalValue()_12_12 return current / historical_12}_12// Returns: 1.08 (108% ratio)
Get rebalancing history:
_10pub fun main(vaultID: UInt64): [RebalanceEvent] {_10 let vault = FlowYieldVaults.getVault(id: vaultID)_10 let autoBalancer = vault.getAutoBalancer()_10_10 return autoBalancer.getRebalanceHistory()_10}_10// Returns array of past rebalancing events with timestamps and amounts
Check next rebalance time:
_10pub fun main(vaultID: UInt64): UFix64 {_10 let registry = FlowYieldVaults.getSchedulerRegistry()_10 return registry.getNextScheduledTime(vaultID: vaultID)_10}_10// Returns: 1703001234 (Unix timestamp)
Recovery Mechanisms
If an AutoBalancer becomes stuck or fails to self-schedule, the Supervisor provides recovery:
Supervisor Recovery: Scans SchedulerRegistry for vaults with pending schedules, attempts to re-seed scheduling for stuck vaults (max 50 per execution), and automatically reschedules itself if more work remains.
Manual Recovery: Vault owners can manually trigger rebalancing via forceRebalance() transaction if AutoBalancer is stuck.
Admin Recovery: Protocol administrators can intervene in case of critical failures using admin capabilities.
Learn more in Scheduling System.
Advanced: Custom Rebalancing Logic
Developers can implement custom AutoBalancer logic for specialized strategies:
_12pub resource CustomAutoBalancer: AutoBalancerInterface {_12 pub fun rebalance() {_12 // Custom logic_12 // - Different thresholds based on time of day_12 // - Multi-vault coordination_12 // - Dynamic threshold adjustment_12 // - Alternative profit distribution_12_12 // Must call scheduleNextRebalance() at end_12 self.scheduleNextRebalance()_12 }_12}
Custom implementations must maintain the self-scheduling mechanism and implement the AutoBalancerInterface and register with SchedulerRegistry.
Best Practices
Monitor Ratio: Keep an eye on your AutoBalancer's value ratio. Frequent rebalancing in one direction indicates systematic vault performance.
Understand Triggers: Know your thresholds. If your vault frequently hits 105%, you're generating steady profits. If it hits 95%, the vault may be experiencing losses.
Gas Awareness: More frequent rebalancing = more gas costs. Balance responsiveness vs. costs based on your vault size.
Threshold Tuning: Larger vaults benefit from tighter thresholds (better optimization). Smaller vaults benefit from wider thresholds (lower gas impact).
Track History: Review rebalancing history to understand vault performance patterns and identify optimal strategy configurations.
Summary
AutoBalancers are FYV's optimization engine that maintain yield positions within target ranges. They monitor value ratios continuously (every 60 seconds), withdraw excess profits above 105% and lock them as collateral, request deficit recovery below 95% to maintain position health, and self-schedule perpetually without external dependencies.
Key mechanisms:
- Value ratio monitoring: Current vs. Historical
- Bidirectional rebalancing: Excess profits and deficit recovery
- Self-scheduling: Perpetual 60-second loops
- Atomic registration: All-or-nothing vault creation
- Gas optimization: No-op when within range
Next Steps
- Understand scheduling: Read Scheduling System
- Learn about leverage: Explore Leveraged Farming
- Create a vault: Follow Vault Lifecycle
- DeFi Actions composability: See DeFi Actions
AutoBalancers continuously optimize your yield position by harvesting profits when value exceeds 105% and recovering deficits when value drops below 95%. This creates a self-optimizing system that locks in gains and prevents losses without manual intervention.