Withdrawal Limit Mechanics
Withdrawals and borrows are gated by market-level liquidity guard rails as well as by the requesting account’s own margin. Withdrawal & Borrow Limits covers what a trader sees; this page covers the calculations behind it.
There are two market-level calculations, one on each side of the vault:
- Rolling withdrawal and borrow limits, an always-on formula recalculated on every action. It is made of two checks (a level/TWAP-drift check and a utilization check) that cap how far a market’s deposit base can drain, or its borrows can grow, relative to that market’s own 24-hour trailing averages.
- Daily deposit cap, an opt-in mirror of the same idea on the deposit side, capping how far total deposits may grow above their 24-hour average in a window. Off by default; see Daily deposit cap.
The rolling calculation is sized by one per-market parameter, the withdraw guard threshold: a notional value that feeds every formula below and also sets the size of the small-depositor exception budget. It is admin-configured and capped at roughly $10,000 notional; see Protocol Guard Rails § Withdraw Guard Threshold for how it is set and by which key.
The rolling calculation is enforced on withdrawals, borrows, subaccount-to-subaccount transfers, and the settlement leg of token swaps. See What is Borrow & Lend? for how deposits and borrows relate to swaps and cross-collateral.
Rolling withdrawal & borrow limits
The check runs on every withdraw-shaped action against the affected spot market. From the market’s current balances and its 24-hour token/utilization trailing averages, it computes two bounds:
- Minimum deposit level: the lowest the market’s total deposits are allowed to fall to.
- Maximum borrow level: the highest the market’s total borrows are allowed to rise to.
Each bound is the stricter of two independent calculations: a level/TWAP-drift check and a utilization check. Whichever constraint binds first wins.
Level check
Minimum deposits. The floor on deposits is the lower of “deposit TWAP minus the market’s withdraw circuit-breaker percentage” or “deposit TWAP minus the withdraw guard threshold”:
The withdraw circuit breaker is a per-market setting, in basis points (10_000 = 100%), and must be at or below 10_000. If a market has never set one (the field reads 0), it defaults to 2_500 bps (25%), so the minimum-deposit floor defaults to 75% of the deposit TWAP unless the guard threshold cuts deeper. A larger guard threshold subtracts more from the TWAP, so it always loosens this floor. If the threshold is at or above the TWAP, that term collapses to the TWAP and the floor is set entirely by the circuit-breaker percentage. A tighter breaker means a smaller share of the deposit TWAP can leave per window. Which admin key may change it, and in which direction, is covered in Protocol Guard Rails § Withdraw Circuit Breaker.
Maximum borrows. The ceiling on borrows depends on whether the market is the main pool or an isolated pool, since isolated pools are tuned to tolerate materially higher utilization:
| Main pool | Isolated pool | |
|---|---|---|
| Utilization-floor candidate | 1/3 (≈33%) of the lesser of deposits and deposit TWAP | 1/2 (50%) of the lesser of deposits and deposit TWAP |
| TWAP-drift candidate | borrow TWAP plus 1/5 (20%) of the lesser of deposits and deposit TWAP | borrow TWAP plus 1/3 (≈33%) of the lesser of deposits and deposit TWAP |
| Hard ceiling | 13/14 (≈92.9%) of the lesser of deposits and deposit TWAP | 19/20 (95%) of the lesser of deposits and deposit TWAP |
The candidate value is the greater of the utilization-floor and TWAP-drift candidates, capped at the hard ceiling, then floored at the market’s withdraw guard threshold and capped again at the market’s total deposit ceiling times its max-borrow fraction, if that fraction is configured. In effect: borrows can grow by roughly 20% (main pool) or 33% (isolated) beyond the trailing borrow TWAP per window, but never above the pool’s hard utilization ceiling.
Utilization check
Separately, the market computes a maximum tolerable utilization for this action:
That is, never below the market’s target optimal utilization, and otherwise halfway between the current 24-hour utilization TWAP and 100%. This is translated back into token terms:
- The minimum deposit level implied by utilization is the current borrow amount divided by the maximum tolerable utilization, capped so it never blocks withdrawals once the resulting deposits would still exceed the guard threshold.
- The maximum borrow level implied by utilization is the maximum tolerable utilization times the current deposit amount, floored at the guard threshold so it never blocks small borrows.
Combining the checks
The action is then validated against the market’s post-action balances:
- If the account’s resulting position in this market is a borrow, both conditions must hold: the resulting borrow amount is at or below the maximum borrow level and the resulting deposit amount is at or above the minimum deposit level.
- If the account stays a depositor, only the minimum-deposit condition is required.
- If no specific account is passed in (a market-wide check with no user context), both conditions are required regardless of who ends up borrowing.
A withdrawal that draws an account’s deposit balance down to zero and then keeps going (opening a borrow) is checked more strictly than a withdrawal that only reduces an existing deposit, because it additionally has to clear the maximum-borrow ceiling.
Small-depositor exception
If the global check fails, one narrow exception can still let a withdrawal through. It is a per-account eligibility filter: it permits a depositor to withdraw their own principal if they have never net-withdrawn more than they’ve deposited, their position has always been a net-positive deposit, and their resulting deposit balance plus the amount withdrawn stays under 1/10th of the market’s withdraw guard threshold.
That per-account filter alone carries no information about how much the market can afford to release, so the market-level check also enforces a budget on top of it: the whole eligible cohort, no matter how many accounts qualify, can take the market’s deposits down by at most one withdraw guard threshold below the level-check floor. Because the withdraw guard threshold is itself capped at ~$10,000 notional, total exception outflow per market per TWAP window is bounded at roughly that amount, regardless of how many small accounts try to use the exception.
Where the guard threshold enters
The withdraw guard threshold (in token-precision units) feeds directly into every formula above: the level-check floor, the max-borrow ceiling, both utilization checks, and the small-depositor exception budget all read it. It also acts as the market’s designated “small market” cutout, so deposits below it are never blocked from withdrawal and borrows below it are never blocked from opening.
It does not pause withdrawals on its own. An action that breaches a rolling limit fails with a daily withdraw limit error; pausing a market is a separate admin operation, covered in Block Conditions.
Daily deposit cap
Deposits can be throttled too. The deposit side mirrors the level check above, using the same 24-hour deposit TWAP, and is governed by two per-market fields:
- Max deposit growth (basis points): how far above the 24-hour deposit TWAP the market’s total deposits may grow in a window.
0disables the cap entirely, which is the value every market is created with, so a market has no deposit cap until an admin sets one. - Deposit guard threshold (token-precision units): a floor below which the cap never binds. It is the deposit-side mirror of the withdraw guard threshold: deposits are always allowed to reach at least this level, however small the TWAP is.
The check is a level predicate over the whole market: after the deposit, the market’s total deposit token amount must be at or below this maximum. It is not a per-user quota, so a deposit can be rejected because of everyone else’s deposits in the same window rather than because of its own size.
Because it is a level predicate, the check only applies when the market’s deposit level actually grew. It compares the deposit token amount before and after the balance update and returns early when the level did not rise. Withdrawals and borrow repayments share the same credit path, and those are exactly the actions that bring a market back under its cap, so they are never blocked by it.
A rejected deposit fails with a daily deposit limit error. Both fields are set together by a single admin update; see Protocol Guard Rails § Deposit Cap.
The deposit cap is one of several reasons a deposit can be refused. The market’s aggregate deposit ceiling, the market-scoped Deposit pause, reduce-only status, and pool-id mismatch are all separate checks, applied on the same instruction. See Block Conditions.