Skip to main content

CLOB (OpshunsClob)

Each options market is an OpshunsClob clone: an ERC-6909 book for a fixed token0 / token1 / premium triple. The mothership OrdersFacet is the user-facing entry for posting, claiming, exercising, and settling shorts. RFQ fills also settle into the same clone via bilateral fillMatched.

For RFQ fill modes (leg-by-leg, FixedPackage, Dutch, Authority), see On-chain fill modes. Building your own matching stack? Call the CLOB directly or Settle matched intents with your own RFQ. Contract helpers: TypeScript SDK (opshunsMothership, orderBuy / orderSell).

What the book is​

ConceptRole
Pair / CLOB addressFactory-deployed clone for one underlying pair + premium token
PairKeyOption terms packed into a bijective ERC-6909 id (premiumTick, strikeWad, exercise window, min notional)
Long inventoryFungible buyId for the series (filled inventory clears premium; see below)
Short inventory0xF2… short-lot NFTs (fungible sellId supply stays 0; sellId is terms only)
Resting queuesPer-tick FIFO bids (premium) and asks (underlying); remainder enqueues as order NFTs (0xF0… buy / 0xF1… sell)
LadderTick bitmap keyed by optionKey (PairKey with premium cleared) for cross-premium discovery

Ids are a fixed bit layout (not a hash): same terms → same pool ids; decode recovers terms bit-for-bit. Full prefixes and counters: ERC-6909 token id namespaces. Premium encoding: Premium ratio.

Posting orders (mothership)​

Typical flow:

Wallet → OrdersFacet.orderBuy / orderSell (+ optional Permit2)
→ clone orderBuy(Referral) / orderSell(Referral)
→ optional WouldTake / postOnly check
→ cross resting opposite side (hinted tick or ladder walk)
→ enqueue remainder (buy order NFT 0xF0… / sell order NFT 0xF1…)
→ matched sell size mints short-lot NFT (0xF2…)
  • Buy posts premium against the book.
  • Sell posts underlying.
  • Args include postOnly (revert with WouldTake if the order would immediately cross) and LadderHint (prevTick / nextTick) to seed bitmap insertion / matching.
  • Min-notional floors apply on CLOB posts (BelowMinNotional if too small). RFQ fillMatched skips that gate.
  • Trailing referrer on orderBuy / orderSell is chosen by the caller. RFQ and FixedPackage bind it inside takerAddressHash instead. See Fees.

The trading app’s Post to book path for a single call/put talks to this stack. REST helpers: Orders & exclusive fills.

Matching vs RFQ​

Two different ways liquidity clears into the same 6909 inventory:

Resting book​

Makers (or any wallet) leave standing bids/asks at a discrete premiumTick. Crosses happen when a counterparty posts. The clone walks the tick bitmap ladder (optionally seeded by LadderHint) to find opposing liquidity across ticks.

Bilateral fillMatched​

RFQ / package settlement after the mothership has already pulled ERC-20 premium + underlying:

Settle RFQ fillMatched after mothership has pulled premium + underlying into this core… No ERC-20 pulls. mint + pool accounting only.

  • Does not advance live queue cursors (bilateral mint; no claim queue).
  • Inventory RFQ, FixedPackage, and Dutch all fillMatched with premiumTick = 0. Cash premium, when there is one, is the package amount settled first. Premium-tick math is for the resting book: Premium ratio.

Filled inventory shares one bucket​

Resting order ids keep the full premium tick (each level is its own FIFO queue). Filled longs and short-lot terms clear premium → one series id per strike / window / type. A zero-premium fill and a premium fill of the same strike therefore land in the same buyId / filledStates bucket. Details: token ids.

RFQ does not take the book​

Inventory executeIntent and package / Dutch legs settle with bilateral fillMatched at premiumTick = 0. There is no per-leg option premium and no ClobOffer slice that lifts resting bids or asks. Resting liquidity is taken only when someone posts orderBuy / orderSell on the premium book.

FixedPackage and Dutch pull an absolute package premium first, then the same zero-premium fillMatched.

Lifecycle after mint​

Once you hold 6909 inventory you can:

  • Claim / manage queued order NFTs (0xF0… / 0xF1…)
  • Exercise longs (buyId): American anytime before expiry when startExerciseTimestamp == 0; European-style when start equals expiry
  • Settle shorts via settleShort(lotId) on the short-lot NFT (0xF2…): early full-assignment strike, or post-expiry strike + unassigned underlying (burn-settle)

Exact selectors are on OrdersFacet / IOpshunsClob. Prefer mothership entrypoints so approvals and fees stay consistent. Id prefixes: token id namespaces.

Fees​

CLOB, RFQ, and package fills share one set of treasury powers. A resting order pays maker-post on the size that queues (kept on cancel). The fill cuts a protocol fee out of the posted amount: taker rate on an immediate cross, half that rate when the resting maker is filled. Default rates, the same-currency cap, and who sets referrer: Fees.

Integrator tips​

  1. Resolve the pair address from the factory / networks registry (opshuns6909_contract in quote intents).
  2. Predict ids with mothership resolvePairKey / clone helpers so off-chain books match on-chain packing (min-notional sentinels are materialized before packing).
  3. Approve the mothership for ERC-20 pulls (or use Permit2 witnesses), not only the clone.
  4. Standard ERC-20 only. no fee-on-transfer or rebasing tokens.
  5. Index portfolio by series (optionKey), not by resting premium tick: fills collapse premium.