Skip to content

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:

  1. Vault calculates the missing amount: shortage = requestedAssets - idleAssets.
  2. Vault calls Controller.fundReplenishOnlyForVault(address(this), shortage).
  3. Controller loops over all registered strategies.
  4. Strategies with zero assets are skipped.
  5. The shortage is allocated pro-rata according to each active strategy's totalAssets().
  6. If a strategy reverts during replenish(), the Controller removes it from the in-memory retry set and retries with the remaining strategies.
  7. 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

  1. The Keeper calls executeRedeem().
  2. The Vault converts all _pendingRedeemShares to assets using the current preview price.
  3. The Vault verifies that execAssets <= idleAssets().
  4. The Vault writes an ExecSnapshot.
  5. Shares move from pending to claimable.
  6. Assets become reserved in _claimableAssets.
  7. _execId increments, advancing the round.

Claim Phase

  1. Investor calls claim(receiver).
  2. The request is claimable only if request.execId < _execId.
  3. Assets are calculated pro-rata from the execution snapshot of that specific round.
  4. Escrowed shares are burned from the vault balance.
  5. Assets transfer to the receiver.