TremorDocs
Docs menu
Market mechanics

Exit, redemption and payoff

The two burn paths, the cap, payoutPerUnit and rounding.

A receipt leaves circulation in exactly one of two ways, and both burn it.

PathWhenPriceLeg
ExitBefore expiry, while the market is currentThe executable bidEXIT
RedemptionAfter finalizationThe final realized varianceSETTLE

Both are receipt → USDC swaps that pull from the same real balance — the writer's vault — through separate virtual Aqua allocations. The receipt's router-only postTransferIn hook burns every unit that arrives, so supply falls exactly with redemption and a receipt can never be recycled for a second payout.

The payoff

RVc           = min(finalVariance, capVariance)
payoutPerUnit = floor(unitNotional · RVc / 1e18)          USDC (6 dec) per 1e18 units
proceeds(u)   = floor(u · payoutPerUnit / 1e18)

payoutPerUnit is written once, by finalize, and never changes. Before finalization it does not exist, and the app says "not yet fixed" rather than showing an estimate dressed as a price.

The most one unit can ever pay is maxPayoutPerUnit = floor(unitNotional · cap / 1e18), which is fixed at creation and is exactly what the writer's vault reserves per unit sold.

Exit

Exit is priced by the market, not by the payoff. It is the integral of the falling bid over the size being sold — see The two-sided quote — and it is clamped by four things:

units    <= units actually outstanding
units     <= units to zero bid
amountOut <= collateral this burn releases
amountOut <= the leg's Aqua balance

The third clamp is what makes one shared balance safe behind two virtual allocations. A payout can never draw more than the obligation that disappears in the same transaction.

Exit closes at expiry — the EXIT program carries a Deadline. Between saleEnd and expiry a market has no ask and only a bid, which is deliberate: nobody should be able to enter after most of the variance has already printed.

Redemption

SETTLE deliberately has no deadline. A holder who redeems years late still redeems.

exact-in:   amountOut = floor(amountIn · payoutPerUnit / 1e18)
exact-out:  unsupported — SETTLE is exact-in only

amountOut is clamped to the leg's Aqua balance and to the liability the burn releases. Rounding is maker-favouring throughout, which here costs the holder at most one base unit of USDC.

The worthless case

A series that finalizes at zero realized variance has payoutPerUnit == 0. SwapVM refuses a swap with amountOut == 0, so those receipts cannot be redeemed through the router at all. The controller exposes burnWorthless(id, units) for exactly that case: the holder burns their receipts, the writer's reservation is released, and nobody is left holding a token that can only revert. The app switches the ticket's action from Redeem to Burn automatically when it detects the state.

Measured on a Base fork

A 5-day backdated window against real Chainlink history, finalized and redeemed (contracts/test/ForkE2E.t.sol):

final realized variance   0.239751118934944514  (48.96% annualized vol)
payout per unit           23.975111 USDC
finalize                  159,192 gas
one redemption            296,021 gas
collateral released at finalization   760.248890 USDC

What we do not show

Before finalization the Lens can compute the payout implied by the variance realized so far. Tremor does not present that as an exit price. It excludes the remaining window, the premium, the spread and the depth of the bid. Where the app shows an exit value it uses the executable bid, quoted on chain, and where it shows a redemption value it uses the fixed payoutPerUnit. It never blends them.