Conditional market
A conditional market is a market that depends on a specific outcome of an existing (parent) market. The child marketβs positions are backed by the parentβs outcome token, not by the chainβs base collateral. For example: βWill Russia withdraw all troops from Ukrainian territory by end of 2025?β conditional on the parent βWill the war in Ukraine end in 2024?β resolving to Yes (outcome index 0).
You create conditional markets with the same MarketFactory functions as root markets (e.g. createCategoricalMarket), but you set parentMarket and parentOutcome in CreateMarketParams. Split, merge and redeem use the same Router (or chain-specific router) with the parentβs outcome token as the collateral token for the child market. Redeeming a resolved conditional market returns parent outcome tokens; to get base collateral in one go you can use ConditionalRouter.redeemConditionalToCollateral when the parent is a root market.
Creating a conditional market
Use any of the four market-creation functions on the MarketFactory and pass a parent market address and parent outcome index in the params. The child market is tied to βparent resolves to this outcome.β
parentMarket
address
Parent market contract address. Use address(0) for a root (non-conditional) market.
parentOutcome
uint256
Index of the parent outcome this market is conditional on (e.g. 0 = Yes, 1 = No in a binary market).
Split, merge and redeem
The same Router (or GnosisRouter / MainnetRouter) is used. The important difference is the collateral token:
Root market: collateral token = base collateral (e.g. sDAI or sUSDS, or the yield-bearing ERC20 you use on that chain).
Conditional market: collateral token = parentβs wrapped outcome token (the ERC20 for the parent outcome at index
parentOutcome).
So for a conditional market you do not use splitFromBase (Gnosis) or splitFromDai (Mainnet); you use splitPosition(collateralToken, market, amount) where collateralToken is the parent outcome ERC20.
Split
You must hold enough parent outcome tokens (from splitting or trading the parent market). Then:
Approve the parentβs wrapped outcome token (for the outcome index the child is conditional on) to the Router.
Call
router.splitPosition(parentWrappedOutcomeToken, conditionalMarket, amount).
You receive a full set of child outcome tokens (one ERC20 per outcome).
Merge
Hold a full set of child outcome tokens (equal amount of each outcome; e.g. 50 of outcome A and 50 of outcome B). Call:
router.mergePositions(parentWrappedOutcomeToken, conditionalMarket, amount).
You receive parent outcome tokens back.
Redeem (after child market is resolved)
Call router.redeemPositions(parentWrappedOutcomeToken, conditionalMarket, outcomeIndexes, amounts) with the winning child outcome index(es) and amounts. You receive parent outcome tokens (not base collateral). To get base collateral you must either:
Redeem the parent market separately (if the parent is resolved), or
Use
ConditionalRouter.redeemConditionalToCollateral(see below), which redeems child winning positions and then redeems the resulting parent outcome to collateral in one tx. The parent must be a root market (not conditional).
ConditionalRouter: redeem to collateral in one call
ConditionalRouter extends Router and adds:
outcomeIndexes / amounts: winning child outcome(s) to redeem.
parentOutcomeIndexes: which parent outcome(s) to redeem when converting the received parent tokens to collateral (e.g.
[0]if the parent resolved to outcome 0).
The parent market must be a root market (not conditional). The function redeems the child positions and then the parent outcome tokens, and sends collateral to the user.
Nested conditional markets
The framework supports multiple levels: a market can be conditional on another conditional market. Interact with each level the same way (collateral token for a child is always the parentβs wrapped outcome token).
If the parent resolves to an outcome different from the one the child is conditional on, the child market (and any deeper nesting) becomes obsolete: no one can redeem that branch for value.
Viem examples
We use the Viem setup: getPublicClient(chain) and getWalletClient(chain, process.env.PRIVATE_KEY). Addresses come from SEER_CONTRACTS[chain.id]. You also need the MarketFactory and Router (or GnosisRouter/MainnetRouter) ABIs, and a parent market already created. The parent can be root or conditional.
1. Create a conditional categorical market
Use the same createMarketParams helper and MarketFactory ABI as in Create a market, and set parentMarket and parentOutcome:
2. Get parent wrapped outcome token (for split/merge/redeem)
The βcollateralβ token for the conditional market in Router calls is the parentβs wrapped outcome ERC20. You can read it from the child market (if the contract exposes it) or from the parent:
3. Split on a conditional market
Approve the parent outcome token to the Router, then call splitPosition with that token and the conditional market. Use addresses.Router (Optimism/Base), addresses.GnosisRouter (Gnosis), or addresses.MainnetRouter (Ethereum) as appropriate for your chain.
4. Merge on a conditional market
You need a full set of child outcome tokens (equal amount of each outcome). Same Router and βcollateralβ token (parent wrapped outcome). Approve the router to spend amount of each child outcome token before calling merge:
5. Redeem (child resolved) β parent outcome tokens
After the child market is resolved, redeem winning child outcome(s). You receive parent outcome tokens. Approve the router to spend each winning child outcome token for the corresponding amount before calling redeem. Use a Router ABI that includes redeemPositions(collateralToken, market, outcomeIndexes, amounts) (see Split, merge and redeem):
6. Redeem to base collateral in one tx (ConditionalRouter)
If the parent is a root market and is already resolved, you can use ConditionalRouter to redeem child winning positions and get collateral in one call. Use addresses.ConditionalRouter. Approve the ConditionalRouter to spend each winning child outcome token for the corresponding amount before calling.
Summary
Create
MarketFactory (e.g. createCategoricalMarket) with parentMarket and parentOutcome in params.
Collateral token for Router
Parentβs wrapped outcome token (read via parentβs wrappedOutcome(parentOutcome) or childβs parent info).
Split
Hold parent outcome tokens β approve parent wrapped token β router.splitPosition(parentWrappedToken, conditionalMarket, amount).
Merge
Hold full set of child outcome tokens (equal amount of each) β router.mergePositions(parentWrappedToken, conditionalMarket, amount) β receive parent outcome tokens.
Redeem
After child resolved β router.redeemPositions(...) β receive parent outcome tokens; or use ConditionalRouter.redeemConditionalToCollateral to get base collateral in one tx (parent must be root and resolved).
Last updated