> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tplus.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# Withdrawals

> The withdrawal queue, signed approvals, fees, and expiry.

A withdrawal is a signed request that passes through a delay queue, is filled from vault liquidity, and produces a protocol-signed approval that the user submits to the vault contract. Approvals are quorum-signed, nonce-bound, and expiring; the vault verifies all three (see the [trust model](/security/trust-model)).

## Fees

Withdrawals pay a [rebalancing fee](/funds/rebalancing) of up to 2.5%, computed at request time and charged only after the onchain withdrawal confirms. A canceled withdrawal is charged nothing.

```text theme={null}
withdrawal_fee = withdrawal_amount * applied_rebalancing_rate
```

Example: a `10,000 USD` withdrawal with a `+1.2%` rebalancing rate charges `10,000 USD * 1.2% = 120 USD` after the onchain withdrawal confirms.

## Process

1. **Request.** A signed request (`POST /withdrawal/init`, verified against the account's multisig configuration) specifying asset, amount (18-decimal), destination address, and optionally a nonce.
2. **Lock and solvency check.** The withdrawal amount is locked. The request is rejected with nothing locked if it would leave the account under-margined once the rebalancing fee is included.
3. **Delay queue.** Every withdrawal waits a delay that scales with the account's recent [withdrawal-capacity usage](#withdrawal-capacity) for that asset, clamped to an onchain minimum and maximum. Queue status: `GET /withdrawal/queue/{user_id}`.
4. **Fill.** After the delay, the withdrawal is filled from vault liquidity, FIFO per asset. Partial fills are accepted only when at least 50% of the remaining amount can be filled.
5. **Approval and execution.** At the next [checkpoint](/security/trust-model#slot-lifecycle) after the fill, the protocol signs an approval bound to the user's nonce and a `validUntil` expiry. The user retrieves the signature(s) and calls `withdraw(...)` on the vault contract, paying gas. The vault verifies the signatures against the required `withdrawalQuorum`, the nonce, and the expiry.

Partial fills use the remaining amount:

```text theme={null}
partial_fill_allowed = available_liquidity >= 50% * remaining_amount
```

Example: if `10,000 USDC` remains, `4,999 USDC` of available liquidity waits, while `5,000 USDC` can fill.

## Withdrawal capacity

The queue delay is not fixed — it grows with how much of an asset's withdrawable liquidity the account has recently drawn down. Withdrawing an asset that is already heavily borrowed, or withdrawing the same asset repeatedly in a short span, lengthens the delay; depositing it back, or simply waiting, shortens it. Usage is tracked per account, per asset.

**Utilization.** For each asset the protocol derives a utilization ratio from vault holdings (free plus locked, across chains) and the borrows outstanding against it:

```text theme={null}
u = liabilities / (holdings + liabilities)
```

`u` runs from `0` (nothing borrowed) toward `1` (holdings nearly exhausted). It is a protocol-wide measure for the asset; the running total below is kept per account.

**Capacity usage.** A withdrawal lowers holdings and so raises `u`; a deposit does the reverse. The account accumulates the change through a convex potential function:

```text theme={null}
F(u) = u / max(1 - u, cap_floor)

usage += F(u_after) - F(u_before)     # never below 0
```

`F` climbs gently at low utilization and steeply as `u` nears `1`, so an identical withdrawal costs far more capacity when the asset is already scarce. `cap_floor` (default `5%`) floors the denominator, bounding how severe the penalty can get. The total is floored at zero — deposits cannot bank negative usage — and resets to zero after an hour, so only recent activity counts.

**Delay.** The accumulated usage is normalized to `[0, 1]` and mapped through onchain delay tiers, then clamped to the configured bounds:

```text theme={null}
delay = clamp(tier(normalized usage), min_delay, max_delay)
```

`min_delay`, `max_delay`, the tier breakpoints, and `cap_floor` are onchain configuration; a higher normalized usage selects a higher tier.

Example: with tiers `{0 → 1m, 0.3 → 5m, 0.6 → 30m}`, `min_delay = 1m`, and `max_delay = 60m`, an account at normalized usage `0.4` waits `5m`; a further withdrawal that pushes it to `0.7` moves it to the `30m` tier.

## Expiry and cancellation

* **Approval expiry.** If a signed approval's `validUntil` passes before the user calls `withdraw(...)`, the protocol verifies onchain that the withdrawal was never executed, then unlocks the locked funds; the user can submit a new request. An already-executed withdrawal is instead recognized as complete.
* **Unfilled timeout.** A withdrawal that cannot be filled from vault liquidity expires from the queue after 24 hours, with the same onchain non-execution check before funds are unlocked.
* **Cancellation.** A queued withdrawal can be canceled with a signed cancel request (`POST /withdrawal/cancel`). Locked funds return immediately; no rebalancing fee is charged.

Because both expiry paths confirm onchain non-execution before unlocking, a withdrawal can never be both executed and refunded.

## Operator failure

If the TEE network goes permanently offline, the vaults' escape hatch allows forced withdrawal onchain without operator participation. Mechanics: [trust model](/security/trust-model#escape-hatch).
