Protocol
Architecture
Thassa markets settle through a proof-of-authority (PoA) oracle pipeline: the markets contract asks the Thassa hub a question, an authorized oracle node answers it against publicly bound sources, a PoA verifier checks the node’s signature onchain, and the hub calls the market back with the outcome. Nothing settles on an unverified answer, and every question is stored onchain in public.
The settlement pipeline
ThassaMarkets
all markets, one contract · oracle client
ThassaHub
oracle request hub · bids & updates
Oracle node (PoA fulfiller)
fetches bound sources · adjudicates · signs
ThassaPoAVerifier
owner-managed signer set · verifies signature
Hub callback → _updateOracle
(marketId, settled, direction) · status → SETTLED
Components
ThassaMarkets
One contract holds all markets — no per-market deployments, which keeps creation gas-free at the protocol level. It extends ThassaOracle, making it an oracle client of the hub: it places settlement bids and receives the hub’s callback. It also runs the entire order book — escrow, matching, fees, redemption.
ThassaHub
The oracle request hub. A settlement request is a hub bid placed via placeBidWithInputData, where inputData = abi.encode(marketId, settlementQuery). The hub holds the bid while the market is SETTLING, accepts a verified update, and invokes the markets contract’s callback. Replay protection comes from hub update digests.
ThassaPoAVerifier
The trust anchor. An owner-managed signer set (addSigner, removeSigner, isSigner, signerCount) verifies each update: the update’s fulfiller must be an authorized signer, and the signature — EIP-191 personal_sign over the hub’s ProofUpdateV2 digest — must recover to that exact fulfiller. Signer changes emit SignerAdded / SignerRemoved.
The oracle node
An offchain fulfiller run by Thassa. For each settlement bid it:
- Parses the structured settlement query from bid
inputData—{question, category, rule, sources}. - Fetches the bound sources itself (ESPN, NWS, news APIs, pricing APIs) — in the node process, before and separate from any LLM call.
- Adjudicates only from the fetched evidence — no open web search. For
majority-rule queries the node computes concurrence in code, one independent verdict per source. - Signs the response envelope echoing the
marketId, or produces no update (_fulfilled=false) when the outcome isn’t determinable yet — sources unavailable, no majority, event not concluded. The bid stays open and the node retries later.
The node’s settlement prompt is hardened against prompt injection: it never follows instructions embedded in a market question and returns strictly the expected shape tuple(marketId, settled, direction).
The callback
The hub delivers the verified update to the markets contract, whose _updateOracle decodes (marketId, settled, direction), requires the market to be SETTLING with settled == true, records the outcome (direction: true = YES), and flips status to SETTLED, emitting MarketSettled. Winners can then redeem $1 per share.
Around the contracts
- Relayer — batches EIP-712-signed orders into
placeOrdersBatchand pays gas. It only ever submits to allowlisted platform contracts and whitelisted methods, and validates every EIP-3009 authorization pays the markets contract before relaying. Never arbitrary calldata. - Indexer — subscribes to contract events (
OrderPlaced,OrderMatched,MarketSettled, …), maintains the read models the API serves, and pushes WebSocket deltas. - Settlement runner — collects the $0.05 settlement fee, calls
settleMarket, and watches the hub to flip statuses and notify.
Why PoA?