Smile Protocol: Complete Reference

Limitations, Solutions, Recommendations, Phases — with status and cross-references
Filter by category:
Code Category Description Status Phase References
L1 Limitation Stale-quote sniping — oracle latency gap enables picked-off trades at prices that no longer reflect reality. Partially mitigated P1 · P2 R3R5R1
L2 Limitation Invisible window — sub-threshold drift inside Chainlink's deviation threshold is undetectable on-chain; defense is pricing. Partially mitigated P1 R4S1
L3 Limitation Post-trade repricing — σ bumps apply after the fill, so traders execute at pre-bump price and eat no impact on the trade where it matters. Mitigated P1 R2P1
L4 Limitation Unbounded drain — one transaction can consume an entire authorization's collateral at a single stale price. Mitigated P1 R1P1
L5 Limitation Can't reject informed traders — every rejection rule is public; snipers simulate it and send only passing txs. Solution: price toxicity, not reject it. Acknowledged Design principle R1-R5P1-P2
L6 Limitation Parameter risk — passive LPs inherit one global σ surface (α, β) set by protocol; no LP vol opinion mechanism; exposure ∂P/∂α and ∂P/∂β. Addressed in P2 P2 S5S6P2
L7 Limitation Nudgeable feedback loop — σ bumps can be manufactured via paid round-trips; attack is costly but bounded nuisance, not free lunch. Accepted tradeoff Accepted P1
L8 Limitation Capital inefficiency — full collateral per option (1 WETH per call, K USDC per put) eliminates liquidation but caps ROI structurally. Addressed in P3 P3 S4S12P3P5
L9 Limitation Settlement oracle dependence — `settleWithChainlinkRound` is permissionless but value depends entirely on Chainlink feed; oracle risk distinct from latency. Active Design choice P0
L10 Limitation RFQ alternative costs — off-chain repricing (R6) solves L1-L5 but sacrifices passivity, composability, and trustlessness; gate behind evidence of need. Gated P3+ R6P3
L11 Limitation Soft liquidity / phantom depth — quoted depth sits in LP wallet and can be spent/revoked before JIT pull; soft quotes are indicative, not firm. Mitigated P0-P3 S1S2S3S4
L12 Limitation Per-trade gas floor — first fill in a series ~1.04M gas, but ~840k of it is the one-time OptionToken ERC-20 deploy, NOT pricing math; repeat fills ~198k (≈ a DEX swap). Mitigations: EIP-1167 clones, LP/keeper pre-deploys, cheap blockspace. Measured Open L10 (why not off-chain)
L13 Limitation Bad debt in the opt-in margin tierMarginVault (S13) is the one place "a written option always pays" can break: if writer margin, free balance, the takeover auction, the backstop pool and the insurance fund are all empty at finalization, holders are paid pro rata (HolderHaircut). Bounded by the 7× backstop ceiling and the gap-40 test, not eliminated. Also: settlement is one Chainlink heartbeat wide (hence the two-step finalize), the Aqua credit line is revocable consent not collateral, sigma still moves the premium (never the margin), takeover is whole-position only, and there is no close() by design.
WhereMarginVault.finalizeSeries (haircut path + IM ratchet), MarginVault.flag / _creditLine, MarginBackstop.withdraw guards; Limitations L13
Documented Open · opt-in S13L7L8
L14 Limitation The Uniswap v4 hook path has never run liveOptionPricingHook has two entrances. The vault path (sigmaFor to price, bumpSigma after every fill and sellback) carries the whole vol surface and is live on Anvil, Sepolia and Arc. The v4 path (beforeSwap 5% fair-value veto, afterSwap surface-wide bump) is gated to a pool manager that Deploy.s.sol sets to address(1) everywhere; no OptionToken v4 pool exists, so there is no on-chain secondary market and that feedback is a design, not a live mechanism. Exercised only in test/OptionPricingHook.t.sol with a pranked pool manager.
Wheresrc/hooks/OptionPricingHook.sol (poolManager guard), script/Deploy.s.sol (placeholder pool manager); Limitations L14, the Uniswap page
Documented Open · deployment, not code (a v4 pool per OptionToken on a chain with Uniswap v4) L3L7S7
L15 Limitation Self-fills are allowed — and economically null — no vault requires buyer != lp; a broker's wash-trade ban needs both sides of one account, which a public chain cannot see (a second wallet defeats any guard). A self-fill pays the 1% fee, moves collateral into escrow and back, creates no counterparty risk (full collateralization), but prints volume on the tape and nudges sigma (L7). The Sepolia and Arc demo fills are the deployer buying from its own range and are labelled as such.
WhereLimitations L15; receipts in the Sepolia deployment notes, the Arc deployment notes, frontend/lib/deployments.ts
Documented Open · by design (pricing, not identity — L5) L5L7
R1 Recommendation Per-block notional cap — track `(lastTradeBlock, blockNotional)` per auth; bounds loss per staleness event to one block's cap, forces multi-block sniping. Implemented P1 L4P1
R2 Recommendation Size-convex pricing — apply σ bump inside premium integral proportional to trade size; large trades eat their own impact at execution, not gift pre-bump price. Implemented P1 L3P1
R3 Recommendation Staleness-scaled spread — widen Ask−Bid continuously with `(now − updatedAt)` instead of cliff-rejecting at `maxStalenessSec`; prices L1 smoothly. Implemented P1 L1P1
R4 Recommendation Spread floor — enforce `spread ≥ Δ × deviationThreshold × spot`; the minimum edge at which quoting inside the invisible window (L2) is positive-EV. Implemented P1 L2P1
R5 Recommendation Pyth pull-oracle — taker supplies signed ~400ms price; shrinks L1 window from "heartbeat" to "sub-second drift"; quoting only (settlement stays Chainlink). Implemented P2 L1P2
R6 Recommendation Hybrid RFQ tier — signed-quote layer on top of on-chain fallback; LPs run fast repricing off-chain; build only if Phase 1–2 markouts show persistent toxicity.
Implementssrc/periphery/RfqVault.sol (EthOnline 2026) — openRange / quoteHash / formulaQuote / fillCost / fill / cancelQuote / redeem / reclaim, EIP-712 domain "Smile RFQ" v1, own settlement, same Aqua JIT pull; test/RfqVault.t.sol; the RFQ · Signed Quotes tab (wallet-signed quotes); script/rfq-lifecycle.sh. Built without the markout gate; opt-in per range.
Implemented P3+ L10S8P3
S1 Solution Honest depth display — the "size shown to a taker" number can lie: an LP's authorized `maxCollateral` might exceed what's actually still in their wallet or approved to Aqua. Fix: before showing any depth number, live-`staticcall` `min(maxCollateral − used, wallet balance, Aqua allowance)` and show that instead. No contract change — this is a frontend/API-layer read. Turns "phantom depth → failed transaction at fill time" into "taker sees the true number before ever clicking buy."
Implementsfrontend/hooks/useFirmDepth.ts frontend/components/OptionMatrix.tsx:230
Implemented P0 L11P0
S2 Solution Firmness bond — S1 stops honest LPs from accidentally displaying depth they can't back; it does nothing about an LP who deliberately displays size they never intend to honor. Fix: at `authorizeRange`, the LP escrows a small slashable bond (bps of `maxCollateral`, owner-tunable via `firmnessBondBps`). If the JIT pull ever fails at fill time, the taker's transaction claims a fixed slice of that bond — compensation for gas and for having revealed their trading intent for nothing. The bond returns in full when the LP deauthorizes cleanly.
ImplementsAquaCollateralVault.sol:226 (set rate) :309-317 (escrow at authorize)
Implemented P1 L11S3P1
S3 Solution Fill-reliability score — S2's bond prices a single bad fill; it can't tell a taker "this LP fails 1 in 3 pulls." Fix: the vault already knows every time a pull succeeds or fails (that's what pays out the S2 bond) — persist it as a per-LP `(fills, failedPulls)` counter and expose it publicly, so frontends and routers can sort/badge LPs by track record instead of trusting a single bond amount.
ImplementsAquaCollateralVault.sol:148-149 (counters) :549 (fill++) :691 (failedPull++)
Implemented P1 L11S2P1its data gates P3
S4 Solution Firm tier — S1-S3 make soft (Aqua) liquidity honestly *priced*, but a taker who needs a guarantee, not a probability, still has nothing. Fix: a parallel wrapper contract that becomes the LP's wallet from Aqua's perspective, so the collateral has no exit except Aqua's own `pull()` — firm by construction, can't fail at fill time. The quote lens prefers a firm maker over a soft one at equal price, so soft liquidity has to be strictly cheaper to still win flow.
Implementssrc/periphery/FirmEscrow.sol:30 (MVP: plain WETH/USDC only — yield-bearing wstETH/sDAI escrow from the full design is not built yet)
MVP implemented P3 L8L11P3
S5 Solution Per-range LP-quoted vol — today every LP is a price-taker of one global volatility surface set by the protocol; nobody can express "I think this is too cheap/expensive." Fix: an optional `sigmaMulBps` multiplier baked into each authorization at creation — 0 means "use the protocol default," anything else scales the surface for that LP's own range. Exactly how professional options desks quote: in vol, not price.
ImplementsAquaCollateralVault.sol:271 (param) :287 (stored on the auth)
Implemented P2 L6S6P2
S6 Solution Best-quote routing — S5 lets LPs disagree on vol, but a taker calling one specific `authId` only ever sees one LP's opinion. Fix: a router view that scans every active authorization covering a strike, skips anything whose S1 depth check would fail, and returns the single best executable Ask — plus `buyBest` to route straight to it. S5 (LPs can disagree) + S6 (takers always see the best of that disagreement) together is the actual price-discovery mechanism: the touch across competing ranges is the market vol, no external IV oracle required.
Implementssrc/periphery/SmileQuoteLens.sol:60 (bestQuote) :101 (buyBest)
Implemented P2 L11S5P2
S7 Solution External IV anchor (optional) — S5/S6 assume competing ranges show up to discover fair vol; if they don't (thin early liquidity), the passive default surface just random-walks off-fair with no correction. Fallback: peg the default surface's σ to an external reference (e.g. Deribit ATM IV) with a bounded, mean-reverting deviation around it. Deliberately not the endgame — it adds a new oracle dependency — so it only gets built if S8's markout data actually shows the passive tier drifting.
Implements not built — gated on S8 evidence of surface drift; no code yet
Planned P5 S5P5
S8 Solution Markout instrumentation — every other gate in this table ("is pricing fair," "do pick-offs exist," "should S7 get built") is a guess without a number behind it. Fix: an off-chain job that, for every fill, re-quotes the protocol's own surface at +1/+5/+30 minutes later and records the delta. Persistent negative markouts (the LP's side consistently worse a few minutes after the fill) is the standard empirical signature of adverse selection — this is the instrument that turns "we think snipers are picking us off" into a measured number.
Implementsanalytics/markouts.mjs
Implemented P0 L1R6P0
S9 Solution Covered-call / cash-secured-put one-click product — S1-S8 make the underlying market honest and competitive; this is the first product actually built on top of it. Pick a side (calls/puts) and a delta-band risk preset (10-20Δ / 20-30Δ / 30-40Δ — delta here reads as "rough probability of finishing in the money") and the UI turns that into a concrete strike range, shows an estimated premium APR, and auto-chains approve → authorizeRange → Aqua.ship as one flow. A separate keeper script handles auto-roll at expiry (settle → reclaim leftover collateral → revoke → re-ship a fresh range at the new spot) — deliberately LP-run, not protocol-run, since rolling needs the LP's own signature and nobody else should be able to touch the position.
Implementsfrontend/components/IncomeOneClick.tsx keeper/roll.mjs
MVP implemented P4 P4
S10 Solution 1inch ecosystem distribution — a business-development lever, not a code change: because option premiums are quoted through a SwapVM strategy (the same mechanism 1inch's own aggregation/Fusion already routes through), 1inch's router can discover and fill Smile's option liquidity like any other swap route, and the option tokens themselves are plain ERC-20s tradable anywhere — no bespoke integration needed on 1inch's side, just listing/registry/grant work on Smile's.
Implements not applicable — distribution/BD track, no separate code path beyond the existing SwapVM strategy
Planned P4 P4
S11 Solution Long-tail listings — Deribit only lists three assets; Smile can permissionlessly list options on anything with a reliable price feed (LST/LRT tokens, L2-native majors, blue-chip DeFi tokens) — a market with zero centralized competition. The catch: thinner feeds are easier to manipulate, so each long-tail listing needs more conservative per-authorization parameters (wider spread floors, lower per-block caps, longer staleness bounds) — all args that already exist on `authorizeRange`, nothing new to build there.
Implements not built yet — the per-auth parameters it needs (spread floor, block cap, staleness bound) already exist; listing itself is unstarted
Planned P4 P4
S12 Solution Defined-risk netting — today a call spread (long a far strike, short a near one) locks collateral for the short leg as if it were naked, even though the structure's true worst case is capped at the strike gap. Fix: vault-level netting so a recognized two-leg structure only locks its actual max loss — credit spreads end up roughly 16× tighter, an iron condor locks the max of its two sides (never the sum, since one settlement price can't breach both), and a debit spread needs zero extra collateral beyond the long leg it already owns. Designed as a separate sibling `SpreadVault` app so the main vault's bytecode is never touched; implementation stays gated on evidence of actual spread demand.
Implementssrc/periphery/SpreadVault.sol (EthOnline 2026) — openStructure / quote / buy / redeem / reclaim, own Aqua strategy + own AquaOptionSettlement; SmilePremiumLib.sol (the vault's premium math as a library); test/SpreadVault.t.sol, test/SpreadSettlement.t.sol; the Spreads · Defined Risk tab; script/spread-lifecycle.sh. Call credit + put credit; iron condor strike-validated only.
Implemented P5 L8P5
S13 Solution MarginVault — opt-in true margin — rung 4 of the capital-efficiency ladder, the one that can break "a written option always pays", so it lives in a separate opt-in vault (puts, USDC) with its own settlement and backstop pool. A put writer locks initial margin — min(K·u, intrinsic + 50% of spot) off the lowest Chainlink answer of the last hour — so an ATM 3000 put locks 1,500 USDC, not 3,000. Below the 30% maintenance floor: free-balance sweep → opt-in Aqua credit line → flag → 1 h grace → 30 min takeover auction (1→10% bonus) → backstop absorbs → at expiry a per-writer waterfall, then the series finalizes drawing backstop, then insurance, then — loudly — a haircut with the IM buffer ratcheting up. Naked notional is capped at 7× the backstop pool. Margin never reads the vol hook.
Implementssrc/periphery/MarginVault.solopenRange / markSpot / marginRequirement / buy / flag / topUp / startAuction / takeOver / absorb / settlePosition / finalizeSeries / redeem; src/periphery/MarginBackstop.sol — share pool, 24 h withdraw, floor max(poolRequirement, naked/7); test/MarginVault.t.sol, MarginCall.t.sol, MarginAuction.t.sol, MarginSettlement.t.sol (gap-40 solvency), MarginInvariants.t.sol (sigma-independence, EIP-170); the Margin · Opt-in Puts tab; script/margin-lifecycle.sh; keeper/margin.mjs
Implemented P5 L13L7S12P5
P0 Phase Measure & be honest — implement S1 (honest depth display) + S8 (markout instrumentation); frontend + off-chain script; no contracts; do unconditionally. ✅ Complete S1S8
P1 Phase Harden — implement R1-R4 (per-block, size-convex, staleness, floor) + S2-S3 (bond, reliability); one contract PR; gate: markouts confirm pick-offs exist. ✅ Complete R1-R4S2-S3S8
P2 Phase Compete — implement S5-S6 (LP-quoted vol, best-quote routing) + R5 (Pyth); enables vol discovery; gate: P1 markouts improved but still uncompetitive vs Deribit. ✅ Complete R5S5-S6
P3 Phase Firm up — gate opened early (fill-failure metric can't see demand that never routes to indicative depth); MVP shipped: plain-collateral FirmEscrow + lens firm-first tiebreak. Yield-bearing upgrade still gated on S3 data + firm-tier uptake. ✅ MVP scope S4S3L11
P4 Phase Sell it — implement S9-S11 (covered-call product, 1inch distribution, long-tail listings); gate: S8's markouts show LP P&L ≥ 0 over a month (product safe to market). Gated P4 S9-S11gated by S8 data
P5 Phase Scale capital — implement S12 (defined-risk netting) + S7 (IV anchor if passive tier drifts); gate: real volume + LP demand for spreads. Gated P5 S7S12L8
Legend
Code: Unique identifier (L = Limitation, R = Recommendation, S = Solution, P = Phase)
Status: Implemented (done + deployed), Planned (designed, not yet coded), Gated (ready to build but waiting for a measurable gate to pass), Active (a standing design choice)
Phase: Which phase the item belongs to or is blocked by
References: Related items — click any to scroll to it
Implementation status summary: P0–P2 fully implemented; P3 shipped in MVP scope (plain-collateral FirmEscrow + firm-first routing — yield-bearing escrow deferred). P4–P5 gated on operational data (markouts, volume, LP demand). All design documents live in docs/; contract changes in src/ under vault, instruction, oracle, and periphery modules.