Contracts
Two deployed contracts of our own, on Somnia Shannon testnet (chain 50312), plus two libraries (RiskGate and AgentToolLib) compiled into the Trader. Everything else is the venue’s or the platform’s.
What we deployed
| Contract | Address |
|---|---|
| BicameralFactory Clones, on-chain registry, and the starter-fuel treasury. | 0xF833ac09eF6666e3273a22529CC6cBaa78c9399c |
| BicameralTrader (implementation) The agent. Every deployed agent is a clone of exactly this. | 0x51abfCcf8D419BdA7464a666506C8Aa8D6cFB733 |
The pieces
BicameralTrader
The agent itself. Holds its own collateral and its own inference fuel, stores the strategy as plain text, and runs the loop: read the book, ask the LLM, gate the answer, place the order, redeem at settlement.
Three of its functions are permissionless by design — openWindow, expirePending and settleAndRedeem. Anyone can call them and the agent behaves identically, which is what makes the keeper powerless.
RiskGate
A pure library. Takes a model verdict and a live market snapshot, returns either an order or a numbered refusal. No model input reaches its own bounds.
AgentToolLib
The adapter that didn’t exist: Somnia Agents on one side, DreamDEX Event Contracts on the other. It renders pool state into a prompt, defines the closed verdict vocabulary, parses answers back, and handles the venue’s encoding — 1e6 probability prices, nanosecond expiries, tick and lot grids.
BicameralFactory
Deploys each agent as an EIP-1167 minimal proxy of one immutable implementation, so every agent on the board provably runs identical code and only the prompt differs. That is what makes comparing their records meaningful.
It is also the registry the site and keeper read from, and it holds the treasury that sponsors a new agent’s first decisions.
The legacy factories
The Floor doesn’t read only one registry. Later deployments created new factories, and the site’s data engine scans a KNOWN_FACTORIES list, so agents from earlier factories (including a few seeded before the current treasury) still appear in the roster. Same immutable implementation, same mechanics — only the registry they were cloned from differs. That’s why the status strip’s agent count and the roster can both exceed the current factory’s own agentCount().
Registering a market is permissionless — and safe
Nothing is taken on trust from the caller. registerMarket reads the pool, collateral, operator id and venue id from the venue’s own BinaryMarketsModule.markets(marketId) and rejects anything that disagrees. A caller can only ask the factory to mirror a market the venue already created — they cannot invent one, and cannot point an agent at a pool of their own.
This also solves a separate problem: MarketCreated carries no venue id and no operator id, and redemption needs both. The module registry is the only source.
The venue and platform
Deployed via CREATE3, so these addresses are identical on testnet and mainnet. Read from the SDK’s own address book rather than written down in our source.
| Contract | Address |
|---|---|
| BinaryMarketsModule | 0x3ecC694Cef705358864a646142ac17A90E29e388 |
| MarketsCore | 0x2802504314685D89bF6C992CA5a8e7cC78bc0294 |
| BinarySettlement | 0xbF4a49e0Dfd092e5FBE8E5761064C49533e6Ed23 |
| OutcomeToken6909 | 0xB52c5934113Af5c0Bb20eb3C72290C8215f755b9 |
| OracleHub | 0xe40db387cC98601Dd11bd634fF2f3AD5686dE32b |
| SomniaAgents platform | 0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776 |
| tUSDC collateral (6 decimals) | 0x70a86D8842FB63C4Ad2b7cdddF530eBf1BB25d8E |
decimals(), never from a literal.