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: 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
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.
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
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
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
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_asyncstill fails, because the adapter cannot prove the exit was paid.- The claim stays open, and
refresh_pendingkeeps 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).
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_redeempays 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
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
- A pending claim must be re-valued with
refresh_pendingafter each begin or settlement, before any share-changing action. Otherwise deposits and fundings fail withPendingClaim. begin_asyncrequiresdeadlineto be in the future (InvalidParamsotherwise). 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_asyncfails withPendingClaim, and so do the synchronousallocateanddeallocateon that leg. A leg with an open action cannot be retired (LegNotEmpty). - When
settle_asyncreports a final settlement, every unit of the request must have been settled, otherwise it fails withPendingActionIncomplete. 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.