Building on Event Contracts
Event Contracts trade on the Somnia Markets on-chain order book. The developer surface is the @somnia-chain/markets-sdk (TypeScript) — the HTTP API covers spot only and has no event-contract endpoints.
With the SDK you can:
- Discover live markets and stream order books, fills, and candles in real time
- Place and cancel orders by symbol in human units (prices are Up probabilities in (0, 1))
- Mint and merge complete sets (1 USDso ⇄ 1 Up + 1 Down) for sell-side inventory
- Redeem winning positions after settlement
Install
The SDK is public on npm. Nothing else to configure:
npm install @somnia-chain/markets-sdk viem
Use version 0.25.0 or newer. Anything below 0.23.0 no longer reads markets at all: the indexer dropped the longOpenInterest column those versions still ask for, so loadMarkets and listBinaryMarkets both fail. The examples here are TypeScript, so run them with a TypeScript runner such as tsx (npx tsx bot.ts).
A minimal loop
Discover a market, gate on its live on-chain state, read the book, take a position:
import { SomniaMarkets, isBinaryMarket, type PlaceOrderResult } from "@somnia-chain/markets-sdk";
const exchange = new SomniaMarkets({ indexerUrl, chain, wsRpcUrl, addresses, privateKey });
const markets = Object.values(await exchange.loadMarkets(true));
for (const m of markets) {
// `info` is a union across market kinds; isBinaryMarket narrows it.
if (!m.active || !isBinaryMarket(m.info)) continue;
// The indexer lags: gate every write on the live on-chain status (1 = Trading).
// Row ids are plain strings; the client wants them hex-typed.
const onchain = await exchange.client.getMarketOnchain(m.info.marketId as `0x${string}`);
if (onchain.status !== 1) continue;
const upSymbol = m.outcomes?.[0]?.symbol; // e.g. "BTC-0-12AUG26-1600/USDso#YES"
if (!upSymbol) continue;
const book = await exchange.fetchOrderBook(upSymbol, 5);
const ask = book.asks[0]?.[0];
if (ask === undefined) continue; // no resting liquidity yet
// Cross the touch; IOC so the unfilled remainder never rests silently.
// From 0.23.0 a reverted write throws a decoded revert error, so let it
// propagate or catch it here rather than testing a status flag.
const order = await exchange.createOrder(upSymbol, "limit", "buy", 5, ask + 0.02, { timeInForce: "IOC" });
// The receipt rides on `info`; the order itself has no `receipt` field.
const { receipt } = order.info as PlaceOrderResult;
console.log("filled in", receipt.transactionHash);
}
The package README on npm covers the rest of the surface: realtime watches, the React hooks, and the raw trader tier. Types ship with the package, so an editor with TypeScript will autocomplete the whole API.
Go deeper: Recipes has a snippet for every action a bot needs, from resting a quote to redeeming after settlement; Market Structure & Lifecycle explains the contract family, the four fill paths, and escrow; Contracts & Addresses lists the deployed core.
There are no API rate limits: market data is the chain itself, and the public RPC endpoints are unthrottled. A trading system should snapshot once and stay current from on-chain events — the SDK's live watches do exactly this.
Two mechanics worth understanding before you build:
- One book, two sides. Up and Down trade on a single order book; a Down price is always 1 minus the Up price. Two opposite-side buyers can cross with no seller at all — the pool mints a fresh Up/Down pair from their combined collateral (so you can quote both sides with zero inventory).
- Markets die on schedule and respawn. Every window has a hard expiry; the venue rolls a successor automatically. Track the successor via the market list, and note that a settled market leaves the live list — winnings are claimed by scanning recently settled markets.
Read the Gotchas before sending a real order.