Vol-Arb Sentinel + Predict Surface Studio for DeepBook Predict on Sui Sui Overflow 2026 · DeepBook Predict track · solo build
Surge proves that DeepBook Predict's volatility surface is both sane and tradeable. It streams live OracleSVIUpdated events from Sui, fits a Stochastic Volatility Inspired (SVI) smile, cross-checks implied vols against Deribit and Polymarket, and fires predict::mint transactions whenever the spread justifies a Kelly-sized position — all while rendering the full surface in a live 3D dashboard.
Two artifacts share a single ingestion pipeline:
| Artifact | Description |
|---|---|
| Vol-Arb Sentinel | Keeper bot: subscribes to OracleSVIUpdated, reconstructs the SVI smile, scans strikes for edge vs. cross-venue, and submits predict::mint PTBs when edge exceeds the Kelly threshold |
| Predict Surface Studio | Next.js dashboard: live 3D react-three-fiber surface, cross-venue smile overlay, butterfly & calendar arb-free checks, trade ledger with Suiscan deep links |
Sui Testnet (OracleSVIUpdated + OraclePricesUpdated events)
│
▼
┌─────────────────────────────────────────────────────┐
│ Ingestion Service :9000 │
│ • Decodes on-chain events │
│ • Fetches cross-venue smiles (Deribit / Polymarket)│
│ • Maintains in-memory ring buffers │
│ – SVI ring: 1 024 entries │
│ – Prices ring: 8 192 entries │
│ • WebSocket fanout :3001 → Dashboard │
└────────────────┬────────────────────────────────────┘
│ shared ring buffers
┌────────┴─────────┐
▼ ▼
┌───────────────┐ ┌──────────────────┐
│ Keeper Bot │ │ Dashboard │
│ :4000 │ │ :3000 │
│ │ │ │
│ Edge scanner │ │ 3D SVI mesh │
│ Kelly sizer │ │ Smile overlay │
│ PTB executor │ │ Trade ledger │
│ JSONL ledger │ │ Kill-switch UI │
└───────────────┘ └──────────────────┘
Single entry point: pnpm start runs all three concurrently.
- Reconstructs the full SVI smile from each
OracleSVIUpdatedevent - Fetches external (Deribit primary, Polymarket fallback) smile at the matching expiry
- Scans strikes ±10% log-moneyness for maximum implied-vol edge
- Sizes trades via quarter-Kelly (full Kelly formula:
f* = p − (1−p)·m/(1−m)) - Computes digital probability
P(S_T > K) = N(d₂)via Black-Scholes - Fires
predict::mintProgrammable Transaction Block when|edge| > threshold - Kill-switch state machine — latches on feeder lag > 60 s, ≥3 consecutive errors, or manual override; must be explicitly reset
- Demo mode —
BOT_DEMO_MODE=truelowers edge threshold to ~0.5 vol points for walkthroughs - Leveraged mint (optional) — atomic 3-step PTB: deposit SUI → borrow dUSDC → predict::mint
- Live 3D SVI vol surface rendered with react-three-fiber / Three.js
- Cross-venue smile overlay — Deribit / Polymarket implied vols on the same canvas, spread region highlighted
- Arb-free checks — butterfly (Durrleman g(k) ≥ 0) and calendar (non-decreasing total variance) violations highlighted in real time
- Trade ledger — every trade with edge, mint cost, realized PnL on settlement, and Suiscan deep links
- Oracle feeder lag pill — live latency indicator; dashboard auto-dims stale data (> 30 s)
- Kill-switch status bar — shows ACTIVE / HALTED + halt reason
- Subscribes to Sui events via
SuiClient.subscribeEvent() - Decodes
OracleSVIUpdatedandOraclePricesUpdatedinto bigint-safe ring buffers - 30-second server-side cross-venue cache to avoid rate limiting
- FailoverFetcher auto-switches from primary to fallback on errors
- WebSocket fanout decoupled from HTTP health checks
.
├── packages/
│ └── core/ @surge/core
│ └── src/
│ ├── types.ts I64, SVIParams, OracleSVIUpdatedEvent …
│ ├── svi.ts SVI evaluation + smile sampling
│ ├── arb.ts Butterfly & calendar arb-free checks
│ ├── ptb.ts predict::mint / redeem / create_manager PTB builders
│ ├── bs.ts Black-Scholes (digital N(d2))
│ ├── config.ts RPC URLs, Predict package IDs
│ └── scaling.ts FLOAT_SCALING bigint ↔ number
├── apps/
│ ├── ingestion/ @surge/ingestion
│ │ └── src/
│ │ ├── index.ts Main loop + HTTP health server (:9000)
│ │ ├── oracleStream.ts Sui event subscription
│ │ ├── ringBuffer.ts Circular in-memory buffer
│ │ ├── crossVenue.ts Deribit / Polymarket fetchers + failover
│ │ ├── fanout.ts WebSocket broadcast to dashboard (:3001)
│ │ └── syntheticVenue.ts Fake smile for dev / demo
│ ├── keeper/ @surge/keeper
│ │ └── src/
│ │ ├── index.ts Decision loop
│ │ ├── edgeScanner.ts Strike scanning + edge computation
│ │ ├── sizing.ts Kelly sizing + digital probability
│ │ ├── killSwitch.ts State machine for trading halts
│ │ ├── ledger.ts Append-only JSONL trade / decision / kill records
│ │ ├── leveragedMint.ts Atomic 3-step PTB builder
│ │ └── httpServer.ts /health, /trades, /status (:4000)
│ └── dashboard/ @surge/dashboard
│ └── src/
│ ├── app/
│ │ └── page.tsx Root layout: status bar / 3D canvas / ledger
│ ├── components/
│ │ ├── SurfaceCanvas.tsx Three.js Canvas wrapper
│ │ ├── SurfaceMesh.tsx SVI mesh geometry + material
│ │ ├── OverlaySmile.tsx Cross-venue line plot
│ │ ├── TradeLedger.tsx Scrollable trade history
│ │ └── StatusBar.tsx Kill-switch status + lag pill
│ └── lib/
│ └── ingestionStore.ts WebSocket client to fanout
├── scripts/
│ ├── validate-schema.ts Dump & verify OracleSVIUpdated event shape
│ ├── bootstrap-manager.ts Create PredictManager + KeeperCap (run once)
│ ├── inspect-manager.ts Read manager object state
│ ├── check-balances.ts Wallet & object balance queries
│ ├── smoke-trade.ts Manual trade for smoke testing
│ ├── setup-margin.ts Create DeepBook Margin manager
│ ├── redeem-settled.ts Redeem settled binary positions
│ └── find-active-oracle.ts Query active oracles
├── docs/
│ ├── ARCHITECTURE.md
│ ├── DEMO_SCRIPT.md
│ └── SUBMISSION.md
├── .env.example
└── PROJECT_BRIEF.md
- Node.js 22+
- pnpm 9+
- A dedicated Sui wallet funded with SUI and dUSDC (testnet — see below)
pnpm installcp .env.example .env
# Edit .env — at minimum set BOT_PRIVATE_KEY (use a dedicated throwaway wallet, never a mainnet key)pnpm validate:schemaThis confirms that the OracleSVIUpdated event shape on testnet matches what the bot expects (critical-risk mitigation).
pnpm bot:bootstrap # creates PredictManager + KeeperCap on-chain
pnpm bot:info # prints bot wallet address and manager object ID
pnpm bot:balances # confirms dUSDC and SUI balancespnpm start # ingestion + keeper + dashboard (concurrent, coloured output)Or run services individually in watch mode during development:
pnpm dev:ingestion # :9000
pnpm dev:keeper # :4000
pnpm dev:dashboard # :3000pnpm start:headless # ingestion + keeper onlyAll settings are loaded from .env. A fully-annotated template is in .env.example.
| Variable | Default | Description |
|---|---|---|
SUI_NETWORK |
testnet |
testnet or mainnet |
PREDICT_PACKAGE_ID |
see below | Predict Move package |
PREDICT_OBJECT_ID |
see below | Predict shared object |
DUSDC_COIN_TYPE |
see below | dUSDC type tag |
| Variable | Default | Description |
|---|---|---|
BOT_EDGE_THRESHOLD_IV |
0.05 |
Minimum implied-vol edge to fire (5 vol points) |
BOT_KELLY_FRACTION |
0.25 |
Kelly scaling factor (quarter-Kelly) |
BOT_MAX_TRADE_NOTIONAL |
50000000 |
Max notional per trade in micro-dUSDC (50 dUSDC) |
BOT_MAX_TRADES_PER_SESSION |
10 |
Hard session cap |
BOT_COOLDOWN_MS |
60000 |
Min milliseconds between trades |
BOT_FEEDER_LAG_KILL_MS |
60000 |
SVI or price lag that trips the kill-switch |
BOT_DEMO_MODE |
false |
Lower threshold to ~0.5 vol pts for demos |
BOT_DEMO_EDGE_OVERRIDE |
0.005 |
Edge threshold in demo mode |
| Variable | Default | Description |
|---|---|---|
CROSSVENUE_PRIMARY |
deribit |
deribit, polymarket, or synthetic |
SYNTHETIC_BIAS_IV |
0.06 |
Bias applied in synthetic (dev/demo) mode |
| Variable | Default | Service |
|---|---|---|
PORT |
9000 |
Ingestion health check |
KEEPER_PORT |
4000 |
Keeper HTTP API |
FANOUT_PORT |
3001 |
WebSocket fanout |
DASHBOARD_PORT |
3000 |
Next.js dashboard |
| Command | Purpose |
|---|---|
pnpm start |
Run all services concurrently |
pnpm start:headless |
Run ingestion + keeper only |
pnpm dev:ingestion |
Watch mode — ingestion |
pnpm dev:keeper |
Watch mode — keeper |
pnpm dev:dashboard |
Next.js dev server |
pnpm validate:schema |
Dump & verify OracleSVIUpdated event shape |
pnpm bot:bootstrap |
Create PredictManager + KeeperCap on-chain |
pnpm bot:info |
Print bot wallet address + manager ID |
pnpm bot:balances |
Check wallet dUSDC & SUI balances |
pnpm bot:inspect |
Read manager object state |
pnpm smoke:trade |
Submit a manual test trade |
pnpm bot:setup-margin |
Create DeepBook Margin manager (leveraged mint) |
pnpm lint |
ESLint across workspace |
pnpm typecheck |
tsc --noEmit |
pnpm test |
Run test suite |
pnpm build |
Compile all packages |
Source of truth: MystenLabs/deepbookv3 — packages/predict
| Item | Value |
|---|---|
| Network | Sui testnet |
| Predict package | 0xf5ea2b3749c65d6e56507cc35388719aadb28f9cab873696a2f8687f5c785138 |
| Predict object | 0xc8736204d12f0a7277c86388a68bf8a194b0a14c5538ad13f22cbd8e2a38028a |
| Quote asset (dUSDC) | 0xe95040085976bfd54a1a07225cd46c8a2b4e8e2b6732f140a0fc49850ba73e1a::dusdc::DUSDC |
| Indexer | https://predict-server.testnet.mystenlabs.com |
Surge requires dUSDC (not official testnet USDC). Request testnet dUSDC at https://tally.so/r/Xx102L.
| Control | Detail |
|---|---|
| Kill-switch latch | Once tripped, the bot halts and must be explicitly reset; will not self-reset |
| Edge floor | No trade fires below BOT_EDGE_THRESHOLD_IV |
| Cooldown | Minimum 60 s between consecutive trades |
| Notional cap | Max 50 dUSDC per trade + 10 trades per session |
| Submission lock | Only one PTB in-flight; keeps Sui nonce ordering simple |
| Arb-free monitoring | Butterfly and calendar violations are highlighted in the dashboard; repeated violations can trip the kill-switch |
| Leveraged mint pre-flight | Collateral/borrow ratio must be ≥ 1.25 before the 3-step PTB fires |
| Layer | Technologies |
|---|---|
| Monorepo | pnpm workspaces, TypeScript 5.6, Node.js 22+ |
| Sui integration | @mysten/sui SDK v1.21.0 |
| Bot runtime | Node.js + tsx, in-memory ring buffers, JSONL ledger |
| Dashboard | Next.js 14.2, React 18, react-three-fiber 8.17, Three.js 0.169 |
| Networking | WebSocket fanout, HTTP servers |
| Cross-venue | Deribit REST (primary), Polymarket CLOB (fallback) |
| Math | SVI parameterization, Black-Scholes, Kelly criterion |
- Private keys are loaded from
.envonly..envis git-ignored — never commit it, even encrypted. - Use a dedicated throwaway wallet for
BOT_PRIVATE_KEY. Do not reuse mainnet keys. - All services are read-only until
BOT_PRIVATE_KEYis set and the keeper is started. - The leveraged mint path requires explicit opt-in via
BOT_LEVERAGE_ENABLED=true.
Live predict::mint transactions fired by the Vol-Arb Sentinel on Sui testnet:
Demo video (YouTube) — ≤5 min walkthrough of the full flow. See docs/DEMO_SCRIPT.md for the full narrative.
Apache-2.0
Surge exposes a real-time volatility data API designed to be consumed by downstream DeFi protocols — particularly options protocols requiring live implied volatility feeds for pricing and risk models.
GET /api/v1/iv-surface
Returns the current implied volatility surface across all active
DeepBook Predict markets. IV is extracted from live market prices
via Black-Scholes Newton-Raphson solve.
GET /api/v1/vol-regime
Returns the current volatility regime classification (LOW / HIGH / SPIKE)
with confidence score and reasoning. Designed to be consumed by keeper
layers (e.g. iv-publisher, stress-publisher) in options protocols.
An options protocol on Sui can query /api/v1/iv-surface to seed its
Black-Scholes stress grid with market-derived implied vols, rather than
using synthetic or hardcoded parameters.