Polymarket outcome tokens are represented using the Gnosis Conditional Tokens Framework’s ERC1155 tokens.
Outcome tokens are derived from a shared conditionId
unique indexSets
and a reference to the underlying ERC20 collateral token.
Full outcome sets can be created from one unit of collateral in an operation called “splitting”.
Full outcome sets can be exchanged for the underlying unit of collateral in an operation called “merging”.
All outcomes on Polymarket are tokenized and exchanged non-custodially and atomically via the Polygon network. In this brief article, we detail the outcome token primitive that underlies all Polymarket markets with specific focus on the binary case.
Binary outcomes (ie “YES” and “NO”) on Polymarket are represented using Gnosis’ Conditional Token Framework (CTF). They are distinct ERC1155 tokens related to a parent condition and backed by some collateral. More technically, the binary outcome tokens are referred to as “positionIds” in Gnosis’s documentation. “PositionIds” are derived from a collateral token and distinct “collectionIds”. “CollectionIds” are derived from a “parentCollectionId”, (always bytes32(0) in our case) a “conditionId”, and a unique “indexSet”. The “indexSet” is a 256 bit array denoting which outcome slots are in an outcome collection; it must be a nonempty proper subset of a condition’s outcome slots. In the binary case, which we are interested in, there are two “indexSets”, one for the first outcome and one for the second. The first outcome’s “indexSet” is 0b01 == 1 and the second’s is 0b10 == 2. The parent “conditionId” (shared by both “collectionIds” and therefore “positionIds”) is derived from a “questionId” (an IPFS hash of market details), an “oracle” address (the UMA adapter V2) and an “outcomeSlotCount” (always 2 in the binary case). Below we summarize the steps for calculating “positionIds”.
Get the conditionId
Function:
getConditionId(oracle, questionId, outcomeSlotCount
Inputs:
oracle
: address - UMA adapter V2
questionId
: bytes32 - an IPFS hash of market details
outcomeSlotCount
: uint - 2 for binary markets
Get the two collectionId
s
Function:
getCollectionId(parentCollectionId, conditionId, indexSet)
Inputs:
parentCollectionId
: bytes32 - bytes32(0)
conditionId
: bytes32 - the conditionId
derived from (1)
indexSet
: uint - 1 (0b01) for the first and 2 (0b10) for the second.
Get the two positionId
s
Function:
getPositionId(collateralToken, collectionId)
Inputs:
collateralToken
: IERC20 - address of ERC20 token collateral (USDC)
collectionId
: bytes32 - the two collectionId
s derived from (3)
See this gist for typescript implementations of the above functions which mirror the solidity function implementations here.
Leveraging the relations above, specifically “conditionIds” → “positionIds” the Gnosis CTF contract allows for “splitting” and “merging” full outcome sets. This means, for prepared conditions (markets), any user can, at any time, split one unit of collateral (USDC) for 1 of each binary outcome token and can, at any time, merge one of each outcome token into one unit of collateral. This means in correctly structured marketplace, the market price of these tokens should always be somewhere between (0, 1) unit of collateral and should sum to 1.