Withdraw And Redeem Flow
King's Vault V2 supports two distinct variants of withdrawal mechanics depending on whether the investor interacts with the synchronous vault or the asynchronous vault.
Synchronous Withdraw And Redeem Flow
KingsVaultV2 handles redemptions immediately. If idle assets within the vault are insufficient to cover the withdrawal, it automatically triggers the Controller's liquidity waterfall.
sequenceDiagram
participant Investor
participant Vault
participant Controller
participant Strategy
Investor->>Vault: withdraw(assets, receiver, owner) / redeem(shares, receiver, owner)
Vault->>Vault: check INVESTOR, not paused, not shutdown
Vault->>Vault: check assets >= MIN_WITHDRAW
alt idleAssets < requested assets
Vault->>Controller: fundReplenishOnlyForVault(vault, shortage)
Controller->>Strategy: replenish(pro-rata amount)
Strategy-->>Vault: asset transfer
end
Vault->>Vault: burn shares
Vault-->>Investor: transfer assets to receiver
Liquidity Waterfall
If the requested withdrawal amount exceeds idleAssets:
- Vault calculates the missing amount:
shortage = requestedAssets - idleAssets. - Vault calls
Controller.fundReplenishOnlyForVault(address(this), shortage). - Controller loops over all registered strategies.
- Strategies with zero assets are skipped.
- The shortage is allocated pro-rata according to each active strategy's
totalAssets(). - If a strategy reverts during
replenish(), the Controller removes it from the in-memory retry set and retries with the remaining strategies. - Each successful withdrawal proportionally decreases the Controller's book value through
_decreaseBookValue().
If no strategy liquidity can cover the total shortage (e.g., all strategies revert or run out of funds), the flow may revert with InsufficientStrategyAssets.
Asynchronous Withdrawal Flow
KingsVaultV2Async changes the withdrawal semantics. withdraw() and redeem() do not immediately transfer assets back to the user. Instead, they escrow the shares within the vault and create a claimable request.
sequenceDiagram
participant Investor
participant AsyncVault
participant Keeper
Investor->>AsyncVault: withdraw/redeem
AsyncVault->>AsyncVault: transfer shares from owner to vault
AsyncVault->>AsyncVault: add RedeemRequest(owner, receiver)
Keeper->>AsyncVault: executeRedeem()
AsyncVault->>AsyncVault: snapshot pending shares/assets
Investor->>AsyncVault: claim(receiver)
AsyncVault->>AsyncVault: burn escrowed shares
AsyncVault-->>Investor: transfer reserved assets
Request Phase
| Step | Detail |
|---|---|
| Validate | Caller must have Roles.INVESTOR, vault must not be paused or shutdown, amount must meet MIN_WITHDRAW. |
| Allowance | If caller is not owner, _spendAllowance(owner, caller, shares) is verified and spent. |
| Escrow | Shares move from the owner to the vault contract. |
| Merge | An existing request for the same (owner, receiver) pair is merged into the current execId. |
| Auto-claim | If an old request for the same pair is already executable, _claim() runs before storing the new request. |
Execution Phase
- The Keeper calls
executeRedeem(). - The Vault converts all
_pendingRedeemSharesto assets using the current preview price. - The Vault verifies that
execAssets <= idleAssets(). - The Vault writes an
ExecSnapshot. - Shares move from pending to claimable.
- Assets become reserved in
_claimableAssets. _execIdincrements, advancing the round.
Claim Phase
- Investor calls
claim(receiver). - The request is claimable only if
request.execId < _execId. - Assets are calculated pro-rata from the execution snapshot of that specific round.
- Escrowed shares are burned from the vault balance.
- Assets transfer to the receiver.