Skip to main content

Overview

The CTFExchange contract is the core binary limit order exchange for Polymarket. It implements comprehensive trading logic for Conditional Token Framework (CTF) assets through a modular architecture of inherited mixins. Contract: CTFExchange
Inherits: BaseExchange, Auth, Assets, Fees, Pausable, AssetOperations, Hashing, NonceManager, Registry, Signatures, Trading

Constructor

constructor(
    address _collateral,
    address _ctf,
    address _proxyFactory,
    address _safeFactory
)
Initializes the CTFExchange contract with required addresses for collateral, conditional tokens, and wallet factories.
_collateral
address
The ERC20 collateral token address (USDC)
_ctf
address
The ERC1155 Conditional Token Framework contract address
_proxyFactory
address
The Polymarket proxy wallet factory address
_safeFactory
address
The Gnosis Safe factory contract address

Trading Functions

fillOrder

function fillOrder(Order memory order, uint256 fillAmount) external
Fills an order with the caller as the taker.
order
Order
The order to be filled
fillAmount
uint256
The amount to be filled, always in terms of the maker amount
Modifiers: nonReentrant, onlyOperator, notPaused Requirements:
  • Caller must be an authorized operator
  • Trading must not be paused
  • Order must be valid and not expired
  • Order signature must be valid
  • Order must not be filled or cancelled

fillOrders

function fillOrders(
    Order[] memory orders,
    uint256[] memory fillAmounts
) external
Fills multiple orders in a single transaction.
orders
Order[]
Array of orders to be filled
fillAmounts
uint256[]
Array of amounts to be filled for each order, in terms of maker amounts
Modifiers: nonReentrant, onlyOperator, notPaused Requirements:
  • Caller must be an authorized operator
  • Trading must not be paused
  • All orders must be valid

matchOrders

function matchOrders(
    Order memory takerOrder,
    Order[] memory makerOrders,
    uint256 takerFillAmount,
    uint256[] memory makerFillAmounts
) external
Matches a taker order against multiple maker orders.
takerOrder
Order
The active taker order to be matched
makerOrders
Order[]
Array of passive maker orders to match against
takerFillAmount
uint256
Amount to fill on the taker order, in terms of maker amount
makerFillAmounts
uint256[]
Array of amounts to fill on each maker order, in terms of maker amounts
Modifiers: nonReentrant, onlyOperator, notPaused Requirements:
  • Caller must be an authorized operator
  • Trading must not be paused
  • Orders must be crossing (price overlap)
  • Token IDs must match or be complements

Order Management Functions

validateOrder

function validateOrder(Order memory order) public view
Validates an order without executing it.
order
Order
The order to validate
Validation checks:
  • Order has not expired
  • Signature is valid
  • Fee rate is within allowed maximum
  • Token ID is registered
  • Order is not already filled or cancelled
  • Nonce is valid

getOrderStatus

function getOrderStatus(bytes32 orderHash) public view returns (OrderStatus memory)
Returns the current status of an order.
orderHash
bytes32
The hash of the order to query
Returns: OrderStatus struct containing:
  • isFilledOrCancelled (bool): Whether the order is filled or cancelled
  • remaining (uint256): Remaining amount available to fill

cancelOrder

function cancelOrder(Order memory order) external
Cancels a single order. Can only be called by the order maker.
order
Order
The order to cancel
Requirements:
  • Caller must be the order maker
  • Order must not already be filled or cancelled

cancelOrders

function cancelOrders(Order[] memory orders) external
Cancels multiple orders in a single transaction.
orders
Order[]
Array of orders to cancel
Requirements:
  • Caller must be the maker of all orders
  • Orders must not already be filled or cancelled

Access Control Functions

addAdmin

function addAdmin(address admin_) external
Adds a new admin to the exchange.
admin_
address
Address to grant admin privileges
Modifiers: onlyAdmin

addOperator

function addOperator(address operator_) external
Adds a new operator to the exchange.
operator_
address
Address to grant operator privileges
Modifiers: onlyAdmin

removeAdmin

function removeAdmin(address admin) external
Removes an admin from the exchange.
admin
address
Address to revoke admin privileges from
Modifiers: onlyAdmin

removeOperator

function removeOperator(address operator) external
Removes an operator from the exchange.
operator
address
Address to revoke operator privileges from
Modifiers: onlyAdmin

renounceAdminRole

function renounceAdminRole() external
Allows caller to renounce their own admin role. Modifiers: onlyAdmin

renounceOperatorRole

function renounceOperatorRole() external
Allows caller to renounce their own operator role. Modifiers: onlyOperator

isAdmin

function isAdmin(address usr) external view returns (bool)
Checks if an address has admin privileges.
usr
address
Address to check
Returns: true if the address is an admin

isOperator

function isOperator(address usr) external view returns (bool)
Checks if an address has operator privileges.
usr
address
Address to check
Returns: true if the address is an operator

Configuration Functions

pauseTrading

