# Exits in flight (/invest/incidents/exits-in-flight)

Some protocols cannot pay out at once. Huma, Hastra and Solstice can put an exit in a queue: the vault asks to withdraw, and the protocol pays days later. While the vault waits, it holds a **claim**, meaning a right to be paid later. This page explains what happens to that claim if the protocol gets into trouble before it pays.

The examples start from the [example vault](/invest/incidents#the-example-vault-used-on-these-pages): Alice holds 4,000 USDC of Senior, June holds 1,000 USDC of Junior, and 3,000 USDC is invested in one **leg** (one investment position of the vault). Each share is worth 1 USDC at the start. The figures were measured in automated tests on copies of the real protocols and are rounded.

## How a queued exit works [#how-a-queued-exit-works]

**What.** An adapter is the small program that connects the vault to one protocol. The second version of the adapter interface (AAI v2) adds actions that complete later. The executor, the service that moves the vault's cash into and out of legs, starts one with `begin_async`, the protocol completes it in its own time, and anyone then calls `settle_async` to bring the USDC back into the vault. The open action is stored in a `PendingAction` account, one per leg.

**Why.** Without queued exits, a leg in a protocol with a waiting period could only be left by selling on a market, at a discount. A queue lets the vault get the full value back, at the cost of waiting.

**How.**

```mermaid
sequenceDiagram
    participant E as Executor
    participant V as akashi_vault program
    participant A as Adapter (AAI v2)
    participant P as Protocol
    participant K as Anyone
    E->>V: begin_async(withdraw, amount, deadline)
    V->>A: CPI aai_begin_withdraw
    A->>P: file the exit request
    A-->>V: claim value (low, mid, high)
    V->>V: create PendingAction with the claim band
    loop until the protocol pays
        K->>V: refresh_pending
        V->>A: CPI aai_value_pending
        A-->>V: claim value now (may only go down)
    end
    P-->>A: protocol completes the exit
    K->>V: settle_async
    V->>A: CPI aai_settle_withdraw (adapter proves completion)
    A-->>V: USDC into idle
    V->>V: close PendingAction
```

*Figure: a queued exit records a claim when it starts, may only lower that claim while it waits, and closes only when the adapter proves the protocol paid.*

The takeaway is that the vault never assumes a queued exit was paid. A token transfer it sees, or a deadline passing, never clears the claim. Only the adapter's settlement call can.

## What the claim is worth [#what-the-claim-is-worth]

The claim is valued differently on each protocol, because each one owes something different while the exit waits:

| Protocol | What the vault holds while it waits | Does a protocol loss reduce it? |
| --- | --- | --- |
| Huma | PST tokens in Huma's escrow, valued at the pool's price | Yes |
| Hastra | A wYLDS redemption, redeemable 1:1 for USDC (one USDC per wYLDS) | No |
| Solstice | USX in escrow, valued at par | No, unless USX itself depegs when it is sold |

*Table: how each protocol's queued exit behaves in the tests; only Huma's claim moves with a loss in the protocol.*

In the examples, the executor queues an exit of 2,000 USDC out of the 3,000 USDC leg. 2,000 USDC is the smallest exit Hastra processes in its batches, so the same amount is used for every protocol. That leaves 3,000 − 2,000 = 1,000 in the normal position, and 2,000 becomes a claim.

## Example 1: a loss while the exit waits [#example-1-a-loss-while-the-exit-waits]

The protocol loses half of its value while the exit is queued.

| | Huma | Hastra, Solstice |
| --- | --- | --- |
| The 1,000 still in the position | Falls to 500 | Falls to 500 |
| The 2,000 claim | Falls to 1,000 | Stays at 2,000 |
| Leg value after `refresh_pending` and `sync_vault` | 500 + 1,000 = 1,500 | 500 + 2,000 = 2,500 |
| Loss booked | 3,000 − 1,500 = 1,500 (Junior's 1,000, then 500 from Senior) | 3,000 − 2,500 = 500 (Junior) |
| Paid when the exit completes | About 1,000 | About 2,000 |

*Table: the same 50% protocol loss costs a Huma leg three times as much as a Hastra or Solstice leg, because Huma's claim shares the loss.*

In both cases the vault enters Recovery, the state in which new deposits and investments stop while an incident is handled. The claim was never valued above what was recorded when the exit began.

## Example 2: the protocol never pays [#example-2-the-protocol-never-pays]

The protocol stops processing exits. The executor set a deadline when it queued the exit, and in the test 31 days pass, which is beyond that deadline:

- `settle_async` still fails, because the adapter cannot prove the exit was paid.
- The claim stays open, and `refresh_pending` keeps valuing it at 2,000.
- The vault keeps running. A new investor deposits 100 USDC into Junior, and Alice withdraws 500 Senior shares for 500 USDC.

The takeaway: a stuck exit does not freeze the vault, and the vault does not write the claim off on its own. If the guardian thinks the claim will never be paid, they mark the leg ([A hack the protocol has not reported](/invest/incidents/hack-discovered)).

## Example 3: the protocol pays short [#example-3-the-protocol-pays-short]

The protocol completes the exit with 70% of what it promised, a 30% shortfall.

- **Huma** pays at a price written down by 30%: about 2,000 × 0.70 = 1,400 USDC for the 2,000 claim. The 1,000 still in Huma is also written down, to 1,000 × 0.70 = 700. The vault books both shortfalls, 600 + 300 = 900, Junior first. Junior falls from 1,000 to about 100, and Senior stays at 4,000.
- **Solstice** completes the exit in USX, but USX now trades at 0.70 USDC. Selling it would lose far more than the adapter's 1% per-swap limit, so the swap's minimum-output check refuses the sale, nothing moves, and the claim stays open at its recorded value.
- **Hastra** cannot pay short: its `complete_redeem` pays the whole request 1:1 or nothing.

The takeaway: a short payment is either booked as a loss or refused. It is never hidden.

## Example 4: the exit is cancelled [#example-4-the-exit-is-cancelled]

Huma cancels the request on its side, or the executor takes back a Hastra request with `cancel_redeem`. The executor calls `cancel_async`. The units return to the leg, the `PendingAction` is closed, and the claim folds back into the normal position, so the leg is again worth about 1,000 + 2,000 = 3,000. The vault is Active and the executor can allocate to the leg again.

## Advanced details [#advanced-details]

- A pending claim must be re-valued with `refresh_pending` after each begin or settlement, before any share-changing action. Otherwise deposits and fundings fail with `PendingClaim`.
- `begin_async` requires `deadline` to be in the future (`InvalidParams` otherwise). The deadline is informational for the protocol and the executor; the program never clears a claim because it has passed.
- While a leg has an open action, a second `begin_async` fails with `PendingClaim`, and so do the synchronous `allocate` and `deallocate` on that leg. A leg with an open action cannot be retired (`LegNotEmpty`).
- When `settle_async` reports a final settlement, every unit of the request must have been settled, otherwise it fails with `PendingActionIncomplete`. The remaining claim it reports may not be higher than the recorded claim (`InvalidActionReport`).
- Which protocols support queued exits is set per leg by `configure_v2_leg`, within the capabilities the adapter declares.
