# Auto-Deallocating (ADA)

**Auto-Deallocating** is Flux's mechanism to protect liquidity providers during periods of extreme vault utilization by allowing controlled reduction of healthy-but-risky manager positions.

### What is ADA?

**Auto-Deallocating (ADA)** is a protective measure that allows a vault to close out manager positions when:

1. The vault has extremely high utilization (typically ≥95%)
2. The manager's position is healthy but approaching liquidation zone
3. LPs need liquidity but managers aren't repaying voluntarily

**Key Characteristics**:

* Manager is **not** liquidated (they're still solvent)
* Manager receives their **full net equity back**
* Vault regains liquidity to serve LP withdrawals
* Only executed by designated ADA Manager (typically vault creator or protocol)
* Optional - can be permanently disabled when vault is created

**ADA vs. Liquidation**:

| Feature                 | Liquidation                          | ADA                                        |
| ----------------------- | ------------------------------------ | ------------------------------------------ |
| **Trigger**             | Health < liquidation threshold       | Health between liquidation & ADA threshold |
| **Executed By**         | Anyone (permissionless)              | ADA Manager only                           |
| **Manager Outcome**     | Loses position + liquidation penalty | Receives full net equity                   |
| **Purpose**             | Prevent bad debt                     | Free up liquidity                          |
| **Vault Condition**     | Any utilization                      | High utilization (≥95%)                    |
| **Profit for Executor** | Yes (liquidation bonus)              | No (break-even)                            |

***

### Why ADA Exists

#### The Liquidity Crunch Problem

Consider this scenario:

```
Vault State:
- Total Assets: $10M
- Borrowed by Managers: $9.5M (95% utilization)
- Idle Liquidity: $500K

LP Withdrawal Requests:
- Alice wants to withdraw $2M (will fail - insufficient liquidity)
- Bob wants to withdraw $1M (will fail - insufficient liquidity)
- LPs unable to withdraw

Manager Positions:
- All positions are healthy (can't be liquidated)
- Managers earning yield, no incentive to close
- But vault needs $2.5M more liquidity for LP withdrawals to succeed!
```

**Without ADA**: LPs cannot withdraw and are stuck waiting indefinitely for managers to voluntarily close positions.

**With ADA**: Vault creator can force-close positions (returning manager's equity) to free up liquidity so LP withdrawals can succeed.

#### ADA is LP Protection

ADA ensures that LPs can eventually get their capital back, even when:

* Managers are technically healthy
* Vault is fully utilized
* Withdrawals would otherwise fail

**It prevents LPs from being held hostage** by managers who won't close positions voluntarily.

***

### How ADA Works

#### Eligibility Conditions

A position can be ADA'd **only if ALL** of these conditions are met:

**1. High Vault Utilization**

```
utilization = (totalAssets - idleLiquidity) / totalAssets

// Must be above ADA utilization threshold (typically 95%)
utilization >= adlUtilizationThreshold
```

**Example**:

```
Vault: $10M total, $500K idle
Utilization: 95% ✅ (above 95% threshold)

Vault: $10M total, $3M idle
Utilization: 70% ❌ (below 95% threshold, ADA blocked)
```

**2. Position Health Below ADL Threshold**

```
healthRatio = totalCollateralValue / debtValue

// Must be below ADA threshold (typically 120%)
// But above liquidation threshold (typically 110%)
healthRatio < adlThreshold && healthRatio >= liquidationThreshold
```

**Example with Strategy Parameters**:

```
Strategy Config:
- liquidationThreshold: 1.1 (110%)
- adlThreshold: 1.2 (120%)

Position:
- Collateral: $125K
- Debt: $110K
- Health: 113.6%

Result: 110% < 113.6% < 120% ✅ Can ADL
```

**3. Position Still Has Positive Equity**

```
netEquity = totalCollateralValue - debtValue

// Manager must have something to receive back
netEquity > 0
```

**If netEquity ≤ 0**: Position is underwater and should be liquidated instead.

#### ADA Parameters

Defined in the strategy contract:

```
struct StrategyParams {
    // ...other params...
    uint256 adlBuffer;               // e.g., 0.1e18 = 10%
    uint256 adlUtilizationThreshold; // e.g., 0.95e18 = 95%
}

// Derived value:
adlThreshold = liquidationThreshold + adlBuffer

Example:
liquidationThreshold = 1.1 (110%)
adlBuffer = 0.1 (10%)
→ adlThreshold = 1.2 (120%)
```

**The ADA Zone**:

```
Health Ratio Zones:

  200% ━━━━━━━━━━━━━━━━━━━━━━━ Extremely Healthy
       │
  150% ┃
       │  Healthy Zone
  120% ━━━━━━━━━━━━━━━━━━━━━━━ ADA Threshold
       │
       │  ADA Zone (can be ADA'd if utilization high)
  110% ━━━━━━━━━━━━━━━━━━━━━━━ Liquidation Threshold
       │
  100% ┃  Underwater Zone (should be liquidated)
       │
   90% ━━━━━━━━━━━━━━━━━━━━━━━ Severely Underwater
```

***

### ADA Execution Flow

#### Step-by-Step Process

**1. ADA Manager Identifies ADA Opportunity**

```
// Check if position can be ADA'd
const { canADL, managerNetEquityUSD } = await strategy.evaluateADL(
  vaultAddress,
  managerAddress
);

if (canADA) {
  console.log(`Manager ${managerAddress} can be ADA'd`);
  console.log(`Net equity to return: $${managerNetEquityUSD / 1e18}`);
}
```

**2. ADA Manager Prepares Executor**

The ADA Manager needs an executor with a callback to handle position unwinding:

```
contract ADAExecutor is IFluxUnlockCallback {
    address public vault;
    address public immutable adlOwner;
    IERC20 public asset;
    IAsset public immutable baseAssetWrapper;

    function fluxUnlockCallback(bytes calldata data) external override {
        require(msg.sender == vault, "Only vault");

        // Decode ADA parameters
        (uint256 trueDebt, uint256 managerNetEquityUSD, bytes memory additionalData) =
            abi.decode(data, (uint256, uint256, bytes));

        uint256 totalPayment = trueDebt + managerNetEquityUSD;

        // 1. Withdraw manager's positions (transferred to us)
        _withdrawAllPositions();

        // 2. Liquidate positions to base asset
        _liquidateToBaseAsset();

        // 3. Deposit totalPayment to working capital
        vault.locked_depositToWrapper(
            baseAssetWrapper,
            WORKING_CAPITAL,
            totalPayment
        );

        // Vault will verify we deposited enough
    }
}
```

**3. Execute ADA Transaction**

```
// Only ADA Manager can call this
vault.executeADL(
    managerAddress,        // Manager to ADL
    additionalWrappers,    // Any extra wrappers manager may have used
    callbackData           // Custom data for executor
);
```

**4. Vault Executes ADA**

Inside the vault's `executeADL` function:

```
function executeADL(address manager, IAsset[] calldata additionalWrappers, bytes calldata data) {
    // 1. Access control
    require(msg.sender == adlManager, "Only ADL manager");
    require(!adlPermanentlyDisabled, "ADL disabled");

    // 2. Accrue interest
    _accrueInterest();

    // 3. Verify position is ADL-eligible
    (bool canADL, uint256 managerNetEquityUSD) = strategy.evaluateADL(address(this), manager);
    require(canADL, "Position not ADL-able");

    uint256 trueDebt = getManagerTrueDebt(manager);

    // 4. Transfer ALL manager's positions to ADL-er
    _transferAllPositions(manager, msg.sender, additionalWrappers);

    // 5. ADL-er unwinds positions via callback
    bytes memory callbackData = abi.encode(trueDebt, managerNetEquityUSD, data);
    _executeWithLock(msg.sender, callbackData);

    // 6. Verify ADL-er prepared enough payment (debt + net equity)
    uint256 adlerValueUSD = baseWrapper.getValue(msg.sender, WORKING_CAPITAL);
    uint256 debtValueUSD = oracle.getValueUSD(asset, trueDebt);
    uint256 totalRequiredUSD = debtValueUSD + managerNetEquityUSD;

    require(adlerValueUSD >= totalRequiredUSD, "Insufficient ADL preparation");

    // 7. Transfer ADL-er's working capital back to manager
    baseWrapper.ledgerTransferSubaccount(msg.sender, manager);

    // 8. Take debt payment from manager's working capital
    baseWrapper.withdraw(manager, WORKING_CAPITAL, address(this), trueDebt);

    // 9. Repay debt accounting
    _repay(principalToRemove);

    // 10. Cleanup manager's position
    delete managerPositions[manager];
    delete registeredWrappers[manager];

    // Manager now has netEquity in working capital, can withdraw
    emit ADLExecuted(manager, msg.sender, trueDebt, managerNetEquityUSD, totalRequiredUSD);
}
```

#### What Happens to Each Party

**Manager (being ADA'd)**:

1. All positions closed
2. Debt repaid in full
3. Receives net equity in vault's base asset (in working capital)
4. Can withdraw net equity immediately
5. Loses future earning potential from position
6. No penalties or fees

**ADA Manager (executor)**:

1. Receives all manager positions
2. Unwinds positions to base asset
3. Pays `trueDebt + managerNetEquity` back to vault
4. Ideally breaks even (no profit, no loss)
5. May incur gas costs and slippage

**Vault / LPs**:

1. Receives debt repayment
2. Gains liquidity
3. Can service LP withdrawals
4. Loses future interest from that manager

***

### ADA Manager Role

#### What is an ADA Manager?

The **ADA Manager** is a designated address (typically the vault creator or protocol governance) that can execute ADA operations.

**Key Responsibilities**:

* Monitor vault utilization
* Identify ADA-eligible positions
* Execute ADA when needed to free liquidity
* Unwind positions with minimal slippage
* Return manager's equity fairly

**Access Control**:

```
// Only vault creator can set ADA manager
function setAdlManager(address newManager) external {
    require(msg.sender == vaultCreator, "Only creator");
    adlManager = newManager;
    emit ADLManagerUpdated(oldManager, newManager);
}

// Get current ADA manager
address public adlManager;

// Permanently disable ADA (irreversible)
function permanentlyDisableADL() external {
    require(msg.sender == vaultCreator, "Only creator");
    adlPermanentlyDisabled = true;
    adlManager = address(0);
    emit ADLPermanentlyDisabled();
}
```

#### ADA Manager Options

**Option 1: Vault Creator as ADA Manager** (Most Common)

```
// During vault creation
address vault = fluxFactory.createVault(...);

// Vault creator is initially set as ADL manager
// Can execute ADA when needed
vault.executeADL(unhealthyManager, wrappers, data);
```

**Pros**:

* Vault creator has incentive to maintain vault health
* Responsive to LP needs
* Can act quickly

**Cons**:

* Centralization risk
* Requires vault creator to actively monitor
* May have conflicts of interest

**Option 2: Protocol Governance as ADA Manager**

```
// Set governance multisig as ADA manager
vault.setAdlManager(governanceMultisig);
```

**Pros**:

* More decentralized
* Trustworthy for LPs
* Protocol-level oversight

**Cons**:

* Slower response time (multisig)
* May not prioritize individual vault needs

**Option 3: Automated ADA Bot**

```
// Set automated bot as ADA manager
ADLBot bot = new ADLBot(vault, strategy);
vault.setAdlManager(address(bot));
```

**Pros**:

* Fastest response
* 24/7 monitoring
* No human intervention needed

**Cons**:

* Bot can be exploited if not secure
* Requires funding for gas
* May execute suboptimally

**Option 4: No ADA Manager (Disabled)**

```
// Set to zero address to temporarily disable
vault.setAdlManager(address(0));

// Or permanently disable
vault.permanentlyDisableADL();
```

**Use Cases**:

* Vault creator wants pure market dynamics
* Immutable vaults prioritizing predictability
* Low-utilization vaults that don't need ADA

***

### ADA in Different Strategy Types

#### Immutable Strategy

```
StrategyParams({
    minBondRatio: 0.25e18,           // 25%
    liquidationBuffer: 0.15e18,       // 15%
    adlBuffer: 0.1e18,                // 10% ✅ ADL enabled
    adlUtilizationThreshold: 0.95e18, // 95%
    // ...
});

// Thresholds:
liquidationThreshold = 1.0 + 0.25 - 0.15 = 1.1 (110%)
adlThreshold = 1.1 + 0.1 = 1.2 (120%)

// ADL zone: 110% < health < 120%
```

**Characteristics**:

* ADA parameters locked forever at deployment
* LPs know exact ADA trigger conditions
* Vault creator decides whether to set ADA manager

#### Mutable Strategy

```
// ADA parameters CANNOT be updated (even in mutable strategies)
// These are set at deployment and never change:
- adlBuffer
- adlUtilizationThreshold

// Only these can be updated:
- annualRate
- vaultCreatorFeeRate
- allowedAssets
```

**Why ADA params are immutable**:

* Changing ADA threshold could surprise managers
* LPs rely on predictable ADA protection
* Risk parameters should be stable

#### Flexible Margin Strategy

```
// ADA is DISABLED in flexible margin strategies
function evaluateADA(address vault, address manager)
    external view returns (bool canADL, uint256 managerNetEquityUSD)
{
    return (false, 0); // Always returns false
}
```

**Why disabled?**:

* Flexible margin vaults are typically single-user
* Manager = LP in most cases
* No need for forced deleveraging
* Manager can close position whenever they want

***

### Use Cases and Examples

#### Example 1: High Utilization LP Withdrawal Crisis

**Scenario**:

```
Vault State:
- Total Assets: $50M
- Idle Liquidity: $2M (4% - very low!)
- Utilization: 96%

LP Withdrawal Attempts:
- LPs trying to withdraw $10M total
- All withdrawals failing due to insufficient liquidity
- LPs getting impatient

Manager Positions:
- Manager A: $15M borrowed, health 115% (in ADA zone!)
- Manager B: $20M borrowed, health 140% (too healthy for ADA)
- Manager C: $13M borrowed, health 118% (in ADA zone!)
```

**ADA Manager Action**:

```
// 1. Identify ADA targets
const targets = [];

for (const manager of allManagers) {
  const { canADL, netEquity } = await strategy.evaluateADL(vault, manager);
  if (canADL) {
    targets.push({ manager, netEquity });
  }
}

// Found: Manager A and Manager C

// 2. Calculate how much liquidity we need to serve LP withdrawals
const desiredLiquidity = 10_000_000e18;
const currentIdle = 2_000_000e18;
const needed = desiredLiquidity - currentIdle; // $8M

// 3. ADA just enough to cover withdrawals
let liquidityFreed = 0;
for (const target of targets) {
  if (liquidityFreed >= needed) break;

  await vault.executeADL(target.manager, [], "");
  liquidityFreed += target.debtRepaid;

  console.log(`ADL'd ${target.manager}, freed $${target.debtRepaid / 1e18}M`);
}

// Result:
// - Manager A ADA'd: $15M liquidity freed
// - Vault now has $17M idle
// - All LP withdrawals can be serviced
// - Manager A received their net equity back
```

#### Example 2: Preventing Bank Run

**Scenario**:

```
Market Event:
- Major protocol hack announced
- LPs rushing to withdraw from all vaults
- This vault getting hit hard

Before Event:
- Utilization: 75% (normal)

During Panic:
- $30M withdrawal requests in 1 hour
- Utilization jumps to 98%
- Idle liquidity: $1M
- Manager positions drifting toward ADA zone due to interest
```

**ADA Manager Strategy**:

```
// Proactive ADA to prevent cascading liquidations

// 1. Calculate target utilization
uint256 targetUtilization = 0.8e18; // 80% - safe level

// 2. Calculate liquidity needed
uint256 currentUtilization = vault.getCurrentUtilization();
uint256 liquidityToFree = calculateLiquidityNeeded(
    vault.totalAssets(),
    currentUtilization,
    targetUtilization
);

// 3. ADA positions starting with lowest health
address[] memory managers = getAllManagers();
sortByHealth(managers); // Ascending order

for (uint256 i = 0; i < managers.length; i++) {
    (bool canADL, uint256 netEquity) = strategy.evaluateADL(vault, managers[i]);

    if (canADL) {
        vault.executeADL(managers[i], [], "");

        // Check if we've freed enough
        if (vault.getCurrentUtilization() <= targetUtilization) {
            break; // Success!
        }
    }
}
```

**Outcome**:

* Vault stabilized at 80% utilization
* LPs can withdraw without queues
* Managers received their equity (no unfair liquidations)
* Vault creator maintains trust

#### Example 3: Gradual Deleveraging

**Scenario**: Vault creator wants to gradually reduce risk during uncertain market conditions.

```
class GradualDeleveragingADL {
  async execute() {
    const maxADLPerDay = 5; // At most 5 positions per day
    const targetUtilization = 0.85e18; // 85%

    while (true) {
      await sleep(24 * 60 * 60); // Wait 24 hours

      const currentUtil = await vault.getCurrentUtilization();

      if (currentUtil > targetUtilization) {
        // Find eligible positions
        const eligible = await findADLEligible();

        // ADL up to max per day
        const toADL = eligible.slice(0, maxADLPerDay);

        for (const manager of toADL) {
          await vault.executeADL(manager, [], "");
          console.log(`Gradual ADL: ${manager}`);
        }
      }
    }
  }
}
```

**Benefits**:

* Reduces vault risk over time
* Doesn't shock managers with sudden mass ADA
* Maintains adequate liquidity for LPs
* Spreads gas costs over time

***

### ADA Implementation Guide

#### For Vault Creators

**1. Decide on ADA Strategy**

```
// Choose ADA parameters during strategy deployment
StrategyParams memory params = StrategyParams({
    // ...other params...
    adlBuffer: 0.1e18,                // 10% buffer above liquidation
    adlUtilizationThreshold: 0.95e18  // Trigger at 95% utilization
});

address strategy = strategyFactory.deployImmutableStrategy(
    allowedAssets,
    params
);
```

**Parameter Selection**:

| Vault Type   | adlBuffer  | adlUtilizationThreshold | Reasoning                       |
| ------------ | ---------- | ----------------------- | ------------------------------- |
| Conservative | 0.15 (15%) | 0.90 (90%)              | Earlier ADA, more LP protection |
| Balanced     | 0.10 (10%) | 0.95 (95%)              | Standard config                 |
| Aggressive   | 0.05 (5%)  | 0.98 (98%)              | Let managers maximize leverage  |

**2. Set ADL Manager**

```
// Option A: Set yourself as ADA manager
vault.setAdlManager(vaultCreator);

// Option B: Set governance
vault.setAdlManager(governanceMultisig);

// Option C: Deploy automated ADA bot
ADLBot bot = new ADABot(vault, strategy);
vault.setAdlManager(address(bot));

// Option D: Disable ADA
vault.setAdlManager(address(0));

// Option E: Permanently disable (irreversible!)
vault.permanentlyDisableADL();
```

**3. Monitor Vault Health**

```
// Monitoring dashboard
async function monitorVaultADL() {
  const utilization = await vault.getCurrentUtilization();
  const threshold = await strategy.adlUtilizationThreshold();

  console.log(`Utilization: ${utilization / 1e16}%`);
  console.log(`ADL Threshold: ${threshold / 1e16}%`);

  if (utilization >= threshold) {
    console.warn("⚠️  High utilization - check for ADL opportunities");

    // Scan all managers
    const managers = await getAllManagers();
    for (const manager of managers) {
      const { canADL, netEquity } = await strategy.evaluateADL(vault, manager);

      if (canADL) {
        console.log(`🎯 ADL Target: ${manager}`);
        console.log(`   Net Equity: $${netEquity / 1e18}`);
        console.log(`   Health: ${await getHealth(manager) / 1e16}%`);
      }
    }
  }
}

// Run every hour
setInterval(monitorVaultADL, 60 * 60 * 1000);
```

**4. Execute ADA When Needed**

```
async function executeADLIfNeeded() {
  const targetLiquidity = await calculateTargetLiquidity(); // Based on typical LP needs
  const idleLiquidity = await vault.getIdleLiquidity();

  if (idleLiquidity < targetLiquidity) {
    const deficit = targetLiquidity - idleLiquidity;
    console.log(`Need $${deficit / 1e18} more liquidity for LP withdrawals`);

    // Find ADA candidates
    const candidates = await findADLCandidates();

    // Sort by health (lowest first - closest to liquidation)
    candidates.sort((a, b) => a.health - b.health);

    // ADA until we have enough liquidity
    let freed = 0;
    for (const candidate of candidates) {
      if (freed >= deficit) break;

      await vault.executeADL(candidate.manager, [], "");
      freed += candidate.debt;

      console.log(`✅ ADL'd ${candidate.manager}`);
    }
  }
}
```

#### For ADA Managers (Executors)

**Building an ADA Executor**

```
contract ProductionADLExecutor is IFluxUnlockCallback {
    IFluxVault public immutable vault;
    address public immutable adlOwner;
    IAsset public immutable baseAssetWrapper;
    IERC20 public immutable baseAsset;

    // DEX router for unwinding positions
    ISwapRouter public immutable swapRouter;

    constructor(
        address _vault,
        address _adlOwner,
        address _baseAssetWrapper,
        address _swapRouter
    ) {
        vault = IFluxVault(_vault);
        adlOwner = _adlOwner;
        baseAssetWrapper = IAsset(_baseAssetWrapper);
        baseAsset = IERC20(vault.asset());
        swapRouter = ISwapRouter(_swapRouter);

        baseAsset.approve(_vault, type(uint256).max);
    }

    function fluxUnlockCallback(bytes calldata data) external override {
        require(msg.sender == address(vault), "Only vault");

        // Decode ADA data
        (uint256 trueDebt, uint256 managerNetEquityUSD, ) =
            abi.decode(data, (uint256, uint256, bytes));

        uint256 totalPaymentNeeded = trueDebt + managerNetEquityUSD;

        // Step 1: Withdraw all positions we received
        uint256 bondBalance = vault.getBondBalance(adlOwner);
        if (bondBalance > 0) {
            vault.locked_withdrawBond(bondBalance);
        }

        uint256 workingCapital = vault.getWorkingCapital(adlOwner);
        if (workingCapital > 0) {
            vault.locked_withdrawFromWrapper(
                baseAssetWrapper,
                WORKING_CAPITAL,
                workingCapital
            );
        }

        // Step 2: Unwind all other positions to base asset
        address[] memory wrappers = vault.registeredWrappers(adlOwner);
        uint256 totalUnwound = 0;

        for (uint256 i = 0; i < wrappers.length; i++) {
            if (wrappers[i] == address(baseAssetWrapper)) continue;

            // Get all position IDs for this wrapper
            bytes32[] memory positionIds = getPositionIds(adlOwner, wrappers[i]);

            for (uint256 j = 0; j < positionIds.length; j++) {
                uint256 amount = IAsset(wrappers[i]).getValue(
                    address(vault),
                    adlOwner,
                    positionIds[j]
                );

                if (amount > 0) {
                    // Withdraw position
                    vault.locked_withdrawFromWrapper(
                        IAsset(wrappers[i]),
                        positionIds[j],
                        type(uint256).max
                    );

                    // Swap to base asset
                    uint256 baseReceived = _swapToBase(wrappers[i], amount);
                    totalUnwound += baseReceived;
                }
            }
        }

        // Step 3: Verify we have enough
        uint256 totalBase = bondBalance + workingCapital + totalUnwound;
        require(totalBase >= totalPaymentNeeded, "Insufficient unwound value");

        // Step 4: Deposit payment to working capital
        vault.locked_depositToWrapper(
            baseAssetWrapper,
            WORKING_CAPITAL,
            totalPaymentNeeded
        );

        // Any excess remains with ADA-er (compensation for gas/slippage)
    }

    function _swapToBase(address wrapper, uint256 amount) internal returns (uint256) {
        // Get underlying token from wrapper
        address token = IAsset(wrapper).underlyingAsset();

        // Approve router
        IERC20(token).approve(address(swapRouter), amount);

        // Swap with slippage protection
        uint256 minOut = calculateMinOut(token, address(baseAsset), amount);

        return swapRouter.exactInputSingle(
            ISwapRouter.ExactInputSingleParams({
                tokenIn: token,
                tokenOut: address(baseAsset),
                fee: 3000,
                recipient: address(this),
                deadline: block.timestamp,
                amountIn: amount,
                amountOutMinimum: minOut,
                sqrtPriceLimitX96: 0
            })
        );
    }
}
```

**ADA Monitoring Bot**

```
class ADLMonitoringBot {
  async run() {
    while (true) {
      try {
        // 1. Check vault utilization
        const utilization = await this.vault.getCurrentUtilization();
        const threshold = await this.strategy.adlUtilizationThreshold();

        if (utilization >= threshold) {
          // 2. Scan for ADL opportunities
          const opportunities = await this.findADLOpportunities();

          // 3. Prioritize by urgency
          opportunities.sort((a, b) => {
            // Lower health = more urgent
            return a.health - b.health;
          });

          // 4. Execute most urgent ADAs
          for (const opp of opportunities) {
            // Check if still needed
            const currentUtil = await this.vault.getCurrentUtilization();
            if (currentUtil < threshold * 0.95) {
              // Utilization back to safe level
              break;
            }

            // Execute ADA
            await this.executeADL(opp.manager);

            // Wait between ADAs to avoid gas spikes
            await sleep(60000); // 1 minute
          }
        }

        // Sleep before next check
        await sleep(300000); // 5 minutes
      } catch (error) {
        console.error("ADL bot error:", error);
        await sleep(60000); // 1 minute before retry
      }
    }
  }

  async findADLOpportunities() {
    const managers = await this.getAllManagers();
    const opportunities = [];

    for (const manager of managers) {
      const { canADL, managerNetEquityUSD } =
        await this.strategy.evaluateADL(this.vault.address, manager);

      if (canADL) {
        const health = await this.lens.getManagerHealth(
          this.vault.address,
          manager
        );
        const debt = await this.vault.getManagerTrueDebt(manager);

        opportunities.push({
          manager,
          health,
          debt,
          netEquity: managerNetEquityUSD,
        });
      }
    }

    return opportunities;
  }

  async executeADL(manager: string) {
    console.log(`Executing ADL on ${manager}`);

    // Get registered wrappers
    const wrappers = await this.vault.registeredWrappers(manager);

    // Execute ADA transaction
    const tx = await this.vault.executeADL(
      manager,
      wrappers, // Pass all known wrappers
      "0x" // No additional data
    );

    const receipt = await tx.wait();
    console.log(`ADL executed: ${receipt.transactionHash}`);
  }
}

// Start bot
const bot = new ADLMonitoringBot(vault, strategy, lens);
bot.run();
```

***

### ADA Best Practices

#### For Vault Creators

**Do**:

* Set ADA parameters appropriate for your vault's risk profile
* Monitor utilization regularly
* Communicate ADA policy clearly to LPs and managers
* Execute ADA fairly (lowest health first)
* Document when and why you'll use ADA

**Don't**:

* ADA managers to punish them (unfair)
* ADA when utilization is healthy (unnecessary)
* Change ADA manager frequently (undermines trust)
* Execute ADA with excessive slippage (hurts manager)
* Forget to fund your ADA executor for gas

#### For Managers

**Do**:

* Understand the vault's ADA parameters before depositing
* Monitor your health ratio to stay out of ADA zone
* Keep vault utilization in mind
* Accept that ADA is fair (you get full equity back)
* Have a plan for receiving net equity after ADA

**Don't**:

* Assume you'll never be ADA'd
* Let health drift into ADA zone during high utilization
* Fight or complain about fair ADA execution
* Borrow from vaults with unfair ADA policies

#### For LPs

**Do**:

* Understand the vault's ADA protection
* Check if vault has an ADA manager
* Verify ADA parameters match your risk tolerance
* Appreciate ADA as liquidity protection

**Don't**:

* Deposit in vaults with ADA disabled if you need withdrawal flexibility
* Expect instant withdrawals during extreme utilization
* Assume ADA will always save you (bad debt can still happen)

***

### Comparison: ADA vs. Other Mechanisms

#### ADA vs. Liquidation

| Feature             | ADA                                   | Liquidation                          |
| ------------------- | ------------------------------------- | ------------------------------------ |
| **Trigger**         | Health in ADA zone + high utilization | Health below liquidation threshold   |
| **Executor**        | Designated ADA manager                | Anyone (permissionless)              |
| **Manager Outcome** | Receives full net equity              | May receive net equity minus penalty |
| **Executor Profit** | Break-even (no profit)                | Liquidation bonus (0-20%)            |
| **Purpose**         | Free liquidity                        | Prevent bad debt                     |
| **Vault Condition** | High utilization required             | Any utilization                      |

**When to use each**:

* **ADA**: Vault needs liquidity, manager is healthy but risky
* **Liquidation**: Manager's position is truly at risk of bad debt

#### ADA vs. Forced Withdrawal

Some protocols have "forced withdrawal" where LP can liquidate a manager. Flux separates these:

| Feature          | Flux ADA                 | Forced Withdrawal      |
| ---------------- | ------------------------ | ---------------------- |
| **Who Executes** | Vault-level ADA manager  | Individual LP          |
| **Coordination** | Centralized, efficient   | Decentralized, chaotic |
| **Fairness**     | All LPs benefit equally  | First-mover advantage  |
| **Gas Costs**    | Single executor          | Every LP pays          |
| **Slippage**     | Optimized by ADA manager | May be rushed          |

**Flux's approach is more efficient** because:

* Single ADA manager can optimize unwinding
* No race condition between LPs
* All LPs benefit proportionally from freed liquidity
* Lower total gas costs

#### ADA vs. Interest Rate Adjustments

| Feature                | ADA                   | Dynamic Interest Rates      |
| ---------------------- | --------------------- | --------------------------- |
| **Time to Effect**     | Immediate             | Gradual                     |
| **Mechanism**          | Force close positions | Incentivize voluntary close |
| **Manager Choice**     | None                  | Yes                         |
| **Complexity**         | Simple                | Complex (IRM curves)        |
| **Emergency Response** | Effective             | Slow                        |

**Best practice**: Use both

* **Normal times**: Adjust rates to encourage borrowing/repayment
* **Emergency**: Use ADA to quickly free liquidity

***

### Technical Reference

#### Events

```
// Emitted when ADA is executed
event ADLExecuted(
    address indexed manager,
    address indexed adlManager,
    uint256 trueDebt,
    uint256 managerNetEquityUSD,
    uint256 totalPayment
);

// Emitted when ADA manager is updated
event ADLManagerUpdated(
    address indexed oldManager,
    address indexed newManager
);

// Emitted when ADA is permanently disabled
event ADLPermanentlyDisabled();
```

#### Errors

```
// ADA-specific errors
error OnlyADLManager();          // Only ADL manager can call
error PositionNotADLable();      // Position doesn't meet ADL criteria
error ADLPermanentlyDisabled();  // ADL has been disabled forever
error InsufficientADLPreparation(uint256 prepared, uint256 required);
```

#### View Functions

```
// Check if position can be ADA'd
function evaluateADL(address vault, address manager)
    external view
    returns (bool canADL, uint256 managerNetEquityUSD);

// Get ADA threshold
function adlThreshold() external view returns (uint64);

// Get ADA utilization threshold
function adlUtilizationThreshold() external view returns (uint64);

// Get current ADA manager
function adlManager() external view returns (address);

// Check if ADA is permanently disabled
function adlPermanentlyDisabled() external view returns (bool);
```

***

### Summary

**Auto-Deallocating (ADA)** is Flux's liquidity protection mechanism that allows vaults to force-close healthy-but-risky positions during high utilization.

**Key Takeaways**:

1. **Purpose**: Free up liquidity for LP withdrawals when vault is highly utilized
2. **Fair to Managers**: They receive their full net equity back (no penalties)
3. **Controlled**: Only designated ADA manager can execute
4. **Conditional**: Requires both high utilization AND position in ADA zone
5. **Optional**: Vault creators can disable or customize ADA parameters

**ADA protects LPs** from being unable to withdraw during high utilization periods, while treating managers fairly by returning their full equity.
