How a decision happens
One loop, five on-chain steps, no off-chain decision anywhere in it. Every step emits an event, which is why the whole record can be rebuilt from logs by anyone.
1 · Someone pokes the agent
openWindow(marketId) is permissionless. A keeper calls it every cycle, but the keeper holds no authority: it cannot trade, cannot move collateral, and cannot change a strategy. Anyone can call it — including you — and the agent behaves identically.
That is what “no server makes a decision” means precisely. There is a keeper process; it just has nothing to decide.
One agent trades a given market at most once per reevaluation interval — the time between openWindow calls on the same market. The reference roster runs reevaluation every 15 minutes, and the factory’s default is 15 minutes too, so a matched window is checked roughly on that cadence rather than on every block.
2 · The contract reads the live book
Before asking anything, the contract reads the current order book, the tick and lot grid, and the market’s own expiry — all on-chain, from the pool itself. It refuses immediately if the market is finalized or too close to expiry.
It then renders that state into a compact prompt. Deliberately numeric: the venue’s own question text is documented as unstable across releases, so nothing here parses prose. The model sees prices, depth and time.
up_bids=[0.877@200000000,0.869@330000000,0.863@460000000] up_asks=[0.900@200000000,0.908@330000000,0.918@460000000] mid_up=0.888 spread=0.023 seconds_to_expiry=1695 (prices are probability that UP wins, 0..1)
That is the real prompt body from the first live decision, taken from the WindowOpened event.
3 · Validators run the model and must agree
The contract calls Somnia’s LLM Inference agent with the user’s strategy, the market state, and a closed set of allowed answers:
BUY_UP · BUY_DOWN · ABSTAIN
A subcommittee of three validators each run the model independently. The answer is accepted once at least two of three agree — a threshold, not unanimity. You can see this on the board: a decision reads 2/3, not 3/3. The result is delivered back to the contract in handleResponse, which checks that the caller really is the agent platform and that the request is one it actually made.
An unreadable answer is published, not discarded — it emits VerdictUnparseable. The inference was already paid for; a decision that vanishes from the record would be worse than one recorded as unreadable.
4 · The gate decides whether that answer becomes an order
The verdict goes through the risk gate: pure Solidity, with bounds fixed at deploy that no model output can change. The gate re-reads the book (state moves between the question and the answer) and computes the price and size itself.
If it refuses, that refusal is emitted and shown publicly. If it passes, the same transaction places the order on the DreamDEX pool.
5 · Settlement
After expiry, settleAndRedeem(marketId) — also permissionless — claims the winning outcome tokens back to collateral. Voided markets pay both sides at 0.5, so it redeems both rather than stranding half the position.
What it looks like on-chain
The first live decision, in nine blocks, start to finish. These are the actual events — note the verdict shows 3 of 3 because all three validators happened to agree that run; the accept threshold is two.
| Event | What it recorded |
|---|---|
WindowOpened | book snapshot above, request id, 60s deadline |
VerdictReceived | 3 of 3 validators agreed → BUY_DOWN |
GateDecision | reason 0 (PASS) → price 0.880, size 5 |
OrderPlaced | real order on the DreamDEX pool |
Fueled | 0.0248 STT rebated automatically by the platform |
The strategy was “fade the crowd: if Up is above 0.80, buy Down.” The book showed Up asks at 0.900–0.918. It bought Down. The reasoning holds up against the input.