# 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 <mark style="color:red;">`MarketFactory`</mark> functions as root markets (e.g. `createCategoricalMarket`), but you set <mark style="color:red;">`parentMarket`</mark> and <mark style="color:red;">`parentOutcome`</mark> in <mark style="color:red;">`CreateMarketParams`</mark>. Split, merge and redeem use the same <mark style="color:red;">`Router`</mark> (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 <mark style="color:red;">`ConditionalRouter.redeemConditionalToCollateral`</mark> 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.”

| Parameter       | Type    | Description                                                                                              |
| --------------- | ------- | -------------------------------------------------------------------------------------------------------- |
| `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 <mark style="color:red;">`Router`</mark> (or <mark style="color:red;">`GnosisRouter`</mark> / <mark style="color:red;">`MainnetRouter`</mark>) 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:

1. Approve the **parent’s wrapped outcome token** (for the outcome index the child is conditional on) to the Router.
2. 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 <mark style="color:red;">`ConditionalRouter.redeemConditionalToCollateral`</mark> (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

<mark style="color:red;">`ConditionalRouter`</mark> extends Router and adds:

```solidity
function redeemConditionalToCollateral(
    IERC20 collateralToken,
    Market market,
    uint256[] calldata outcomeIndexes,
    uint256[] calldata parentOutcomeIndexes,
    uint256[] calldata amounts
) public
```

* **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](/seer-documentation/developers/interact-with-seer/create-a-market.md), and set `parentMarket` and `parentOutcome`:

```typescript
import { getPublicClient, getWalletClient, SEER_CONTRACTS, ERC20_APPROVE_ABI, MARKET_ABI } from "./viem-setup";
import { gnosis } from "viem/chains"; // or mainnet, base, etc.

const chain = gnosis;
const publicClient = getPublicClient(chain);
const walletClient = getWalletClient(chain, process.env.PRIVATE_KEY! as `0x${string}`);
const addresses = SEER_CONTRACTS[chain.id];
const parentMarketAddress = "0x..."; // parent market address
const parentOutcomeIndex = 0;       // e.g. 0 = Yes

const params = createMarketParams({
  marketName: "If the war ends in 2024, will Russia withdraw all troops by end of 2025?",
  outcomes: ["Yes", "No"],
  parentMarket: parentMarketAddress,
  parentOutcome: BigInt(parentOutcomeIndex),
  category: "misc",
  openingTime: Math.floor(Date.now() / 1000) + 86400 * 30,
  minBond: 10000000000000000n,
  tokenNames: ["YES", "NO"],
});

const hash = await walletClient.writeContract({
  address: addresses.MarketFactory,
  abi: marketFactoryAbi,
  functionName: "createCategoricalMarket",
  args: [params],
});
const receipt = await publicClient.waitForTransactionReceipt({ hash });
// Parse NewMarket event to get conditional market address
const conditionalMarketAddress = "0x..."; // from event
```

#### 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:

```typescript
const parentMarket = await publicClient.readContract({
  address: conditionalMarketAddress,
  abi: MARKET_ABI,
  functionName: "parentMarket",
});
const parentOutcome = await publicClient.readContract({
  address: conditionalMarketAddress,
  abi: MARKET_ABI,
  functionName: "parentOutcome",
});

const [parentWrappedOutcomeToken] = await publicClient.readContract({
  address: parentMarket,
  abi: MARKET_ABI,
  functionName: "wrappedOutcome",
  args: [parentOutcome],
});
// parentWrappedOutcomeToken is the ERC20 to use as collateralToken in Router calls
```

#### 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.

```typescript
const routerAddress = addresses.Router ?? addresses.GnosisRouter ?? addresses.MainnetRouter;
const amount = 1000000000000000000n; // 1e18

await walletClient.writeContract({
  address: parentWrappedOutcomeToken,
  abi: ERC20_APPROVE_ABI,
  functionName: "approve",
  args: [routerAddress, amount],
});

const routerAbi = [
  {
    inputs: [
      { name: "collateralToken", type: "address" },
      { name: "market", type: "address" },
      { name: "amount", type: "uint256" },
    ],
    name: "splitPosition",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      { name: "collateralToken", type: "address" },
      { name: "market", type: "address" },
      { name: "amount", type: "uint256" },
    ],
    name: "mergePositions",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      { name: "collateralToken", type: "address" },
      { name: "market", type: "address" },
      { name: "outcomeIndexes", type: "uint256[]" },
      { name: "amounts", type: "uint256[]" },
    ],
    name: "redeemPositions",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
] as const;

