OddMaki
Operations

Creating Markets

How to create binary markets and market groups on your venue — parameters, best practices, and on-chain mechanics.

Markets are created within a venue. You need your venue ID and USDC for the creation fee.

Creating a Binary Market

A binary market is a single YES/NO question. It goes live immediately on creation.

const tx = await client.market.createMarket({
  venueId: 1n,
  question: {
    title: 'Will BTC reach $100k by end of 2026?',
    description: 'Resolves YES if Bitcoin reaches $100,000 USD on any major exchange before January 1, 2027.',
  },
  outcomes: ['Yes', 'No'],
  tickSize: parseEther('0.01'),       // $0.01 price increments
  collateralToken: USDC_ADDRESS,
  additionalReward: 0n,              // no extra UMA reward
  liveness: 0n,                      // defaults to 2 hours
});

What happens on-chain:

  1. Validates parameters and access control
  2. Allocates a market ID (auto-incrementing from 1)
  3. Enriches the question data with market metadata
  4. Generates a deterministic questionId and conditionId
  5. Prepares the CTF condition and computes YES/NO position IDs
  6. Collects the market creation fee (50/50 protocol/venue split)
  7. Emits MarketCreated

Creating a Market Group

Market groups contain N mutually exclusive outcomes. The lifecycle is: create → add outcomes → activate.

// 1. Create the group
await client.market.createMarketGroup({
  venueId: 1n,
  question: 'Who will win the championship?',
  description: 'Resolves YES for the winning team.',
  collateralToken: USDC_ADDRESS,
  tickSize: parseEther('0.01'),
  additionalReward: 0n,
  liveness: 0n,
});

// 2. Add outcomes (each becomes a binary YES/NO market)
await client.market.addMarketToGroup({
  marketGroupId: 1n,
  marketName: 'Team A',
  marketQuestion: 'Will Team A win?',
});

await client.market.addMarketToGroup({
  marketGroupId: 1n,
  marketName: 'Team B',
  marketQuestion: 'Will Team B win?',
});

// 3. Optionally add placeholder slots for late additions
await client.market.addPlaceholderMarkets({
  marketGroupId: 1n,
  count: 3n,
});

// 4. Activate (locks totalMarkets, enables trading)
await client.market.activateMarketGroup({ marketGroupId: 1n });

Placeholders can be activated later with real names and questions:

await client.market.activatePlaceholder({
  marketGroupId: 1n,
  marketId: 5n,
  marketName: 'Team C',
  marketQuestion: 'Will Team C win?',
});

Writing Good Resolution Criteria

The description field is what UMA asserters and disputors use to determine the outcome. Be specific:

  • State the exact condition for YES vs NO
  • Include data sources (e.g., "any major exchange", "official results")
  • Include deadlines with timezone if applicable
  • Avoid ambiguous language

Market Parameters

ParameterDescriptionConstraints
venueIdWhich venue to create inMust exist and be active
question.titleThe market questionNon-empty
question.descriptionResolution criteriaUsed by UMA for disputes
outcomesOutcome labelsMust be ['Yes', 'No'] for binary
tickSizePrice incrementMust be > 0. Common: parseEther('0.01')
collateralTokenTrading collateralMust be UMA-whitelisted ERC-20
additionalRewardExtra UMA asserter rewardAdded to venue default. 0 is common
livenessUMA challenge periodMinimum 7200s (2 hours), values below are floored
Market creation feeCharged to creatorMinimum 5 USDC, set per venue, 50/50 split

On-Chain Mechanics

The creation fee is pulled from your wallet via transferFrom — approve USDC to the Diamond before creating.

For market groups:

  • Only the group creator can add markets and activate
  • Maximum 50 markets per group (including placeholders)
  • Minimum 2 markets required to activate
  • totalMarkets is locked at activation — used for NegRisk conversion math
  • Placeholders reserve position IDs at creation; only the question text changes on activation

What's Next