Skip to main content

What are split, merge, and convert?

Polymarket positions are ERC-1155 tokens representing outcomes. Three on-chain operations let you manage them directly: Split — Turn USDC into YES + NO tokens for a market. You put in 100andget100YESshares+100NOshares.Onesidewillbeworth100 and get 100 YES shares + 100 NO shares. One side will be worth 1 at resolution, the other $0. Merge — The reverse. Put YES + NO tokens back together and get USDC. 100 YES + 100 NO = $100 USDC returned. Convert — Rebalance positions across outcomes in a multi-outcome market (neg-risk only). If you hold NO tokens on certain outcomes, convert them into USDC plus YES tokens on the remaining outcomes.

When to use each

OperationUse case
SplitMint new outcome tokens without going through the orderbook. Useful for market making or taking positions on illiquid markets.
MergeExit positions without selling on the orderbook. Redeem paired YES+NO tokens for USDC at any time.
ConvertRebalance across outcomes in multi-outcome markets (e.g. “Who will win the World Cup?”). Swap your NO exposure on some outcomes into YES exposure on others.

TypeScript (gasless)

The TypeScript SDK executes these operations gaslessly through the Polymarket relayer. No MATIC/POL needed.
npm install polynode-sdk@latest

Split

import { PolyNodeTrader } from 'polynode-sdk';

const trader = new PolyNodeTrader({ polynodeKey: 'pn_live_...' });
await trader.ensureReady('0xYOUR_PRIVATE_KEY');

// Split $100 into YES + NO tokens
const result = await trader.split({
  conditionId: '0x895e01db...', // from market data
  amount: 100,                   // $100 USDC
});

console.log(result.txHash); // on-chain transaction hash

Merge

// Merge YES + NO tokens back into $50 USDC
const result = await trader.merge({
  conditionId: '0x895e01db...',
  amount: 50,
});

Convert

Convert is only available on neg-risk multi-outcome markets (e.g. “Republican Presidential Nominee” with 36 outcomes).
// Convert NO positions on outcomes 0 and 1 ($100 each)
const result = await trader.convert({
  marketId: '0xc7d902c4...', // negRiskMarketID from market data
  outcomeIndices: [0, 1],     // which outcomes to convert
  amount: 100,                // $100 per outcome
});
What happens:
  • Your NO tokens on outcomes 0 and 1 are burned
  • You receive (number of outcomes - 1) x amount in USDC (here: $100)
  • You receive YES tokens on all other outcomes (here: outcomes 2 through 35)
The outcomeIndices correspond to the position of each outcome in the market. Index 0 is the first outcome, index 1 is the second, etc. You can find these by looking at the questionID field in market data — the last byte of each questionID is the outcome index.

Rust (transaction builder)

The Rust SDK builds transactions that you submit via your own provider or the Polymarket relayer.
use polynode::trading::position_management::*;

// Build a split transaction
let tx = build_split_txn(
    "0x895e01db...", // conditionId
    100.0,            // $100
    true,             // neg_risk
);

// tx.to = contract address
// tx.data = ABI-encoded calldata
// Submit via your provider or the Polymarket relayer
// Build a convert transaction
let tx = build_convert_txn(
    "0xc7d902c4...", // marketId
    &[0, 1],          // outcome indices
    100.0,             // $100 per outcome
);

Python (transaction builder)

from polynode.trading.position_management import build_split_txn, build_convert_txn

# Build a split transaction
tx = build_split_txn("0x895e01db...", 100.0, neg_risk=True)
# tx.to, tx.data, tx.value — submit via your provider

# Build a convert transaction
tx = build_convert_txn("0xc7d902c4...", [0, 1], 100.0)

Finding market IDs

To use these operations, you need the right identifiers from market data:
FieldWhere to find itUsed by
conditionIdMarket data from /v1/events/search or Gamma APIsplit(), merge()
negRiskMarketIDMarket data (only on neg-risk markets)convert()
Outcome indexLast byte of each outcome’s questionIDconvert() outcomeIndices
// Example: finding IDs for a market
import { PolyNode } from 'polynode-sdk';
const pn = new PolyNode({ apiKey: 'pn_live_...' });

const results = await pn.searchEvents('Republican nominee', { limit: 1 });
const market = results.events[0].markets[0];
console.log(market.conditionId);       // for split/merge
console.log(market.negRiskMarketID);   // for convert

Neg-risk vs standard markets

Standard marketsNeg-risk markets
Outcomes2 (binary YES/NO)Many (e.g. 36 candidates)
Split/MergeVia CTF contractVia NegRiskAdapter
ConvertNot availableAvailable
Auto-detectionTypeScript SDK handles thisTypeScript SDK handles this
The TypeScript SDK auto-detects the market type and routes to the correct contract. Rust and Python default to neg-risk (most multi-outcome markets). Pass neg_risk=False for standard binary markets.
Convert operations are gasless in the TypeScript SDK. Rust and Python SDKs return pre-built transactions — submit them via the Polymarket relayer or your own provider.