> ## 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:
1. **Splitting** USDCe into YES/NO tokens to have inventory to quote
2. **Merging** tokens back to USDCe to reduce exposure
3. **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)
```typescript theme={null}
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
```typescript theme={null}
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
```typescript theme={null}
// 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
```typescript theme={null}
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.
```typescript theme={null}
const NEG_RISK_ADAPTER = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296";
const NEG_RISK_CTF_EXCHANGE = "0xC5d563A36AE78145C45a50134d48A1215220f80a";
```
See [Negative Risk Overview](/developers/neg-risk/overview) for details.
## Inventory Strategies
### Pre-market Preparation
Before quoting a market:
1. Check market metadata via Gamma API
2. Split sufficient USDCe to cover expected quoting size
3. 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:
1. Cancel all open orders
2. Wait for resolution
3. Redeem winning tokens
4. Merge any remaining pairs
## Batch Operations
For efficiency, batch multiple operations:
```typescript theme={null}
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();
```
## Related Documentation
Conditional Token Framework basics
Detailed split documentation
Detailed merge documentation
Gasless transaction execution