
Everything behind ChainStreet — how a market is defined, how the crowd prices it, how the oracle settles it, and how the money moves.
ChainStreet is a binary prediction market for stock-ticker price events. Every market asks one yes-or-no question about where a symbol trades by a deadline — and anyone can open one on any ticker the quote feed covers.
Positions are taken in ETH on Robinhood Chain. There is no order book and no market maker: each side of a market is a pool, and the split between pools is the price. When the deadline passes, an oracle reads the live quote and the contract pays the winning side.
4663.Four categories cover absolute price targets and relative moves. Percent categories measure against entry_price — the quote captured at the moment the market was created, stored so the baseline can never drift.
price_abovequote ≥ target_value
price_belowquote ≤ target_value
pct_gain(quote − entry_price) ÷ entry_price × 100 ≥ target_value
pct_loss(entry_price − quote) ÷ entry_price × 100 ≥ target_value
A market moves through four states:
Deadlines must sit at least one hour in the future — the contract rejects anything sooner so a market cannot be opened and settled in the same block window.
Pricing is pari-mutuel. Nobody quotes a spread; the two pools price each other. A side's implied probability is its share of the total pool:
implied_yes = yes_pool / (yes_pool + no_pool) implied_no = no_pool / (yes_pool + no_pool)
Two consequences worth internalising. First, your own stake moves the line — a large bet shifts the odds against itself, so the price you effectively get is worse than the price you saw. Second, the odds are a snapshot, not a lock: later bets on the other side change your payout ratio right up until the deadline. An empty market shows 50/50 because neither side has any weight yet.
A 2% protocol fee comes off every position as it enters. The remainder — your net stake — is what actually joins the pool and what your payout is computed from.
fee = stake × 2% net_stake = stake − fee payout = net_stake × total_pool ÷ winning_pool
Because the losing pool is included in total_pool, winners split the losers' stakes in proportion to their own. The more lopsided the market was against you, the larger your multiple.
Figures are illustrative — pool sizes shown are round numbers for clarity, and real pools include every other bettor's net stake.
At resolution the oracle pulls the current quote for the market's ticker and evaluates the category rule. Quotes are cached briefly to stay inside the data provider's rate limits, so a resolution reflects the quote at settlement time rather than a tick-exact price.
Resolution is triggered by an authenticated call. With no body the oracle decides the outcome itself; passing an explicit outcome overrides it, which exists for markets that need a human call or when the feed cannot answer:
# Oracle decides
curl -X POST /api/markets/<id>/resolve \
-H "x-api-key: $ORACLE_API_KEY"
# Manual override
curl -X POST /api/markets/<id>/resolve \
-H "x-api-key: $ORACLE_API_KEY" \
-H "content-type: application/json" \
-d '{"outcome": true}'Note the trust assumption: resolution and on-chain settlement are performed by the contract owner key, so this is an operator-attested oracle rather than a decentralised one.
Robinhood Chain is an EVM Layer 2 on the Arbitrum Orbit stack that posts data to Ethereum and uses ETH for gas. Standard tooling works unchanged — viem, wagmi, Foundry, Hardhat.
The public RPC endpoints are shared and rate-limited — fine for wallets and testing, but a dedicated provider is recommended for production traffic.
ChainStreetMarkets.sol holds every pool and pays out directly to bettors. Market IDs are the off-chain UUID packed into a bytes32. Claims follow checks-effects-interactions and are guarded against reentrancy; fees accumulate for the owner to pull rather than being pushed on every bet.
Constants: FEE_BPS = 200 (2%), MIN_BET = 0.001 ether, MIN_DURATION = 1 hours. Ownership transfer is two-step — the incoming owner must call acceptOwnership().
All routes are server-side. Endpoints marked x-api-key require the oracle key and are compared in constant time.
POST /api/markets
content-type: application/json
{
"title": "Will AAPL close above $200 by June 1?",
"description": "Resolves on the regular-session quote.",
"category": "price_above",
"ticker": "AAPL",
"target_value": 200,
"target_date": "2026-06-01T20:00:00.000Z"
}entry_price.