Iris documentation
Iris is a cross-chain front-end on top of Derive's permissionless options orderbook. It owns no contracts and no liquidity — it adds the onboarding, the retail UX, and the signing layer that turns a click into a valid order on Derive.
Overview
Derive (ex-Lyra) runs a permissionless, hybrid options orderbook: the matching is fast and off-chain, settlement is non-custodial and on-chain on Derive Chain (an OP-Stack L2). Anyone with a Derive account can read the market and submit signed orders — there is no market-maker whitelist.
Iris rides that liquidity and reframes it for normal users: deposit any token from any chain, and run a single-leg, fully collateralised options strategy presented as a plain-English yield product ("deposit USDC, earn X% APR").
Architecture
any token / any chain
│ LI.FI (swap + bridge)
▼
USDC on Derive Chain ── deposit ──▶ Subaccount (collateral + positions)
▲ ▲
│ Privy embedded wallet │ signed orders (EIP-712)
│ │
┌─────┴───────────── Iris web (Next.js) ──┴──────────┐
│ funding UI · strategy cards (APR) · trade · portfolio │
└───────────────────────┬────────────────────────────┘
│ REST
┌───────────▼────────────┐
│ Iris server (Node/TS) │ holds the session key,
│ Derive client + signer │ signs every order
└───────────┬────────────┘
▼
Derive REST/WS (api.lyra.finance)| Layer | Owned by Derive | Owned by Iris |
|---|---|---|
| Liquidity / orderbook | ✓ | |
| Smart wallets, subaccounts, session keys | ✓ | |
| Matching + on-chain settlement | ✓ | |
| Cross-chain onboarding (Privy · LI.FI · Arc) | ✓ | |
| Retail framing (options → APR) | ✓ | |
| Order signer (EIP-712) | ✓ |
End-to-end flow
1 · Fund
The user holds some token on some chain. LI.FI quotes a route that swaps + bridges it into USDC heading to Derive Chain (in one transaction). The USDC lands in the user's Derive smart wallet and is deposited into a subaccount as collateral.
2 · Discover
The Iris backend reads Derive's public endpoints (get_instruments, get_ticker) for live options — prices, greeks, implied volatility, top-of-book. The strategy layer turns each option into an economics object: premium, collateral, breakeven, and an annualised yield.
3 · Trade
The user clicks a card ("Earn 72% APR"). The backend builds the trade, signs it with a session key (EIP-712), and submits it to Derive's matching engine. The order crosses the live book; the position settles on-chain and shows up in the subaccount.
Order signing (EIP-712)
Every order is a signed authorization. Iris ports the official Derive scheme (derivexyz/v2-action-signing) 1:1. The steps:
1. ABI-encode the trade module data
[asset, subId, limitPrice·1e18, amount·1e18, maxFee·1e18, recipientId, isBid]
2. moduleDataHash = keccak(encoded)
3. actionHash = keccak( abi.encode(
ACTION_TYPEHASH, subaccountId, nonce, tradeModule,
moduleDataHash, signatureExpiry, owner, signer) )
4. digest = keccak( 0x1901 ‖ DOMAIN_SEPARATOR ‖ actionHash )
5. signature = sign(digest, sessionKey) // 65 bytes
6. POST /private/order { ...order, signer, signature, nonce }The matching engine recovers the signature, checks the signer is a registered session key for that subaccount, and matches. The nonce (timestamp + random) prevents replay; the DOMAIN_SEPARATOR binds the signature to the right chain and contracts.
Strategies & economics
All three presets are the same primitive — one option, fully collateralised. They differ only in option type, direction, and collateral.
| Preset | Action | Collateral | Framed as |
|---|---|---|---|
| Cash-Secured Put | sell a put | USDC (strike × size) | "deposit USDC, earn APR" |
| Covered Call | sell a call | the underlying | "yield on an asset you hold" |
| Buy Call | buy a call | premium paid | "capped-risk upside bet" |
The yield framing for the income presets:
periodReturn = premium / collateral
APR = (premium / collateral) × (365 / daysToExpiry) × 100Security model
EOA (you) ──owner──▶ Smart Wallet ──holds──▶ Subaccount (funds + positions)
│ signs only onboarding ▲
Session key (Iris backend) ──signs orders───────┘
└─ CANNOT withdraw to an arbitrary addressIris holds only the session key. Even a fully compromised backend can place trades inside the subaccount but cannot move funds out — withdrawals require the owner key, which never leaves the user.
Backend API
| Method | Route | Purpose |
|---|---|---|
| GET | /api/health | env + trading status |
| GET | /api/presets | the strategy presets |
| GET | /api/strategies/:preset | live candidates + APR |
| GET | /api/instruments | raw option instruments |
| GET | /api/ticker/:instrument | live ticker + greeks |
| POST | /api/trade | sign + place an order |
| GET | /api/account | collateral + positions |
| GET | /api/history | trade history |
Onboarding (testnet)
The demo trades on Derive testnet (api-demo.lyra.finance, chain id 901) — no real money. One-time setup:
- Generate a session key (
npm run signkey). - Connect at
testnet.derive.xyz; get gas froml2faucet.com/derive. - Get test USDC through the app's deposit flow (the test-USDC
mint()is gated to Derive's bridge). - Create a subaccount + deposit; note the subaccount id.
- Register the session-key address on the Developers page.
- Fill
server/.envand the backend signs + submits real testnet orders.
Cross-chain funding
Three layers, no overlap: Privy (wallet + embedded wallets), LI.FI (swap+bridge into USDC, one tx), and Arc (USDC settlement hub). Privy and other wallet-infra providers are mutually exclusive — Iris commits to Privy and pairs it with LI.FI and Arc, which sit on different layers.
Demo vs. product
Demo: the backend trades from one pre-onboarded account via a session key — viewers do nothing on Derive. Product: the onboarding (smart wallet + subaccount + session key) is automatable behind Privy, so a real user goes connect → deposit → earn without ever leaving Iris. That automation is the main demo-to-product gap.