Creating Markets
How to create binary and multi-outcome prediction markets on-chain.
Binary market
A YES/NO question with a deadline and a resolver.
bytes32 conditionId = factory.createMarket(
"Will ETH hit $10k by Dec 2026?", // question
2, // outcomeSlotCount (2 = binary)
1767225600, // deadline (Unix timestamp)
resolverAddress // resolver contract
);That's it. The market is live. Anyone can trade on it immediately.
The resolver is chosen at creation time and cannot be changed. It determines how the market gets resolved - UMA, Kalshi, Polymarket, or any custom resolver.
What happens on-chain:
- A
questionIdis generated:keccak256(abi.encodePacked(question, marketCount)) conditionIdis derived:CTF.getConditionId(factory, questionId, 2)- CTF prepares the condition (creates the YES/NO token slots)
- Market is stored in the factory with its metadata
Parameters:
| Param | Type | Rules |
|---|---|---|
question | string | Any text. Becomes part of the questionId hash. |
outcomeSlotCount | uint256 | 2–255. Use 2 for binary. |
deadline | uint256 | Must be in the future. This is when the market can be resolved, not when trading stops. |
resolver | address | The resolver contract that will resolve this market. Cannot be changed after creation. |
Returns: conditionId (bytes32) - the unique identifier for this market. You need this for everything: placing orders, resolving, redeeming.
Multi-outcome market
"Who wins the election?" with multiple candidates. Uses the NegRiskAdapter.
string[] memory outcomes = new string[](3);
outcomes[0] = "Trump";
outcomes[1] = "Harris";
outcomes[2] = "DeSantis";
uint256 marketId = negRiskAdapter.createMultiOutcomeMarket(
"Who wins the 2028 election?", // question
outcomes, // outcome labels
1762041600, // deadline
resolverAddress // resolver contract
);This creates 3 independent binary markets:
- "Who wins the 2028 election? | Trump" - YES/NO
- "Who wins the 2028 election? | Harris" - YES/NO
- "Who wins the 2028 election? | DeSantis" - YES/NO
Each binary market has its own conditionId and trades independently on the OrderBook. All legs share the same resolver.
Get the conditionIds:
bytes32 trumpConditionId = negRiskAdapter.getOutcomeConditionId(marketId, 0);
bytes32 harrisConditionId = negRiskAdapter.getOutcomeConditionId(marketId, 1);
bytes32 desantisConditionId = negRiskAdapter.getOutcomeConditionId(marketId, 2);Limits:
- 2–64 outcomes
- No duplicate labels
- No empty labels
- Question max 1024 bytes
Reading market data
// Get market details
(
bytes32 questionId,
uint64 deadline,
uint8 outcomeSlotCount,
bool resolved,
address creator,
address resolver
) = factory.markets(conditionId);
// Check if market is actively trading
bool trading = factory.isTrading(conditionId);
// Check if market can be resolved (deadline passed, not yet resolved)
bool resolvable = factory.isResolvable(conditionId);