6.6 KiB
Documentation Index
Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt Use this file to discover all available pages before exploring further.
Inventory Management
Split, merge, and redeem outcome tokens for market making
Overview
Market makers need to manage their inventory of outcome tokens. This involves:
- Splitting USDCe into YES/NO tokens to have inventory to quote
- Merging tokens back to USDCe to reduce exposure
- Redeeming winning tokens after market resolution
All these operations use the Conditional Token Framework (CTF) contract, typically via the Relayer Client for gasless execution.
These examples assume you have initialized a RelayClient. See [Setup](/developers/market-makers/setup) for client initialization.Splitting USDCe into Tokens
Split 1 USDCe into 1 YES + 1 NO token. This creates inventory for quoting both sides.
Via Relayer Client (Recommended)
import { ethers } from "ethers";
import { Interface } from "ethers/lib/utils";
import { RelayClient, Transaction } from "@polymarket/builder-relayer-client";
const CTF_ADDRESS = "0x4d97dcd97ec945f40cf65f87097ace5ea0476045";
const USDCe_ADDRESS = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const ctfInterface = new Interface([
"function splitPosition(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] partition, uint amount)"
]);
// Split $1000 USDCe into YES/NO tokens
const amount = ethers.utils.parseUnits("1000", 6); // USDCe has 6 decimals
const splitTx: Transaction = {
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("splitPosition", [
USDCe_ADDRESS, // collateralToken
ethers.constants.HashZero, // parentCollectionId (null for Polymarket)
conditionId, // conditionId from market
[1, 2], // partition: [YES, NO]
amount
]),
value: "0"
};
const response = await client.execute([splitTx], "Split USDCe into tokens");
const result = await response.wait();
console.log("Split completed:", result?.transactionHash);
Result
After splitting 1000 USDCe:
- Receive 1000 YES tokens
- Receive 1000 NO tokens
- USDCe balance decreases by 1000
Merging Tokens to USDCe
Merge equal amounts of YES + NO tokens back into USDCe. Useful for:
- Reducing inventory
- Exiting a market
- Converting profits to USDCe
Via Relayer Client
const ctfInterface = new Interface([
"function mergePositions(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] partition, uint amount)"
]);
// Merge 500 YES + 500 NO back to 500 USDCe
const amount = ethers.utils.parseUnits("500", 6);
const mergeTx: Transaction = {
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("mergePositions", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionId,
[1, 2],
amount
]),
value: "0"
};
const response = await client.execute([mergeTx], "Merge tokens to USDCe");
await response.wait();
Result
After merging 500 of each:
- YES tokens decrease by 500
- NO tokens decrease by 500
- USDCe balance increases by 500
Redeeming After Resolution
After a market resolves, redeem winning tokens for USDCe.
Check Resolution Status
// Via CLOB API
const market = await clobClient.getMarket(conditionId);
if (market.closed) {
// Market is resolved
const winningToken = market.tokens.find(t => t.winner);
console.log("Winning outcome:", winningToken?.outcome);
}
Redeem Winning Tokens
const ctfInterface = new Interface([
"function redeemPositions(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] indexSets)"
]);
const redeemTx: Transaction = {
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("redeemPositions", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionId,
[1, 2] // Redeem both YES and NO (only winners pay out)
]),
value: "0"
};
const response = await client.execute([redeemTx], "Redeem winning tokens");
await response.wait();
Payout
- If YES wins: Each YES token redeems for $1 USDCe
- If NO wins: Each NO token redeems for $1 USDCe
- Losing tokens are worthless (redeem for $0)
Negative Risk Markets
Multi-outcome markets use the Negative Risk CTF Exchange. The split/merge process is similar but uses different contract addresses.
const NEG_RISK_ADAPTER = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296";
const NEG_RISK_CTF_EXCHANGE = "0xC5d563A36AE78145C45a50134d48A1215220f80a";
See Negative Risk Overview for details.
Inventory Strategies
Pre-market Preparation
Before quoting a market:
- Check market metadata via Gamma API
- Split sufficient USDCe to cover expected quoting size
- Set token approvals if not already done
During Trading
Monitor inventory and adjust:
- Skew quotes when inventory is imbalanced
- Merge excess tokens to free up capital
- Split more when inventory runs low
Post-Resolution
After market closes:
- Cancel all open orders
- Wait for resolution
- Redeem winning tokens
- Merge any remaining pairs
Batch Operations
For efficiency, batch multiple operations:
const transactions: Transaction[] = [
// Split on Market A
{
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("splitPosition", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionIdA,
[1, 2],
ethers.utils.parseUnits("1000", 6)
]),
value: "0"
},
// Split on Market B
{
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("splitPosition", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionIdB,
[1, 2],
ethers.utils.parseUnits("1000", 6)
]),
value: "0"
}
];
const response = await client.execute(transactions, "Batch inventory setup");
await response.wait();