Withdraw Flow
Withdraw unwinds the position proportionally. The user receives the volatile asset; LT handles debt repayment and share burning atomically.
sequenceDiagram
participant User
participant LT
participant AMM as LEVAMM
participant Cryptoswap
User->>LT: withdraw(shares, min_assets, receiver)
LT->>LT: _calculate_values (update buckets)
LT->>AMM: _withdraw(frac) %% compute pro-rata collateral + debt
AMM-->>LT: (d_collateral, d_debt)
LT->>Cryptoswap: transferFrom(amm, LT, d_collateral) %% reclaim LP
LT->>Cryptoswap: remove_liquidity_fixed_out(lp, 0, d_debt, 0)
Cryptoswap-->>LT: asset + crvUSD
LT->>LT: _burn(msg.sender, shares)
LT->>AMM: transfer crvUSD (repay debt allocation)
LT->>User: asset (crypto_received)
LT->>LT: distribute_borrower_fees()
remove_liquidity_fixed_out takes a fixed debt-token amount out (pinning the crvUSD side) and lets the asset side float — that is how LT guarantees the AMM's debt is repaid exactly while the user receives whatever asset falls out.
Why you might receive less than PPS × shares
Three independent causes. A single withdrawal can experience any combination of them.
1. Temporary Redemption Discount (TRD)
- Nature: LEVAMM's invariant-implied state vs. Cryptoswap's current price disagree at the moment of withdrawal.
- Sign:
preview_withdraw(shares) < pricePerShare() × shares / 1e18. - Resolution: transient — closes as arbs move through
VirtualPooland realign LEVAMM with Cryptoswap. Typical: hours to days. - Applies to: both staked and unstaked positions.
- Reference: Protocol: TRD.
2. PPS drag
- Nature: cumulative rebalance slippage over the holding period exceeded cumulative fees captured. PPS grew less than a corresponding unleveraged position would suggest — drag is embedded in the vault's accounting, not a transient gap.
- Sign: even with
TRD = 0, the redemption value at unwind is below a hypothetical "pure-fees" expectation. - Resolution: only recovers if forward fee capture outpaces forward rebalance cost — not guaranteed.
- Applies to: unstaked positions (staked has watermark protection).
- Reference: Protocol: PPS vs Redemption Value.
3. Watermark shortfall
- Nature:
staked < ideal_stakedat the time of withdrawal. The staked bucket has absorbed losses that have not yet been paid back by incoming fees. - Sign: staked-position redemption below the watermark; visible as
1 − staked/ideal_staked. - Resolution: transient — Recovery Mode routes all admin fee to the staked bucket until parity is restored.
- Applies to: staked positions only.
- Reference: Protocol: Watermark & Recovery.
Interaction
TRD and watermark shortfall are independent — a withdrawal can have nonzero TRD while also seeing a watermark shortfall. PPS drag is structurally different (accumulated inside PPS itself) and coexists with both. Use preview_withdraw for a pre-trade estimate that includes TRD, and inspect LT.liquidity for the watermark gap separately. PPS drag is visible only by comparing realised PPS to expectation over your holding period — there is no single on-chain value that surfaces it.
Events emitted
LT.Withdraw(sender, receiver, owner, assets, shares)AMM.RemoveLiquidityRaw(collateral_change, debt_change)Cryptoswap.RemoveLiquidity(from the pool)LT.DistributeBorrowerFees— on the refuel hook
Edge cases
| Case | Behaviour |
|---|---|
shares == 0 | Reverts "Withdrawing nothing" |
msg.sender == staker() or receiver == staker() | Reverts "Withdraw to/from staker" — unstake from gauge first |
AMM.is_killed() | Reverts "We're dead. Use emergency_withdraw" |
crypto_received < min_assets | Reverts "Slippage" |
Post-burn supply < MIN_SHARE_REMAINDER + shares and supply ≠ shares | Reverts "Remainder too small" — withdraw more or withdraw all |
Gas
~ 300–450k on mainnet, dominated by Cryptoswap remove_liquidity_fixed_out and LEVAMM invariant update.