function pauseTrading() external
Pauses all trading operations on the exchange. Modifiers: onlyAdmin

unpauseTrading

function unpauseTrading() external
Resumes trading operations on the exchange. Modifiers: onlyAdmin

setProxyFactory

function setProxyFactory(address _newProxyFactory) external
Updates the Polymarket proxy wallet factory address.
_newProxyFactory
address
New proxy wallet factory address
Modifiers: onlyAdmin

setSafeFactory

function setSafeFactory(address _newSafeFactory) external
Updates the Gnosis Safe factory address.
_newSafeFactory
address
New Safe factory address
Modifiers: onlyAdmin

registerToken

function registerToken(
    uint256 token,
    uint256 complement,
    bytes32 conditionId
) external
Registers a token pair (binary outcome) for trading on the exchange.
token
uint256
The ERC1155 token ID to register
complement
uint256
The complementary token ID (the other outcome)
conditionId
bytes32
The CTF condition ID for this market
Modifiers: onlyAdmin Requirements:
  • Token and complement must be different
  • Neither token can be zero
  • Tokens must not already be registered

View Functions

getCollateral

function getCollateral() public view returns (address)
Returns the collateral token address (USDC). Returns: Address of the ERC20 collateral token

getCtf

function getCtf() public view returns (address)
Returns the Conditional Token Framework contract address. Returns: Address of the ERC1155 CTF contract

getMaxFeeRate

function getMaxFeeRate() public pure returns (uint256)
Returns the maximum allowed fee rate in basis points. Returns: Maximum fee rate (1000 bips = 10%)

getConditionId

function getConditionId(uint256 token) public view returns (bytes32)
Returns the condition ID for a registered token.
token
uint256
The token ID to query
Returns: The bytes32 condition ID

getComplement

function getComplement(uint256 token) public view returns (uint256)
Returns the complement token ID for a given token.
token
uint256
The token ID to query
Returns: The complement token ID Requirements:
  • Token must be registered

validateComplement

function validateComplement(uint256 token, uint256 complement) public view
Validates that two tokens are complements of each other.
token
uint256
First token ID
complement
uint256
Second token ID to validate as complement
Reverts: If tokens are not complements

validateTokenId

function validateTokenId(uint256 tokenId) public view
Validates that a token is registered for trading.
tokenId
uint256
Token ID to validate
Reverts: If token is not registered

getProxyFactory

function getProxyFactory() public view returns (address)
Returns the Polymarket proxy wallet factory address. Returns: Proxy factory address

getSafeFactory

function getSafeFactory() public view returns (address)
Returns the Gnosis Safe factory address. Returns: Safe factory address

getPolyProxyFactoryImplementation

function getPolyProxyFactoryImplementation() public view returns (address)
Returns the implementation address used by the proxy factory. Returns: Proxy factory implementation address

getSafeFactoryImplementation

function getSafeFactoryImplementation() public view returns (address)
Returns the master copy address used by the Safe factory. Returns: Safe factory master copy address

getPolyProxyWalletAddress

function getPolyProxyWalletAddress(address _addr) public view returns (address)
Computes the Polymarket proxy wallet address for a given owner.
_addr
address
Address of the wallet owner
Returns: Computed proxy wallet address

getSafeAddress

function getSafeAddress(address _addr) public view returns (address)
Computes the Gnosis Safe address for a given owner.
_addr
address
Address of the safe owner
Returns: Computed safe address

isValidNonce

function isValidNonce(address usr, uint256 nonce) public view returns (bool)
Checks if a nonce is valid for a user.
usr
address
User address
nonce
uint256
Nonce to validate
Returns: true if the nonce matches the user’s current nonce

incrementNonce

function incrementNonce() external
Increments the caller’s nonce by 1, invalidating all orders with the previous nonce.

Events

OrderFilled

event OrderFilled(
    bytes32 indexed orderHash,
    address indexed maker,
    address indexed taker,
    uint256 makerAssetId,
    uint256 takerAssetId,
    uint256 makerAmountFilled,
    uint256 takerAmountFilled,
    uint256 fee
)
Emitted when an order is filled.

OrdersMatched

event OrdersMatched(
    bytes32 indexed takerOrderHash,
    address indexed takerOrderMaker,
    uint256 makerAssetId,
    uint256 takerAssetId,
    uint256 makerAmountFilled,
    uint256 takerAmountFilled
)
Emitted when orders are matched against each other.

OrderCancelled

event OrderCancelled(bytes32 indexed orderHash)
Emitted when an order is cancelled.

FeeCharged

event FeeCharged(
    address indexed receiver,
    uint256 tokenId,
    uint256 amount
)
Emitted when a fee is charged.

NewAdmin

event NewAdmin(
    address indexed newAdminAddress,
    address indexed admin
)
Emitted when a new admin is added.

NewOperator

event NewOperator(
    address indexed newOperatorAddress,
    address indexed admin
)
Emitted when a new operator is added.

