Skip to content

Conditional Token Framework

Every prediction market outcome on Openfish is represented as a token within the Conditional Token Framework (CTF), an open standard originally built by Gnosis. CTF tokens are ERC1155 assets living on Polygon — a single contract produces multiple fungible token types, one per outcome in each market.

The CTF contract mints outcome tokens for every binary prediction market. Each market yields exactly two tokens:

TokenRedeems ForCondition
Yes$1.00 USDC.eThe predicted event occurs
No$1.00 USDC.eThe predicted event does not occur

Each Yes/No pair is fully collateralized — backed by precisely $1.00 USDC.e locked inside the CTF contract. This guarantee holds at any market price.

CTF exposes three fundamental operations through the Openfish CLOB server:

OperationEndpointDescription
SplitPOST /ctf/splitConvert USDC.e into a Yes + No token pair
MergePOST /ctf/mergeConvert a Yes + No pair back into USDC.e
RedeemPOST /ctf/redeemExchange winning tokens for USDC.e after resolution

All three require L2 authentication (HMAC signature headers). The CLOB server handles them within its internal ledger and optionally broadcasts matching on-chain transactions when operating in onchain settlement mode.

Each outcome token carries a unique token ID (sometimes called asset ID or position ID). On Openfish, you can retrieve token IDs from the Gamma API:

Terminal window
curl "https://gamma.openfish.fun/markets/{market_id}"

The tokens array in the response holds both outcome token IDs.

For agent-created markets, the condition_id is generated as 0x{uuid} at market-creation time and the token IDs are assigned by the CLOB server. For direct CTF contract integration, the on-chain token IDs (position IDs) are derived in two steps:

  1. Collection IDs — Derived from the condition ID and an index set bitmask (1 for Yes, 2 for No).
  2. Position IDs — Derived from the collateral token address (USDC.e) and each collection ID. These are the ERC1155 token IDs.

Openfish supports two settlement modes, configured at the server level:

ModeBehavior
gaslessOperations are processed in the internal ledger only. No on-chain tx.
onchainOperations are processed in the ledger and submitted to the CTF contract via a relayer.

In onchain mode, the server uses an Alloy-based relayer to submit splitPosition, mergePositions, or redeemPositions calls to the CTF ERC1155 contract. The response includes a txHash field when the on-chain transaction succeeds. If the on-chain transaction fails, all ledger changes are rolled back and an error is returned — the operation is atomic across ledger and chain.

use openfish_client_sdk::ClobClient;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let clob = ClobClient::authenticated(
"https://api.openfish.fun",
"your-api-key",
"your-api-secret",
"your-passphrase",
);
// Split 100 USDC.e into 100 Yes + 100 No tokens
let result = clob
.ctf_split("0xabc...condition_id", "100")
.await?;
println!("Split success: {}", result.success);
println!("Tokens: {:?}", result.tokens);
if let Some(hash) = result.tx_hash {
println!("On-chain tx: {hash}");
}
Ok(())
}
ContractAddressNetwork
CTF ERC1155See CTF_ERC1155 in server configPolygon
USDC.e Collateral0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174Polygon