OddMaki
Protocol

Token Mechanics

How conditional tokens work in OddMaki — CTF, ERC-1155, split, merge, and NegRisk adapter.

Every market position on OddMaki is an ERC-1155 token managed by the Gnosis Conditional Tokens Framework (CTF). Understanding how tokens are created, traded, and redeemed is key to working with the protocol.

Conditional Token Framework (CTF)

The CTF is an external ERC-1155 contract that mints and burns outcome tokens based on conditions registered by an oracle. The OddMaki Diamond serves as both the oracle and the custody layer.

How it works:

  1. Prepare condition — Diamond registers a question with the CTF at market creation
  2. Split — Collateral is locked, YES and NO tokens are minted
  3. Merge — YES and NO tokens are burned, collateral is returned
  4. Report — Diamond reports the outcome to the CTF after resolution
  5. Redeem — Users claim collateral directly from the CTF

ERC-1155 Tokens

Each binary market produces exactly two tokens:

OutcomeIndexIndex Set
YES01 (bit 0)
NO12 (bit 1)

Token IDs are deterministic — derived from a three-step hash chain:

conditionId  = keccak256(oracle, questionId, 2)
collectionId = keccak256(parentCollectionId, conditionId, indexSet)
positionId   = uint256(keccak256(collateralToken, collectionId))

Position IDs are computed once at market creation and stored in MarketTradingData.positionIds[2].

Split and Merge

Split converts collateral into equal amounts of YES and NO tokens:

// Split 100 USDC into 100 YES + 100 NO
const tx = await client.trade.splitPosition(1n, parseAmount('100', 6));

Requires prior USDC approval to the Diamond. The caller receives equal amounts of both outcome tokens.

Merge is the inverse — burns equal amounts of YES and NO to return collateral:

// Merge 50 YES + 50 NO back into 50 USDC
const tx = await client.trade.mergePositions(1n, parseAmount('50', 6));

Requires CTF approval to the Diamond (ctf.setApprovalForAll(diamond, true)).

Split and merge also happen automatically during order matching: Mint-to-Fill splits when crossing buy orders cover 1.0 collateral, and Merge-to-Fill merges when crossing sell orders cost ≤ 1.0 collateral.

NegRisk Adapter

Market groups use a wrapped collateral layer so that position IDs are distinct from standalone markets. This enables NegRisk position conversion.

Conversion transforms NO positions across multiple group markets into YES positions in the complementary markets, plus collateral returned:

  • Input: NO tokens from N markets, amount each
  • Output: YES tokens for the remaining (M - N) markets + (N - 1) × amount collateral
// Convert NO on markets 0,1,2 in a 5-market group
const tx = await client.market.convertPositions({
  marketGroupId: 1n,
  indexSet: 0b111n,  // bits 0,1,2 = NO positions
  amount: parseAmount('100', 6),
});
// Receive: 2 YES tokens + 200 USDC

This keeps NegRisk pricing consistent — the sum of all YES probabilities in a group should equal 1.

Token Lifecycle

Market Creation → Condition prepared, position IDs registered

    Trading → Split/merge via orderbook (Mint-to-Fill, Merge-to-Fill)
       ↓         Users can also split/merge directly
    Resolution → Diamond reports payouts to CTF

   Redemption → Winners call CTF.redeemPositions() for collateral

After resolution, the payout vector determines value:

  • YES wins: [1, 0] — YES tokens redeem 1:1 for collateral
  • NO wins: [0, 1] — NO tokens redeem 1:1
  • Invalid: [1, 1] — both tokens split collateral equally

For market groups, cascade resolution automatically sets all siblings to NO when one market resolves YES.

What's Next