RemovedAdmin

event RemovedAdmin(
    address indexed removedAdmin,
    address indexed admin
)
Emitted when an admin is removed.

RemovedOperator

event RemovedOperator(
    address indexed removedOperator,
    address indexed admin
)
Emitted when an operator is removed.

TradingPaused

event TradingPaused(address indexed pauser)
Emitted when trading is paused.

TradingUnpaused

event TradingUnpaused(address indexed pauser)
Emitted when trading is unpaused.

TokenRegistered

event TokenRegistered(
    uint256 indexed token0,
    uint256 indexed token1,
    bytes32 indexed conditionId
)
Emitted when a token pair is registered for trading.

ProxyFactoryUpdated

event ProxyFactoryUpdated(
    address indexed oldProxyFactory,
    address indexed newProxyFactory
)
Emitted when the proxy factory address is updated.

SafeFactoryUpdated

event SafeFactoryUpdated(
    address indexed oldSafeFactory,
    address indexed newSafeFactory
)
Emitted when the safe factory address is updated.

Errors

NotAdmin

error NotAdmin()
Thrown when a non-admin tries to call an admin-only function.

NotOperator

error NotOperator()
Thrown when a non-operator tries to call an operator-only function.

NotOwner

error NotOwner()
Thrown when trying to cancel an order not owned by the caller.

NotTaker

error NotTaker()
Thrown when the caller is not the designated taker of an order.

OrderFilledOrCancelled

error OrderFilledOrCancelled()
Thrown when trying to fill or cancel an order that is already filled or cancelled.

OrderExpired

error OrderExpired()
Thrown when trying to fill an expired order.

InvalidNonce

error InvalidNonce()
Thrown when an order has an invalid nonce.

MakingGtRemaining

error MakingGtRemaining()
Thrown when trying to fill more than the remaining amount on an order.

NotCrossing

error NotCrossing()
Thrown when orders don’t have price overlap and cannot be matched.

TooLittleTokensReceived

error TooLittleTokensReceived()
Thrown when a match operation doesn’t generate enough tokens.

MismatchedTokenIds

error MismatchedTokenIds()
Thrown when trying to match orders with incompatible token IDs.

FeeTooHigh

error FeeTooHigh()
Thrown when an order specifies a fee higher than the maximum allowed.

InvalidSignature

error InvalidSignature()
Thrown when an order signature is invalid.

InvalidComplement

error InvalidComplement()
Thrown when validating tokens that are not complements.

InvalidTokenId

error InvalidTokenId()
Thrown when a token ID is not registered or invalid.

AlreadyRegistered

error AlreadyRegistered()
Thrown when trying to register a token that is already registered.

Paused

error Paused()
Thrown when trying to trade while the exchange is paused.

Data Structures

Order

struct Order {
    uint256 salt;
    address maker;
    address signer;
    address taker;
    uint256 tokenId;
    uint256 makerAmount;
    uint256 takerAmount;
    uint256 expiration;
    uint256 nonce;
    uint256 feeRateBps;
    Side side;
    SignatureType signatureType;
    bytes signature;
}
salt
uint256
Unique salt to ensure order uniqueness
maker
address
Address of the order maker (source of funds)
signer
address
Address that signed the order
taker
address
Designated taker address (zero address for public orders)
tokenId
uint256
Token ID being bought (BUY) or sold (SELL)
makerAmount
uint256
Maximum amount of tokens to be sold by maker
takerAmount
uint256
Minimum amount of tokens to be received by maker
expiration
uint256
Timestamp after which the order expires (0 = no expiration)
nonce
uint256
Nonce for onchain cancellations
feeRateBps
uint256
Fee rate in basis points charged to maker on proceeds
side
Side
Order side: BUY (0) or SELL (1)
signatureType
SignatureType
Type of signature: EOA (0), POLY_PROXY (1), POLY_GNOSIS_SAFE (2), or POLY_1271 (3)
signature
bytes
The order signature

OrderStatus

struct OrderStatus {
    bool isFilledOrCancelled;
    uint256 remaining;
}
isFilledOrCancelled
bool
Whether the order is completely filled or has been cancelled
remaining
uint256
Remaining maker amount available to fill

Side

enum Side {
    BUY,    // 0
    SELL    // 1
}
Order side enumeration.

SignatureType

enum SignatureType {
    EOA,                // 0: ECDSA signatures from EOAs
    POLY_PROXY,         // 1: Signatures from Polymarket Proxy wallets
    POLY_GNOSIS_SAFE,   // 2: Signatures from Polymarket Gnosis Safes
    POLY_1271           // 3: EIP-1271 signatures from smart contracts
}
Supported signature types.

MatchType

enum MatchType {
    COMPLEMENTARY,  // 0: Buy vs Sell (direct trade)
    MINT,           // 1: Both buys (mint new tokens from collateral)
    MERGE           // 2: Both sells (merge tokens into collateral)
}
Types of order matching operations.