const hash = await walletClient.writeContract({
  address: routerAddress,
  abi: routerAbi,
  functionName: "splitPosition",
  args: [parentWrappedOutcomeToken, conditionalMarketAddress, amount],
});
```

#### 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:

```typescript
// 1. Approve router to spend `amount` of each child outcome token.
const numOutcomes = await publicClient.readContract({
  address: conditionalMarketAddress,
  abi: MARKET_ABI,
  functionName: "numOutcomes",
  args: [],
});
for (let i = 0n; i < numOutcomes; i++) {
  const [childWrappedToken] = await publicClient.readContract({
    address: conditionalMarketAddress,
    abi: MARKET_ABI,
    functionName: "wrappedOutcome",
    args: [i],
  });
  await walletClient.writeContract({
    address: childWrappedToken,
    abi: ERC20_APPROVE_ABI,
    functionName: "approve",
    args: [routerAddress, amount],
  });
}

// 2. Merge
const hash = await walletClient.writeContract({
  address: routerAddress,
  abi: routerAbi,
  functionName: "mergePositions",
  args: [parentWrappedOutcomeToken, conditionalMarketAddress, amount],
});
```

#### 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](/seer-documentation/developers/interact-with-seer/split-merge-and-redeem.md)):

```typescript
const outcomeIndexes = [0n];   // e.g. first outcome won
const amounts = [500000000000000000n];

// 1. Approve router to spend each winning child outcome token.
for (let i = 0; i < outcomeIndexes.length; i++) {
  const [winningChildToken] = await publicClient.readContract({
    address: conditionalMarketAddress,
    abi: MARKET_ABI,
    functionName: "wrappedOutcome",
    args: [outcomeIndexes[i]],
  });
  await walletClient.writeContract({
    address: winningChildToken,
    abi: ERC20_APPROVE_ABI,
    functionName: "approve",
    args: [routerAddress, amounts[i]],
  });
}

// 2. Redeem
const hash = await walletClient.writeContract({
  address: routerAddress,
  abi: routerAbi,
  functionName: "redeemPositions",
  args: [parentWrappedOutcomeToken, conditionalMarketAddress, outcomeIndexes, amounts],
});
```

#### 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.

```typescript
const collateralToken = "0x..."; // base collateral (e.g. sDAI or sUSDS)

const conditionalRouterAbi = [
  {
    inputs: [
      { name: "collateralToken", type: "address" },
      { name: "market", type: "address" },
      { name: "outcomeIndexes", type: "uint256[]" },
      { name: "parentOutcomeIndexes", type: "uint256[]" },
      { name: "amounts", type: "uint256[]" },
    ],
    name: "redeemConditionalToCollateral",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
] as const;

const outcomeIndexes = [0n];
const parentOutcomeIndexes = [0n]; // parent outcome that won (e.g. Yes = 0)
const amounts = [500000000000000000n];

// 1. Approve ConditionalRouter to spend each winning child outcome token.
for (let i = 0; i < outcomeIndexes.length; i++) {
  const [winningChildToken] = await publicClient.readContract({
    address: conditionalMarketAddress,
    abi: MARKET_ABI,
    functionName: "wrappedOutcome",
    args: [outcomeIndexes[i]],
  });
  await walletClient.writeContract({
    address: winningChildToken,
    abi: ERC20_APPROVE_ABI,
    functionName: "approve",
    args: [addresses.ConditionalRouter, amounts[i]],
  });
}

// 2. Redeem to collateral
const hash = await walletClient.writeContract({
  address: addresses.ConditionalRouter,
  abi: conditionalRouterAbi,
  functionName: "redeemConditionalToCollateral",
  args: [
    collateralToken,
    conditionalMarketAddress,
    outcomeIndexes,
    parentOutcomeIndexes,
    amounts,
  ],
});
```

***

### Summary

| Step                            | What to use                                                                                                                                                                                                         |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **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). |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://seer-3.gitbook.io/seer-documentation/developers/interact-with-seer/conditional-market.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
