Trade crypto options on Thetanuts Finance - orderbook fills, RFQ lifecycle, multi-strike structures, real-time WebSocket, wallet management, early settlement, referrer fees
IMPORTANT: On EVERY new conversation, the agent MUST run these checks before doing anything else.
Step 0: Check for skill updates (ALWAYS run first)
└─> bash scripts/update.sh
└─> If update found: inform user "Skill updated to vX.Y.Z — reloading with latest features"
└─> If already up to date: proceed silently (don't mention it)
Step 1: Check wallet status
└─> node scripts/wallet-discover.js
Step 2: Interpret the result:
- configured: false → Enter ONBOARDING MODE
- configured: true → Greet user with their address, proceed normally
Why always check for updates? The skill evolves frequently with new option types, SDK features, and bug fixes. Running update.sh ensures the agent always has the latest trading capabilities. Updates NEVER modify wallet secrets (.env, WDK_SEED).
When no wallet is configured, guide the user through setup in this order:
No wallet detected
│
▼
┌─────────────────────────────────────────┐
│ "Welcome to Thetanuts Options Trading! │
│ Let's get you set up in 3 steps." │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Step 1: Create or import a wallet │
│ • New user → wallet-create.js │
│ • Have a seed? → wallet-import.js │
│ │
│ WARN: Use a DEDICATED wallet. │
│ Never reuse your primary wallet seed. │
│ Custody stays LOCAL on your machine. │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Step 2: Verify & fund the wallet │
│ • Run wallet-discover.js → show address │
│ • Run wallet-balance.js --chain │
│ base-mainnet │
│ • If zero balance: explain funding │
│ - Need ETH on Base for gas fees │
│ - Need USDC for PUT trades │
│ - Need WETH for CALL trades │
│ - Bridge via bridge.base.org │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Step 3: Market overview & first trade │
│ • Fetch prices: get-prices.ts │
│ • WebSearch for market news │
│ • Ask risk preference (LOW/MED/HIGH) │
│ • Show first strategy recommendation │
└─────────────────────────────────────────┘
Once wallet is configured, present:
Welcome to Thetanuts Options Trading!
Your wallet: 0x...
Chain: Base Mainnet
Balances: X ETH (gas) | Y USDC | Z WETH
What would you like to do?
• "Show me options" → View available strikes and prices
• "Recommend a strategy" → I'll check market news and suggest based on your risk preference
• "Check my positions" → View open trades and P&L on expired ones
• "What's the market doing?" → Latest crypto news and how it affects options
New to options? Just say "teach me about options"
.thetanuts-keys/ directory — lost keys cannot decrypt past offers.TNUT Agent is your AI-powered assistant for trading crypto options on Thetanuts Finance.
What it does:
Local-first design:
Capabilities:
| Category | What You Can Do |
|---|---|
| Wallet | Create, import, check balances |
| Market Data | Live prices, MM quotes, orderbook orders |
| Trading | Fill orderbook orders, submit RFQs, approve tokens |
| Positions | View open positions, calculate payoffs |
Options are contracts that give you the right (but not obligation) to buy or sell an asset at a specific price by a specific date.
A PUT gives the holder the right to SELL at the strike price.
| Action | You... | Profit When | Risk |
|---|---|---|---|
| Buy PUT | Pay premium upfront | Price drops below strike | Lose premium if price stays up |
| Sell PUT | Receive premium | Price stays above strike | Lose if price drops below strike |
Example:
A CALL gives the holder the right to BUY at the strike price.
| Action | You... | Profit When | Risk |
|---|---|---|---|
| Buy CALL | Pay premium upfront | Price rises above strike | Lose premium if price stays down |
| Sell CALL | Receive premium | Price stays below strike | Lose if price rises above strike |
Example:
| Term | Definition |
|---|---|
| Strike | The price at which the option can be exercised |
| Expiry | When the option expires (settlement date, 8:00 UTC) |
| Premium | The price paid for the option |
| Settlement | Cash payment based on price difference at expiry |
| Collateral | Funds locked to back the option (for sellers) |
IMPORTANT: Different option types require different collateral tokens:
| Option Type | Implementation | Collateral Required |
|---|---|---|
| PUT | PUT | USDC (quote asset) |
| CALL | INVERSE_CALL | WETH (base asset) |
(collateral × 1e8) / strikecollateral / 1e12 (1 WETH = 1 contract)The build-rfq.ts script automatically selects the correct collateral based on option type.
Beyond vanilla PUT and CALL options, Thetanuts supports advanced multi-strike structures for sophisticated trading strategies.
| Type | Strikes | Collateral | Description |
|---|---|---|---|
| PUT | 1 | USDC | Standard cash-settled put |
| INVERSE_CALL | 1 | WETH | Cash-settled call (base collateral) |
| CALL_SPREAD | 2 | USDC | Buy lower strike call, sell higher strike call |
| PUT_SPREAD | 2 | USDC | Buy higher strike put, sell lower strike put |
| CALL_FLY | 3 | USDC | Call butterfly - profit near middle strike |
| PUT_FLY | 3 | USDC | Put butterfly - profit near middle strike |
| CALL_CONDOR | 4 | USDC | Call condor - wider profit range |
| PUT_CONDOR | 4 | USDC | Put condor - wider profit range |
| IRON_CONDOR | 4 | USDC | Put spread + call spread (neutral) |
| PHYSICAL_CALL | 1 | WETH | Physically settled call |
| PHYSICAL_PUT | 1 | USDC | Physically settled put |
CRITICAL: Strikes must be ordered correctly or the RFQ will fail.
| Structure | Type | Strike Order | Example |
|---|---|---|---|
| Vanilla | PUT/CALL | N/A (1 strike) | --strike 1900 |
| Spread | PUT | Descending (high→low) | --strikes 1900,1800 |
| Spread | CALL | Ascending (low→high) | --strikes 2000,2100 |
| Butterfly | PUT | Descending | --strikes 1900,1850,1800 |
| Butterfly | CALL | Ascending | --strikes 2000,2050,2100 |
| Condor | ALL | Always ascending | --strikes 1800,1900,2100,2200 |
These are simplified formulas for quick estimation. For exact on-chain values, use previewFillOrder() or client.utils.calculateCollateral().
| Structure | Collateral | Simplified Formula | Example |
|---|---|---|---|
| Vanilla PUT | USDC | collateral / strike | $1900 USDC at $1900 strike = 1 contract |
| INVERSE_CALL | WETH | collateral (1:1) | 1 WETH = 1 contract |
| CALL_SPREAD | USDC | collateral / (upper - lower) | $100 USDC / $100 width = 1 contract |
| PUT_SPREAD | USDC | collateral / (upper - lower) | $100 USDC / $100 width = 1 contract |
| Butterfly | USDC | collateral / (middle - lower) | $50 USDC / $50 wing = 1 contract |
| Condor | USDC | collateral / (strike2 - strike1) | $100 USDC / $100 inner width = 1 contract |
| IRON_CONDOR | USDC | collateral / max(K2-K1, K4-K3) | Based on wider wing |
| PHYSICAL_CALL | WETH | Same as INVERSE_CALL | 1 WETH = 1 contract |
| PHYSICAL_PUT | USDC | Same as Vanilla PUT | collateral / strike |
Key rule: Only INVERSE_CALL and PHYSICAL_CALL use WETH (base asset). Everything else uses USDC — including CALL_SPREAD, CALL_FLY, and CALL_CONDOR.
| Structure | Market View | Risk Level | Risk/Reward | Best For |
|---|---|---|---|---|
| PUT | Bearish | HIGH | Large profit (up to strike - premium), lose premium | Strong downside conviction |
| CALL | Bullish | HIGH | Unlimited profit, lose premium | Strong upside conviction |
| PUT_SPREAD | Moderately bearish | MEDIUM | Capped profit/loss | Cheaper than vanilla put |
| CALL_SPREAD | Moderately bullish | MEDIUM | Capped profit/loss | Cheaper than vanilla call |
| PUT_FLY | Neutral/range-bound | LOW | High reward if pinned, tiny cost | Low cost, precise target |
| CALL_FLY | Neutral/range-bound | LOW | High reward if pinned, tiny cost | Low cost, precise target |
| CONDOR | Neutral/range-bound | MEDIUM | Lower reward, wider range | More forgiving than fly |
| IRON_CONDOR | Neutral | LOW | Collect premium both sides | Range-bound markets |
| PHYSICAL_CALL | Bullish (want delivery) | HIGH | Receive underlying asset | Physical settlement needed |
| PHYSICAL_PUT | Bearish (want delivery) | HIGH | Deliver underlying asset | Physical settlement needed |
When a user asks for a strategy recommendation, FIRST ask about their risk preference, then match to appropriate strategies within that tier.
Present these three options:
| Risk Level | What It Means | Max Loss | Profit Potential |
|---|---|---|---|
| LOW | Defined max loss, premium collection, high probability of small wins | Capped & known upfront | Capped but consistent |
| MEDIUM | Spreads with balanced risk/reward, moderate probability | Capped at spread width | Capped at spread width |
| HIGH | Full directional exposure, low probability of large wins | Full premium (buyer) or very large (seller) | Unlimited (buyer) |
User wants a strategy recommendation
│
▼
┌──────────────────────────────────┐
│ Step 1: Check market news │
│ (WebSearch - see News section) │
└──────────────────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Step 2: Ask risk level │
│ LOW / MEDIUM / HIGH │
└──────────────────────────────────┘
│
├── LOW RISK
│ │
│ ├── Neutral view ──────► IRON_CONDOR (sell)
│ │ Collect premium both sides, profit if range-bound
│ │ Max loss: spread width - premium
│ │ Max gain: premium collected
│ │ Win prob: ~60-70% (price stays in range)
│ │
│ ├── Slightly bullish ──► PUT_FLY (buy) or Sell PUT via orderbook
│ │ Butterfly: tiny cost, big payout if pinned
│ │ Max loss: premium paid (very small)
│ │ Max gain: wing width - premium
│ │
│ ├── Slightly bearish ──► CALL_FLY (buy) or Sell CALL via orderbook
│ │ Same as above, opposite direction
│ │
│ └── Range-bound ───────► Butterfly (CALL_FLY / PUT_FLY)
│ Cheapest defined-risk play
│ Max loss: premium paid (~$3-5/contract)
│ Max gain: wing width (~$47-50/contract)
│
├── MEDIUM RISK
│ │
│ ├── Bullish ──────────► CALL_SPREAD (buy)
│ │ Cheaper than vanilla call, capped both sides
│ │ Max loss: premium paid
│ │ Max gain: spread width - premium
│ │ Risk/Reward: typically 1:1 to 1:3
│ │
│ ├── Bearish ─────────► PUT_SPREAD (buy)
│ │ Cheaper than vanilla put, capped both sides
│ │ Max loss: premium paid
│ │ Max gain: spread width - premium
│ │
│ └── Range-bound ─────► CONDOR (CALL_CONDOR / PUT_CONDOR)
│ Wider profit range than butterfly
│ Max loss: wing width - premium collected
│ Max gain: premium collected (sell) or inner width (buy)
│
└── HIGH RISK
│
├── Bullish ──────────► CALL (vanilla buy) / INVERSE_CALL
│ Unlimited profit potential if price rises
│ Max loss: full premium paid
│ Max gain: unlimited
│
├── Bearish ─────────► PUT (vanilla buy)
│ Unlimited profit if price crashes
│ Max loss: full premium paid
│ Max gain: strike - premium (if price → 0)
│
└── Selling premium ──► Naked PUT sell or CALL sell
Collect premium, very large risk if wrong
Max loss: strike price (PUT) or unlimited (CALL)
Max gain: premium collected
Every strategy recommendation MUST include this card:
┌────────────────────────────────────────────────┐
│ Strategy: [STRATEGY NAME] │
│ Risk Level: [LOW / MEDIUM / HIGH] │
│ Direction: [BULLISH / BEARISH / NEUTRAL] │
├────────────────────────────────────────────────┤
│ Max Loss: $[amount] ([description]) │
│ Max Gain: $[amount] ([description]) │
│ Break-even: $[price] │
│ Win Zone: Price between $[low] and $[high] │
│ Collateral: [amount] [token] │
└────────────────────────────────────────────────┘
Different structures give you different exposure per dollar of collateral:
| Structure | $100 Collateral Gets You | Relative Efficiency | Risk Level |
|---|---|---|---|
| Vanilla PUT (at $2000 strike) | ~0.05 contracts | 1x (baseline) | HIGH |
| PUT_SPREAD ($100 width) | 1 contract | 20x more | MEDIUM |
| Butterfly ($50 wing width) | 2 contracts | 40x more | LOW |
| Condor ($100 inner width) | 1 contract | 20x more | MEDIUM |
| Iron Condor ($100 inner width) | 1 contract | 20x more | LOW |
Key Insight: For users with small collateral (under $100), LOW and MEDIUM risk strategies (spreads, butterflies) provide significantly more market exposure than HIGH risk vanilla options.
When recommending a strategy, consider these inputs in order of priority:
| Priority | Input | How to Determine | Impact on Recommendation |
|---|---|---|---|
| 1 | Risk Level | Ask user: low, medium, or high? | PRIMARY filter — determines available strategies |
| 2 | Market View | Ask user: bullish, bearish, or neutral? | Determines direction within risk tier |
| 3 | News/Events | WebSearch for recent market events | Informs conviction level and timing |
| 4 | Collateral Size | Check wallet balance | Small = prefer spreads/butterflies for efficiency |
| 5 | Conviction Level | Ask: strong view or moderate? | High conviction may justify higher risk tier |
| 6 | Expiry Timeframe | Check available expiries | Short-term neutral = butterfly, Longer = condor |
Before EVERY strategy recommendation, the agent MUST search for recent market-moving events. This ensures context-aware recommendations, not purely technical ones.
Use WebSearch with these queries (run at least 2):
| Query | Purpose |
|---|---|
"crypto market news today" | General market sentiment |
"ethereum price catalyst" or "bitcoin price catalyst" | Asset-specific events |
"FOMC meeting crypto" or "CPI inflation crypto" | Macro events affecting crypto |
"crypto options expiry this week" | Options-specific events (pin risk, gamma squeeze) |
"ethereum upgrade" or "bitcoin ETF flows" | Protocol/regulatory catalysts |
If WebSearch returns a relevant article, use WebFetch to get deeper details.
| Event Type | Expected Impact | Suggested Direction | Risk Note |
|---|---|---|---|
| Rate cut / dovish Fed | Bullish | CALL-side strategies | MEDIUM — market may "sell the news" |
| Rate hike / hawkish Fed | Bearish | PUT-side strategies | MEDIUM — may already be priced in |
| Major exchange hack/exploit | Bearish (short-term) | PUT-side strategies | HIGH — volatility spike |
| ETF approval / large inflows | Bullish | CALL-side strategies | MEDIUM — catalyst may be priced in |
| Protocol upgrade (successful) | Bullish for that asset | CALL-side strategies | LOW-MEDIUM |
| Regulatory crackdown | Bearish | PUT-side or neutral | HIGH — uncertainty and fear |
| Large options expiry (high OI) | Neutral → pin risk | Butterflies / Condors (LOW risk) | LOW — defined risk |
| No significant news | Neutral / range-bound | Premium selling (Iron Condor) | LOW — collect theta decay |
| Conflicting signals | Uncertain | Neutral structures or wait | Reduce size, use LOW risk |
When presenting a strategy recommendation, always include market context:
Market Context (from recent news):
• [Event 1]: [brief description] → [bullish/bearish/neutral]
• [Event 2]: [brief description] → [bullish/bearish/neutral]
Overall market bias: [BULLISH / BEARISH / NEUTRAL / UNCERTAIN]
Based on [RISK LEVEL] risk preference and current market conditions:
[Strategy recommendation with Risk Summary Card]
2-Strike Spread (CALL_SPREAD):
npx tsx scripts/build-rfq.ts \
--underlying ETH \
--type CALL \
--strikes 2000,2100 \
--expiry 1774684800 \
--contracts 1 \
--direction buy
Buy $2000 call, sell $2100 call. Max profit = $100 - premium. Max loss = premium.
3-Strike Butterfly (PUT_FLY):
npx tsx scripts/build-rfq.ts \
--underlying ETH \
--type PUT \
--strikes 1900,1850,1800 \
--expiry 1774684800 \
--contracts 1 \
--direction buy
Profit maximized if ETH settles at $1850. Low cost, high reward if pinned.
4-Strike Condor (IRON_CONDOR):
npx tsx scripts/build-rfq.ts \
--underlying ETH \
--type PUT \
--strikes 1800,1900,2100,2200 \
--expiry 1774684800 \
--contracts 1 \
--direction sell
Sell iron condor. Collect premium if ETH stays between $1900-$2100.
The SDK supports two trading systems. Choose based on your use case:
| OptionBook | RFQ (Factory) | |
|---|---|---|
| What | Fill existing market-maker orders | Create custom options via sealed-bid auction |
| When to use | Quick trades on listed options | Custom strikes, expiries, multi-leg structures |
| Structures | Vanilla only | Vanilla, spread, butterfly, condor, iron condor |
| Key methods | fillOrder(), previewFillOrder() | buildRFQRequest(), requestForQuotation() |
| Pricing | Order prices from fetchOrders() | MM pricing from getAllPricing() |
| Data source | Book indexer (/api/v1/book/) | Factory indexer (/api/v1/factory/) |
| User data | getUserPositionsFromIndexer() | getUserRfqs(), getUserOptionsFromRfq() |
| Stats | getBookProtocolStats(), getBookDailyStats() | getFactoryProtocolStats(), getFactoryDailyStats() |
| Collateral | Paid upfront by taker | collateralAmount = 0 (held by factory) |
| Settlement | Cash only | Cash or physical |
What it is: Fill existing orders posted by market makers - instant execution.
You → Fill existing order → Instant trade
Best for:
How it works:
npx tsx scripts/fetch-orders.ts --type PUTnpx tsx scripts/fill-order.ts --order-index 0 --collateral 10 --seed "..." --executeWhat it is: Request a custom quote from market makers - they respond within 45 seconds.
You → Submit RFQ → MM sees it → MM sends encrypted offer → You settle (or accept early)
Best for:
How it works:
npx tsx scripts/build-rfq.ts --underlying ETH --type PUT --strike 1900 --expiry <timestamp> --contracts 0.1 --direction buyto and data| Scenario | Use | Why |
|---|---|---|
| "I see a good price on orderbook" | Orderbook | Instant execution |
| "Standard strike, liquidity exists" | Orderbook | Faster, simpler |
| "Custom strike not on orderbook" | RFQ | Only way to get it |
| "Large size trade" | RFQ | May get better pricing |
| "Need it filled NOW" | Orderbook | RFQ takes up to 6 min |
| "No orders at my strike" | RFQ | Request custom quote |
| "Multi-leg structure" | RFQ | Orderbook only supports vanilla |
| "Physical settlement" | RFQ | Orderbook is cash-only |
Agent Decision Logic:
When a user wants to trade, the agent ALWAYS checks the orderbook first before recommending a trading method.
User wants to trade
│
▼
┌─────────────────────────┐
│ check-orderbook.ts │
│ Check for liquidity │
└─────────────────────────┘
│
▼
┌─────────────────────────┐
│ Exact strike match? │
└─────────────────────────┘
│ │
Yes No
│ │
▼ ▼
┌─────────┐ ┌─────────────────┐
│Orderbook│ │Nearby strikes? │
│ Fill │ │(within ±5%) │
└─────────┘ └─────────────────┘
│ │
Yes No
│ │
▼ ▼
┌─────────┐ ┌─────┐
│Show │ │ RFQ │
│options │ │ │
└─────────┘ └─────┘
Before recommending orderbook or RFQ, run:
npx tsx scripts/check-orderbook.ts --underlying ETH --type PUT --strike 1900 --expiry 1774684800 --direction sell
The script returns:
recommendation: "orderbook" or "rfq"reason: Explanation of whyorderbookOrders: Matching orders with pricesnearbyStrikes: Alternative strikes if exact not foundnextStep: Command to run nextScenario 1: Liquidity Found
User: "Sell a PUT at $1900"
Agent: Runs check-orderbook.ts
Result: {
"recommendation": "orderbook",
"reason": "Found orderbook liquidity at strike $1900. Best bid: $8.08. Available: 75 contracts."
}
Agent: "Found a buyer at $8.08/contract. Use orderbook for instant execution."
Scenario 2: No Exact Match, Nearby Available
User: "Sell a PUT at $1850"
Agent: Runs check-orderbook.ts
Result: {
"recommendation": "rfq",
"reason": "No orderbook liquidity at $1850. Nearby strikes: $1900 (+2.7%), $1925 (+4.1%)"
}
Agent: "No orders at $1850, but $1900 is available (+2.7%). Would you like that, or submit RFQ for $1850?"
Scenario 3: Partial Fill
User: "Sell 100 contracts at $1900"
Agent: Runs check-orderbook.ts --size 100
Result: {
"recommendation": "orderbook",
"partialFillAvailable": true,
"partialSize": 75,
"reason": "Found 75 contracts (you requested 100). Partial fill available."
}
Agent: "Only 75 contracts available on orderbook. Fill partial now, or use RFQ for full 100?"
Step 1: Check wallet
└─> node scripts/wallet-discover.js
Step 2: Check balance
└─> node scripts/wallet-balance.js --chain base-mainnet --tokens 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Step 3: Fetch orderbook
└─> npx tsx scripts/fetch-orders.ts --type PUT
Step 4: Preview fill (see what you'll get)
└─> npx tsx scripts/fill-order.ts --order-index 0 --collateral 10 --seed "..."
Step 5: Execute fill
└─> npx tsx scripts/fill-order.ts --order-index 0 --collateral 10 --seed "..." --execute --wait
Step 1: Check wallet & balance (same as above)
Step 2: Get MM pricing to see market levels
└─> npx tsx scripts/get-mm-pricing.ts ETH --type PUT
Step 3: Build RFQ with your terms
└─> npx tsx scripts/build-rfq.ts --underlying ETH --type PUT --strike 1900 --expiry 1774684800 --contracts 0.1 --direction buy
Step 4: Approve tokens (if selling/first time)
└─> npx tsx scripts/approve-token.ts --token 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --spender 0x1aDcD391CF15Fb699Ed29B1D394F4A64106886e5 --max --seed "..." --wait
Step 5: Send RFQ transaction
└─> npx tsx scripts/send-transaction.ts --to <from step 3> --data <from step 3> --seed "..." --wait
Step 6: Wait for MM offer (up to 45 seconds)
Step 7: Verify RFQ fill
└─> npx tsx scripts/check-rfq-fill.ts --address <wallet> --ticker <expected> --since <submission_timestamp>
└─> If filled: Shows position details
└─> If not filled: Shows suggestions for next steps
npx tsx scripts/get-positions.ts 0xYourWalletAddress
After trades expire, show the user their realized returns. This workflow uses existing scripts — no new tools needed.
Step 1: Fetch all positions
└─> npx tsx scripts/get-positions.ts <wallet_address>
Step 2: Categorize by status
- Settled/expired positions → REALIZED P&L
- Active/open positions → UNREALIZED (show separately)
Step 3: For each expired position
- Use the pnlUsd field from get-positions.ts (if available)
- If pnlUsd is missing, calculate manually:
└─> For PUT/CALL: npx tsx scripts/calculate-payout.ts --type <PUT|CALL> --strike <strike> --settlement <settlement_price> --contracts <amount> [--is-buyer]
└─> For spreads/butterflies/condors: use client.option.calculatePayout(optionAddress, settlementPrice) on-chain
(Note: calculate-payout.ts only supports vanilla PUT/CALL — multi-strike payouts need the SDK on-chain method)
Step 4: Aggregate and present using the template below
For BUYERS (paid premium):
For SELLERS (received premium):
Present results in this format:
Portfolio Performance Summary
══════════════════════════════════════════════════════════
Wallet: 0x...
Period: [earliest expired trade] to [latest expired trade]
REALIZED P&L (Expired Positions)
┌──────────────────────┬──────┬─────────┬─────────┐
│ Trade │ Side │ P&L │ ROI │
├──────────────────────┼──────┼─────────┼─────────┤
│ ETH-28MAR-2000-P │ SELL │ +$12.50 │ +6.25% │
│ ETH-28MAR-2100-C │ BUY │ -$8.00 │ -100% │
│ ETH-04APR-1900/1800 │ BUY │ +$45.00 │ +150% │
├──────────────────────┼──────┼─────────┼─────────┤
│ TOTAL │ │ +$49.50 │ │
└──────────────────────┴──────┴─────────┴─────────┘
Win rate: 2/3 (66.7%)
Average P&L per trade: +$16.50
Best trade: ETH PUT_SPREAD (+$45.00, +150%)
Worst trade: ETH CALL (-$8.00, expired worthless)
OPEN POSITIONS
┌──────────────────────┬──────┬───────────┬──────────┬────────┐
│ Trade │ Side │ Contracts │ Expiry │ Status │
├──────────────────────┼──────┼───────────┼──────────┼────────┤
│ ETH-18APR-2000-P │ BUY │ 0.5 │ Apr 18 │ Active │
└──────────────────────┴──────┴───────────┴──────────┴────────┘
After a market maker submits an encrypted offer to your RFQ, you can decrypt and accept it early — no need to wait for the full deadline.
Step 1: Submit RFQ (Workflow 2, Steps 1-5)
Step 2: MM sends encrypted offer (within 45 seconds)
Step 3: Decrypt the offer using your ECDH keypair
└─> Uses client.rfqKeys.decryptOffer()
Step 4: Accept the offer early
└─> Uses client.optionFactory.encodeSettleQuotationEarly(quotationId, offerAmount, nonce, offeror)
└─> Send transaction with returned {to, data}
Real examples:
0x105f75cdfb64a3796100f6d667bc4f7fec3836d2b5aa5c43b66073a1b40964ee0xa89fb6dbad43b430399bbdec878927185e602b7df9b5390f71d2d11c33e4d850If a user wants to cancel an active RFQ before it settles, or if no MM responded:
┌─────────────────────────────────────────────────────┐
│ RFQ submitted │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ MM responded? │ │
│ └─────────────────────┘ │
│ │ │ │
│ Yes No │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌──────────────────────────────┐ │
│ │ Accept │ │ RFQ expires with no offers │ │
│ │ or │ │ → No collateral was locked │ │
│ │ Cancel? │ │ → Nothing to refund │ │
│ └─────────┘ └──────────────────────────────┘ │
│ │ │ │
│ Accept Cancel │
│ │ │ │
│ ▼ ▼ │
│ Settle Cancel RFQ │
│ └─> cancelQuotation(quotationId) │
│ └─> Collateral returned to wallet │
└─────────────────────────────────────────────────────┘
// Cancel before settlement — requester only
const { to, data } = client.optionFactory.encodeCancelQuotation(quotationId);
// Send transaction with {to, data} via send-transaction.ts
// MM cancels their offer before settlement
const { to, data } = client.optionFactory.encodeCancelOfferForQuotation(quotationId);
// Query current state of an RFQ
const quotation = await client.optionFactory.getQuotation(quotationId);
// quotation status: 'active' | 'settled' | 'cancelled'
// quotation.isActive — whether RFQ is still open
// quotation.currentWinner — winning offeror's address
| Scenario | Collateral | What Happens |
|---|---|---|
| Buy RFQ, no MM responds | No collateral locked by buyer | Nothing to refund — buyer only pays premium if settled |
| Buy RFQ, user cancels before settlement | No collateral locked | RFQ cancelled, no action needed |
| Sell RFQ, no MM responds | Collateral held by factory | RFQ expires, collateral returned automatically |
| Sell RFQ, user cancels before settlement | Collateral held by factory | cancelQuotation() releases collateral back to wallet |
| Sell RFQ, settled | Collateral locked in option | Collateral backs the option until expiry/settlement |
| Orderbook fill (buy or sell) | Collateral paid/locked at fill | Irreversible — no cancellation for orderbook fills |
IMPORTANT: Orderbook fills are INSTANT and IRREVERSIBLE. Only RFQs can be cancelled (before settlement).
No ETH is sent as transaction value for option trades. All collateral flows happen via ERC-20 token transfers (USDC, WETH). ETH is only used for gas fees.
Buyer Flow:
1. Premium is paid in collateral tokens (USDC for PUTs, WETH for CALLs)
2. Token approval needed: approve-token.ts (one-time per token/spender)
3. Collateral is transferred to the contract when the trade executes
4. If RFQ: collateralAmount = 0 in the request (factory holds it)
5. If Orderbook: collateral deducted at fill time
What you PAY: Premium (in USDC or WETH) + gas (in ETH)
What you GET: Option position (right to profit if price moves your way)
At expiry: Payout if in-the-money, or nothing if out-of-the-money
Seller Flow:
1. Collateral is LOCKED to back the option (USDC for PUTs, WETH for CALLs)
2. Token approval needed: approve-token.ts (one-time per token/spender)
3. Collateral transferred to contract and held until expiry
4. Premium is received from buyer
What you PAY: Collateral lock (USDC or WETH) + gas (in ETH)
What you GET: Premium received upfront
At expiry: Keep premium if OTM, or payout difference if ITM
Remaining collateral returned after settlement
| Action | Collateral Token | Gas Token | Approval Needed |
|---|---|---|---|
| Buy PUT | USDC (premium) | ETH | USDC → OptionFactory/OptionBook |
| Buy CALL | WETH (premium) | ETH | WETH → OptionFactory/OptionBook |
| Sell PUT | USDC (collateral lock) | ETH | USDC → OptionFactory/OptionBook |
| Sell CALL | WETH (collateral lock) | ETH | WETH → OptionFactory/OptionBook |
Always check balance BEFORE trading:
# Check USDC balance (for PUTs)
node scripts/wallet-balance.js --chain base-mainnet --tokens 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
# Check WETH balance (for CALLs)
node scripts/wallet-balance.js --chain base-mainnet --tokens 0x4200000000000000000000000000000000000006
# Check ETH balance (for gas)
node scripts/wallet-balance.js --chain base-mainnet
The winner (winningOfferor) in an RFQ is always the market maker with the best offer price. Winner selection works the same way for ALL option types — PUT, CALL, spreads, butterflies, condors, iron condors, and physical options.
The winner address appears in three places depending on context:
| Context | Field | When to Use |
|---|---|---|
| On-chain state | QuotationState.currentWinner | During active RFQ — the current best offeror |
| State API | StateRfq.winner | After settlement — the final winning MM |
| Settlement event | QuotationSettledEvent.winningOfferor | Emitted when RFQ settles |
| Type | Buyer Payout Formula | Max Payout | Settlement |
|---|---|---|---|
| PUT | max(strike - price, 0) × contracts | strike × contracts | Cash (USDC) |
| INVERSE_CALL | max(price - strike, 0) × contracts | Unlimited | Cash (WETH) |
| CALL_SPREAD | min(max(price - K1, 0), K2 - K1) × contracts | (K2 - K1) × contracts | Cash (USDC) |
| PUT_SPREAD | min(max(K1 - price, 0), K1 - K2) × contracts | (K1 - K2) × contracts | Cash (USDC) |
| CALL_FLY | Peaks at middle strike, 0 at wings | wing width × contracts | Cash (USDC) |
| PUT_FLY | Peaks at middle strike, 0 at wings | wing width × contracts | Cash (USDC) |
| CALL_CONDOR | Flat max between K2-K3, tapers at wings | inner width × contracts | Cash (USDC) |
| PUT_CONDOR | Flat max between K2-K3, tapers at wings | inner width × contracts | Cash (USDC) |
| IRON_CONDOR | Profit if price between K2-K3 | premium collected | Cash (USDC) |
| PHYSICAL_CALL | Buyer receives underlying asset | N/A (delivery) | Physical |
| PHYSICAL_PUT | Buyer delivers underlying, receives USDC | N/A (delivery) | Physical |
The SDK utility client.utils.calculatePayout() supports these types:
type PayoutType = 'call' | 'put' | 'call_spread' | 'put_spread';
For butterflies, condors, and iron condors: use client.option.calculatePayout(optionAddress, settlementPrice) which calculates on-chain for any option type, or use client.option.simulatePayout() for simulation.
// For vanilla and spreads — use utility function
const payout = client.utils.calculatePayout({
type: 'call_spread',
strikes: [2000n * 10n**8n, 2100n * 10n**8n],
settlementPrice: 2050n * 10n**8n,
numContracts: 1n * 10n**18n,
});
// For butterflies, condors, iron condors — use on-chain calculation
const payout = await client.option.calculatePayout(optionAddress, settlementPrice);
When an option settles at expiry, these events are emitted:
| Event | Fields | Description |
|---|---|---|
OptionExpiredEvent | settlementPrice | Oracle records the final price |
OptionPayoutEvent | buyer, amountPaidOut | Buyer receives payout (if ITM) |
CollateralReturnedEvent | seller, amountReturned | Seller gets remaining collateral back |
Physical options involve actual asset delivery instead of cash settlement:
| Type | Buyer Pays | Buyer Receives | Seller Provides |
|---|---|---|---|
| PHYSICAL_CALL | strike × contracts (USDC) | contracts of underlying (WETH) | WETH collateral |
| PHYSICAL_PUT | contracts of underlying (WETH) | strike × contracts (USDC) | USDC collateral |
The SDK has dedicated builders for physical options:
client.optionFactory.buildPhysicalRFQ()client.optionFactory.buildPhysicalSpreadRFQ()client.optionFactory.buildPhysicalButterflyRFQ()client.optionFactory.buildPhysicalCondorRFQ()When viewing orders, availableAmount represents the maker's collateral budget, not the number of contracts. The actual number of purchasable contracts depends on the option type and collateral requirements.
These are the on-chain formulas using raw decimal values. For practical use, prefer previewFillOrder() which handles all conversions automatically.
| Option Type | # Strikes | Collateral | On-Chain Formula | Example |
|---|---|---|---|---|
| Vanilla PUT | 1 | USDC | (collateral × 1e8) / strike | 10,000 USDC at $95k = 0.105 contracts |
| INVERSE_CALL | 1 | WETH | collateral / 1e12 | 1 WETH = 1 contract |
| CALL_SPREAD | 2 | USDC | (collateral × 1e8) / spreadWidth | 10,000 USDC / $10k = 1 contract |
| PUT_SPREAD | 2 | USDC | (collateral × 1e8) / spreadWidth | 10,000 USDC / $10k = 1 contract |
| BUTTERFLY | 3 | USDC | (collateral × 1e8) / maxSpread | Based on widest strike range |
| CONDOR | 4 | USDC | (collateral × 1e8) / maxSpread | Based on widest strike range |
| PHYSICAL_CALL | 1 | WETH | Same as INVERSE_CALL | 1 WETH = 1 contract |
| PHYSICAL_PUT | 1 | USDC | Same as Vanilla PUT | Same formula |
IMPORTANT: Only single-strike CALL options (INVERSE_CALL, PHYSICAL_CALL) use WETH collateral. ALL multi-strike structures use USDC, even CALL_SPREAD, CALL_FLY, and CALL_CONDOR.
Always use previewFillOrder() to see the actual contract count before filling:
const order = orders[0];
// Preview shows calculated max contracts based on collateral requirements
const preview = client.optionBook.previewFillOrder(order);
console.log(`Max contracts: ${preview.maxContracts}`);
console.log(`Collateral token: ${preview.collateralToken}`);
console.log(`Price per contract: ${preview.pricePerContract}`);
// Preview with specific premium amount
const preview10 = client.optionBook.previewFillOrder(order, 10_000000n); // 10 USDC premium
console.log(`Contracts for 10 USDC: ${preview10.numContracts}`);
For a PUT option with a $95,000 strike:
The previewFillOrder() method handles these calculations automatically for all option types.
| Module | Purpose | Requires Signer |
|---|---|---|
client.erc20 | Token approvals, balances, transfers | Write ops only |
client.optionBook | Fill/cancel orders, get fees, preview fills | Write ops only |
client.api | Fetch orders, positions, stats | No |
client.optionFactory | RFQ lifecycle management | Write ops only |
client.option | Position management, payouts | Write ops only |
client.events | Query blockchain events (OfferMade, QuotationRequested) | No |
client.ws | Real-time WebSocket subscriptions | No |
client.pricing | Option pricing, Greeks | No |
client.mmPricing | Market maker pricing with fee adjustments | No |
client.rfqKeys | ECDH keypair management for sealed-bid RFQ encryption | No |
client.utils | Decimal conversions, payoffs | No |
The SDK supports a referrer address for fee sharing on order fills. When a referrer is set, a portion of the trading fees is allocated to the referrer.
// Option 1: Set referrer at client initialization (applies to all fills)
const client = new ThetanutsClient({
chainId: 8453,
provider,
signer,
referrer: '0x92b8ac05b63472d1D84b32bDFBBf3e1887331567',
});
// All fillOrder calls will use this referrer automatically
await client.optionBook.fillOrder(order);
// Option 2: Pass referrer per fill call (overrides client default)
await client.optionBook.fillOrder(order, undefined, '0xYourReferrerAddress');
// Option 3: Use encode methods (for viem/wagmi/AA wallets)
const { to, data } = client.optionBook.encodeFillOrder(
order,
collateralAmount,
'0x92b8ac05b63472d1D84b32bDFBBf3e1887331567'
);
const hash = await walletClient.sendTransaction({ to, data });
// Query referrer fee split
const feeBps = await client.optionBook.getReferrerFeeSplit('0x...');
console.log(`Referrer fee: ${feeBps} bps`);
// Query accumulated fees
const fees = await client.optionBook.getFees(usdcAddress, '0x...');
console.log(`Accumulated fees: ${fees}`);
If no referrer is provided, the zero address (0x000...) is used (no fee sharing).
The SDK uses ECDH (Elliptic Curve Diffie-Hellman) key pairs for encrypted offers in the RFQ system. Keys are automatically persisted based on your environment:
| Environment | Default Storage | Persistence |
|---|---|---|
| Node.js | FileStorageProvider | Keys saved to .thetanuts-keys/ directory |
| Browser | LocalStorageProvider | Keys saved to localStorage |
// Keys are automatically persisted - no configuration needed
const keyPair = await client.rfqKeys.getOrCreateKeyPair();
console.log('Public Key:', keyPair.compressedPublicKey);
// Keys are saved automatically and survive process restarts
IMPORTANT: Back up your RFQ private keys! Keys are stored in
.thetanuts-keys/with secure permissions. If lost, you cannot decrypt offers made to your public key. There is no recovery mechanism.
Subscribe to live updates for orders and prices:
const client = new ThetanutsClient({ chainId: 8453, provider });
// 1. Connect
await client.ws.connect();
// 2. Subscribe to order updates
const unsubOrders = client.ws.subscribeOrders((update) => {
console.log(`Order ${update.event}:`, update);
});
// 3. Subscribe to price updates for ETH
const unsubPrices = client.ws.subscribePrices((update) => {
console.log(`ETH price: $${update.price}`);
}, 'ETH');
// 4. Handle connection state changes
const unsubState = client.ws.onStateChange((state) => {
console.log(`WebSocket state: ${state}`);
});
// 5. Disconnect when done
// unsubOrders(); unsubPrices(); unsubState();
// client.ws.disconnect();
The WebSocket module auto-reconnects by default (up to 10 attempts).
All SDK methods throw ThetanutsError with typed error codes:
import { isThetanutsError, OrderExpiredError, InsufficientAllowanceError } from '@thetanuts-finance/thetanuts-client';
try {
await client.optionBook.fillOrder(order, 10_000000n);
} catch (error) {
if (error instanceof OrderExpiredError) {
console.log('Order expired, fetching fresh orders...');
const freshOrders = await client.api.fetchOrders();
} else if (error instanceof InsufficientAllowanceError) {
console.log('Approving tokens first...');
await client.erc20.ensureAllowance(usdcAddress, optionBookAddress, amount);
} else if (isThetanutsError(error)) {
switch (error.code) {
case 'SLIPPAGE_EXCEEDED': console.log('Price moved too much'); break;
case 'INSUFFICIENT_BALANCE': console.log('Not enough tokens'); break;
case 'SIGNER_REQUIRED': console.log('Signer required'); break;
case 'CONTRACT_REVERT': console.log('Contract call failed'); break;
}
}
}
| Code | Description |
|---|---|
ORDER_EXPIRED | Order has expired or will expire soon |
SLIPPAGE_EXCEEDED | Price moved beyond tolerance |
INSUFFICIENT_ALLOWANCE | Token approval needed |
INSUFFICIENT_BALANCE | Not enough tokens |
NETWORK_UNSUPPORTED | Network not supported |
HTTP_ERROR | API request failed |
CONTRACT_REVERT | Smart contract call failed |
INVALID_PARAMS | Invalid parameters provided |
ORDER_NOT_FOUND | Order not found |
SIZE_EXCEEDED | Fill size exceeds available |
SIGNER_REQUIRED | Signer needed for transaction |
WEBSOCKET_ERROR | WebSocket connection error |
interface ThetanutsClientConfig {
chainId: 8453; // Required: Chain ID
provider: Provider; // Required: ethers.js provider
signer?: Signer; // Optional: For transactions
referrer?: string; // Optional: Referrer address for fees
apiBaseUrl?: string; // Optional: Override API URL
indexerApiUrl?: string; // Optional: Override indexer URL
pricingApiUrl?: string; // Optional: Override pricing URL
wsUrl?: string; // Optional: Override WebSocket URL
env?: 'dev' | 'prod'; // Optional: Environment (default: prod)
logger?: ThetanutsLogger; // Optional: Custom logger
keyStorageProvider?: StorageProvider; // Optional: Custom RFQ key storage
}
const client = new ThetanutsClient({
chainId: 8453,
provider,
logger: {
debug: (msg, meta) => myLogger.debug(msg, meta),
info: (msg, meta) => myLogger.info(msg, meta),
warn: (msg, meta) => myLogger.warn(msg, meta),
error: (msg, meta) => myLogger.error(msg, meta),
},
});
Before deploying to production, verify the following:
https://mainnet.base.org which has strict rate limitsreferrer address to earn fee-sharing revenue on fillslogger to capture errors in Sentry/Datadogclient.erc20.ensureAllowance() before fillOrder()order.expiry before filling to avoid wasted gas estimates.thetanuts-keys/ directory — lost keys cannot decrypt past offersThe SDK provides utilities for safe decimal conversions:
| Type | Decimals | Example |
|---|---|---|
| USDC | 6 | 1000000 = 1 USDC |
| WETH | 18 | 1000000000000000000 = 1 WETH |
| cbBTC | 8 | 100000000 = 1 cbBTC |
| Strike/Price | 8 | 185000000000 = $1850 |
// Convert to on-chain values
const usdc = client.utils.toBigInt('100.5', 6); // 100500000n
const strike = client.utils.strikeToChain(1850); // 185000000000n
// Convert from on-chain values
const display = client.utils.fromBigInt(100500000n, 6); // '100.5'
const price = client.utils.strikeFromChain(185000000000n); // 1850
Agent: [Triggers onboarding flow]
wallet-discover.js → no wallet foundAgent: Welcome to Thetanuts Options Trading! Let's get you set up.
I see you don't have a wallet configured yet.
Would you like to create a new wallet or import an existing one?
[After wallet creation...]
Your wallet: 0x7a3F...9e2B
Chain: Base Mainnet
Balance: 0 ETH | 0 USDC | 0 WETH
To start trading, you'll need to fund your wallet:
• ETH on Base for gas fees (bridge via bridge.base.org)
• USDC for PUT options | WETH for CALL options
Once funded, tell me:
1. What's your risk preference? (Low / Medium / High)
2. Are you bullish, bearish, or neutral on ETH?
I'll check the latest market news and recommend a strategy!
Agent:
"crypto market news today""ethereum bitcoin price catalyst this week"Agent: Let me check the latest market news...
Market Context:
• Fed meeting tomorrow — markets expect rate hold, dovish tone → BULLISH
• Large BTC options expiry ($2.3B) on Friday → potential pin risk → NEUTRAL
• ETH Layer-2 TVL hitting ATH → positive sentiment → BULLISH
Overall bias: MODERATELY BULLISH with near-term volatility expected
What risk level are you comfortable with?
LOW: Iron Condor — collect premium, profit if ETH stays in range
Good for the expected range-bound action before Fed meeting
MEDIUM: Call Spread — capped upside play on the bullish bias
Benefit from dovish Fed without unlimited downside
HIGH: Vanilla Call — unlimited upside if Fed sparks a rally
Lose full premium if market sells the news
Agent:
Agent: Here are the LOW RISK strategies available right now:
┌────────────────────────────────────────────────────────┐
│ Strategy: Iron Condor (ETH) │
│ Risk Level: LOW │
│ Direction: NEUTRAL │
├────────────────────────────────────────────────────────┤
│ Strikes: $1800 / $1900 / $2100 / $2200 │
│ Max Loss: $85/contract │
│ Max Gain: $15/contract (premium collected) │
│ Win Zone: ETH stays between $1900-$2100 │
│ Current ETH: $2,050 (right in the sweet spot!) │
│ Collateral: ~$100 USDC per contract │
└────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────┐
│ Strategy: Put Butterfly (ETH) │
│ Risk Level: LOW │
│ Direction: NEUTRAL (target $2,000) │
├────────────────────────────────────────────────────────┤
│ Strikes: $1950 / $2000 / $2050 │
│ Max Loss: ~$3/contract (premium paid) │
│ Max Gain: ~$47/contract (if ETH settles at $2,000) │
│ Win Zone: ETH settles near $2,000 │
│ Collateral: ~$50 USDC per contract │
└────────────────────────────────────────────────────────┘
Which strategy interests you? Or want to see MEDIUM or HIGH risk options?
Agent:
get-positions.ts with user's wallet addressAgent: Let me check your trading performance...
Portfolio Performance Summary
══════════════════════════════════════════════════════════
Wallet: 0x7a3F...9e2B
Period: Mar 14, 2026 to Apr 11, 2026
REALIZED P&L (Expired Positions)
┌───────────────────────┬──────┬──────────┬─────────┐
│ Trade │ Side │ P&L │ ROI │
├───────────────────────┼──────┼──────────┼─────────┤
│ ETH-28MAR-2000-P │ SELL │ +$12.50 │ +6.25% │
│ ETH-28MAR-2100-C │ BUY │ -$8.00 │ -100% │
│ ETH-04APR-1900/1800-PS│ BUY │ +$45.00 │ +150% │
├───────────────────────┼──────┼──────────┼─────────┤
│ TOTAL │ │ +$49.50 │ │
└───────────────────────┴──────┴──────────┴─────────┘
Win rate: 2/3 (66.7%)
Average P&L per trade: +$16.50
Best trade: ETH PUT_SPREAD (+$45.00, +150% ROI)
Worst trade: ETH CALL (-$8.00, expired worthless)
Insight: Your MEDIUM risk spread trades outperformed the HIGH risk
vanilla call. Consider focusing on spreads for better risk-adjusted returns.
OPEN POSITIONS
┌───────────────────────┬──────┬───────────┬──────────┐
│ Trade │ Side │ Contracts │ Expiry │
├───────────────────────┼──────┼───────────┼──────────┤
│ ETH-18APR-2000-P │ BUY │ 0.5 │ Apr 18 │
└───────────────────────┴──────┴───────────┴──────────┘
Want me to analyze what your open position might settle at?
User: Show me ETH puts
Agent:
npx tsx scripts/get-mm-pricing.ts ETH --type PUTAgent's Decision Process:
If Orderbook:
Agent: There's a BID at $1900. Let me fill it for you.
1. Previews: "You'll sell ~0.005 contracts, receive ~$X premium"
2. Asks: "Proceed?"
3. Executes fill
If RFQ:
Agent: No orderbook liquidity at $1900. I'll submit an RFQ.
1. Builds RFQ for ETH-1900-PUT sell
2. Approves USDC if needed
3. Submits RFQ
4. "RFQ submitted. MMs have 45 seconds to respond."
Agent:
npx tsx scripts/get-positions.ts 0xYourAddressAgent's Decision Process:
Agent:
Market Context:
• ETH down 3% on regulatory concerns → BEARISH
• Overall market sentiment weak → confirms bearish view
With $50 and a bearish view at MEDIUM risk, I recommend a PUT SPREAD:
┌────────────────────────────────────────────────────────┐
│ Strategy: PUT_SPREAD Risk: MEDIUM │
│ Direction: BEARISH │
├────────────────────────────────────────────────────────┤
│ Max Loss: $50 (your full collateral) │
│ Max Gain: $50 (spread width - premium) │
│ Break-even: ~$1892 │
│ Win Zone: ETH below $1900 at expiry │
│ Collateral: $50 USDC → 0.5 contracts (20x more than │
│ vanilla PUT which gives only 0.026) │
└────────────────────────────────────────────────────────┘
Available strikes for tomorrow's expiry:
• PUT_SPREAD $1950/$1850 - Bid: $12/contract
• PUT_SPREAD $1900/$1800 - Bid: $8/contract
Which spread would you like?
Want HIGH risk instead? Vanilla PUT gives unlimited profit but only 0.026 contracts.
Want LOW risk instead? Put Butterfly costs ~$3 with $47 max gain.
Agent's Decision Process:
Agent:
Market Context:
• No major catalysts this week → NEUTRAL
• Options expiry Friday with large OI at $2000 → pin risk → NEUTRAL
With $30 and a neutral view, here's my LOW RISK recommendation:
┌────────────────────────────────────────────────────────┐
│ Strategy: CALL_FLY (Butterfly) Risk: LOW │
│ Direction: NEUTRAL (target $2,050) │
├────────────────────────────────────────────────────────┤
│ Strikes: 2000 / 2050 / 2100 │
│ Max Loss: ~$5/contract (premium paid) │
│ Max Gain: ~$45/contract (at exactly $2050) │
│ Break-even: $2005 - $2095 │
│ Collateral: $30 → ~6 contracts │
└────────────────────────────────────────────────────────┘
Why butterfly (LOW risk)?
• Cheapest way to play range-bound (more contracts per dollar)
• Max loss is tiny (~$5/contract)
• If ETH pins near $2050, each contract pays ~$45
Want MEDIUM risk? A Condor ($100+) gives a wider profit zone.
Build this RFQ? (y/n)
Agent's Decision Process:
Agent:
Market Context:
• Market consolidating after rally → NEUTRAL
• No major events this week → supports range-bound play
For premium selling, I recommend an IRON CONDOR (LOW RISK):
┌────────────────────────────────────────────────────────┐
│ Strategy: IRON_CONDOR (sell) Risk: LOW │
│ Direction: NEUTRAL (profit if range-bound) │
├────────────────────────────────────────────────────────┤
│ Strikes: $1800 / $1900 / $2100 / $2200 │
│ Max Loss: $85/contract (if ETH exits range) │
│ Max Gain: $15/contract (premium collected) │
│ Win Zone: ETH stays between $1900-$2100 │
│ Current ETH: $2,000 (right in the middle!) │
│ Collateral: ~$100 USDC per contract │
└────────────────────────────────────────────────────────┘
This strategy profits ~60-70% of the time in range-bound markets.
You collect $15 premium and risk $85 if wrong.
Is ETH likely to stay between $1900-$2100? Let me build this RFQ.
Tailor detail level to the user's experience:
| User Type | How to Detect | What to Show |
|---|---|---|
| New user | First session, no wallet, asks basic questions | Simplified info, no SDK details, guide step-by-step |
| Returning user | Has wallet, has traded before | Relevant data for their question, skip basics |
| Advanced user | Asks about multi-strike, SDK, specific params | Full technical detail, contract addresses, raw data |
For strategy recommendations — Always include the Risk Summary Card (see "Risk-Categorized Strategy Recommendations" section for the full template with all fields: Strategy, Risk Level, Direction, Max Loss, Max Gain, Break-even, Win Zone, Collateral).
For price/market data — Use compact tables:
ETH Options (PUT) — Current Price: $2,050
┌────────────┬─────────┬────────┬────────┐
│ Strike │ Expiry │ Bid │ Ask │
├────────────┼─────────┼────────┼────────┤
│ $1,900 │ Apr 25 │ $8.50 │ $12.00 │
│ $2,000 │ Apr 25 │ $25.00 │ $30.00 │
└────────────┴─────────┴────────┴────────┘
For trade confirmations — Clear summary before execution:
Trade Summary
═════════════
Action: Buy PUT_SPREAD
Risk Level: MEDIUM
Strikes: $1900 / $1800
Expiry: Apr 25, 2026
Contracts: 1.0
Cost: ~$15 USDC
Max Loss: $15 | Max Gain: $85
Confirm? (yes/no)
For errors — Never show raw JSON to the user:
{"error": "INSUFFICIENT_ALLOWANCE"} → "You need to approve USDC spending first. Want me to do that?"| Tool | When to Use | Example |
|---|---|---|
| WebSearch | Before every strategy recommendation (fetch market news) | "crypto market news today" |
| WebFetch | Drill into a specific article or data source from WebSearch results | Fetch full article content |
| context7 | When user asks about SDK features or encounters an unfamiliar error | Resolve thetanuts-finance/thetanuts-client, then query docs |
When a user asks a technical question about the Thetanuts SDK:
resolve-library-id to find thetanuts-finance/thetanuts-clientquery-docs with the specific topic (e.g., "fillOrder", "WebSocket", "error handling")| Command | Description |
|---|---|
node scripts/wallet-discover.js | Check if wallet configured, show addresses |
node scripts/wallet-create.js | Generate new wallet |
node scripts/wallet-import.js --seed-file /path | Import existing seed |
node scripts/wallet-balance.js --chain base-mainnet | Check balance |
node scripts/wallet-select.js --family evm --chain base-mainnet | Set active chain |
| Command | Description |
|---|---|
npx tsx scripts/get-prices.ts | Get BTC/ETH prices |
npx tsx scripts/get-mm-pricing.ts ETH --type PUT | Get MM option quotes |
npx tsx scripts/fetch-orders.ts --type PUT | Fetch orderbook |
npx tsx scripts/check-orderbook.ts --underlying ETH --type PUT --strike 1900 --expiry <ts> --direction sell | Check orderbook liquidity (run FIRST before trading) |
| Command | Description |
|---|---|
npx tsx scripts/fill-order.ts --order-index 0 --collateral 10 --seed "..." --execute | Fill orderbook order |
npx tsx scripts/build-rfq.ts --underlying ETH --type PUT --strike 1900 --expiry <ts> --contracts 0.1 --direction buy | Build vanilla RFQ (45s deadline) |
npx tsx scripts/build-rfq.ts --underlying ETH --type CALL --strikes 2000,2100 --expiry <ts> --contracts 1 --direction buy | Build multi-strike RFQ (spread/fly/condor) |
npx tsx scripts/approve-token.ts --token <addr> --spender <addr> --max --seed "..." | Approve tokens |
npx tsx scripts/send-transaction.ts --to <addr> --data <hex> --seed "..." | Send transaction |
npx tsx scripts/check-rfq-fill.ts --address <wallet> --ticker <expected> --since <ts> | Verify RFQ fill status |
| Command | Description |
|---|---|
npx tsx scripts/get-positions.ts <address> | Get open positions |
npx tsx scripts/calculate-payout.ts --type PUT --strike 1900 --settlement 1800 --contracts 1 | Calculate payoff |
| Contract | Address |
|---|---|
| OptionBook | 0xd58b814C7Ce700f251722b5555e25aE0fa8169A1 |
| OptionFactory | 0x1aDcD391CF15Fb699Ed29B1D394F4A64106886e5 |
| Token | Address | Decimals |
|---|---|---|
| USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | 6 |
| WETH | 0x4200000000000000000000000000000000000006 | 18 |
| cbBTC | 0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf | 8 |
| cbDOGE | 0x73c7A9C372F31c1b1C7f8E5A7D12B8735c817C79 | 8 |
| cbXRP | 0x7B2Cd9EA5566c345C9cdbcF58f5E211a0dB47444 | 6 |
| aBasWETH | 0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7 | 18 |
| aBascbBTC | 0xBdb9300b7CDE636d9cD4AFF00f6F009fFBBc8EE6 | 8 |
| aBasUSDC | 0x4e65fE4DbA92790696d040ac24Aa414708F5c0AB | 6 |
| Type | Address |
|---|---|
| PUT | 0xF480F636301d50Ed570D026254dC5728b746A90F |
| INVERSE_CALL | 0x3CeB524cBA83D2D4579F5a9F8C0D1f5701dd16FE |
| CALL_SPREAD | 0x4D75654bC616F64F6010d512C3B277891FB52540 |
| PUT_SPREAD | 0xC9767F9a2f1eADC7Fdcb7f0057E829D9d760E086 |
| CALL_FLY | 0xD8EA785ab2A63a8a94C38f42932a54A3E45501c3 |
| PUT_FLY | 0x1fE24872Ab7c83BbA26Dc761ce2EA735c9b96175 |
| CALL_CONDOR | 0xbb5d2EB2D354D930899DaBad01e032C76CC3c28f |
| PUT_CONDOR | 0xbdAcC00Dc3F6e1928D9380c17684344e947aa3Ec |
| IRON_CONDOR | 0x494Cd61b866D076c45564e236D6Cb9e011a72978 |
| PHYSICAL_CALL | 0x07032ffb1df85eC006Be7c76249B9e6f39b60F32 |
| PHYSICAL_PUT | 0xAC5eCA7129909dE8c12e1a41102414B5a5f340AA |
| Asset | Address |
|---|---|
| ETH/USD | 0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70 |
| BTC/USD | 0x64c911996D3c6aC71f9b455B1E8E7266BcbD848F |
| SOL | 0x975043adBb80fc32276CbF9Bbcfd4A601a12462D |
| DOGE | 0x8422f3d3CAFf15Ca682939310d6A5e619AE08e57 |
| XRP | 0x9f0C1dD78C4CBdF5b9cf923a549A201EdC676D34 |
Updates are checked automatically at the start of every conversation (see First-Time Setup). The agent runs update.sh silently and only notifies the user if a new version is installed.
To manually check or force dependency updates:
bash scripts/update.sh
Optional flags:
REFRESH_WDK_DEPS=1 - Refresh dependencies from lockfileUPGRADE_WDK_DEPS=1 - Upgrade dependency versionsRESTART_WDK_RUNTIME=1 - Best-effort restart of WDK runtimeUpdates NEVER modify wallet secrets (.env, WDK_SEED).
Options use: {UNDERLYING}-{EXPIRY}-{STRIKE}-{TYPE}
Examples:
ETH-28MAR26-2500-P = ETH Put, $2500 strike, March 28 2026 expiryBTC-28MAR26-95000-C = BTC Call, $95000 strike, March 28 2026 expiry