Skip to main content
Kuest uses multiple smart contracts on Polygon for trading, market creation, and settlement.

Contract addresses

All addresses from src/lib/contracts.ts:

Core trading contracts

ContractAddressPurpose
USDC (Native)0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359Trading collateral
USDC (Bridged)0x2791bca1f2de4661ed88a30c99a7a9449aa84174Legacy USDC.e
Conditional Tokens0x4682048725865bf17067bd85fF518527A262A9C7Outcome token minting
CTF Exchange0xB5592f7CccA122558D2201e190826276f3a661cbOrder matching
Neg Risk Exchange0xef02d1Ea5B42432C4E99C2785d1a4020d2FB24F5Multi-outcome markets

Oracle and resolution

ContractAddressPurpose
UMA CTF Adapter0x20088f6aa9D8D5947c9f002167355Cb332134bf8Oracle adapter
UMA Neg Risk Adapter0x724259Fe88100FE18C134324C4853975FBDa4d76Multi-outcome oracle
Resolved By0x559a18f929E47589521E4c61599E235Fd38A0c95Resolution authority

Safe wallet support

ContractAddressPurpose
Safe Proxy Factory0x0202c1c426C77cEE55979e4fB3496288fAba8413Deploy Safe wallets
Safe Multisend0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761Batch transactions

Constants

src/lib/contracts.ts
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export const ZERO_COLLECTION_ID = '0x0000000000000000000000000000000000000000000000000000000000000000'

Contract ABIs

USDC token

[
  {
    "name": "balanceOf",
    "type": "function",
    "stateMutability": "view",
    "inputs": [{"name": "account", "type": "address"}],
    "outputs": [{"name": "balance", "type": "uint256"}]
  },
  {
    "name": "approve",
    "type": "function",
    "stateMutability": "nonpayable",
    "inputs": [
      {"name": "spender", "type": "address"},
      {"name": "amount", "type": "uint256"}
    ],
    "outputs": [{"name": "success", "type": "bool"}]
  },
  {
    "name": "transfer",
    "type": "function",
    "stateMutability": "nonpayable",
    "inputs": [
      {"name": "to", "type": "address"},
      {"name": "amount", "type": "uint256"}
    ],
    "outputs": [{"name": "success", "type": "bool"}]
  }
]

Conditional Tokens

[
  {
    "name": "splitPosition",
    "type": "function",
    "inputs": [
      {"name": "collateralToken", "type": "address"},
      {"name": "parentCollectionId", "type": "bytes32"},
      {"name": "conditionId", "type": "bytes32"},
      {"name": "partition", "type": "uint256[]"},
      {"name": "amount", "type": "uint256"}
    ]
  },
  {
    "name": "mergePositions",
    "type": "function",
    "inputs": [
      {"name": "collateralToken", "type": "address"},
      {"name": "parentCollectionId", "type": "bytes32"},
      {"name": "conditionId", "type": "bytes32"},
      {"name": "partition", "type": "uint256[]"},
      {"name": "amount", "type": "uint256"}
    ]
  },
  {
    "name": "redeemPositions",
    "type": "function",
    "inputs": [
      {"name": "collateralToken", "type": "address"},
      {"name": "parentCollectionId", "type": "bytes32"},
      {"name": "conditionId", "type": "bytes32"},
      {"name": "indexSets", "type": "uint256[]"}
    ]
  }
]

Contract interactions

Approve USDC for trading

import { NATIVE_USDC_TOKEN_ADDRESS, CTF_EXCHANGE_ADDRESS } from '@/lib/contracts'
import { useWriteContract } from 'wagmi'

const { writeContract } = useWriteContract()

// Approve unlimited USDC
await writeContract({
  address: NATIVE_USDC_TOKEN_ADDRESS,
  abi: erc20Abi,
  functionName: 'approve',
  args: [
    CTF_EXCHANGE_ADDRESS,
    BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
  ],
})

Split USDC into outcome tokens

import { CONDITIONAL_TOKENS_CONTRACT } from '@/lib/contracts'
import { parseUnits } from 'viem'

// Split 10 USDC into YES/NO shares
await writeContract({
  address: CONDITIONAL_TOKENS_CONTRACT,
  abi: conditionalTokensAbi,
  functionName: 'splitPosition',
  args: [
    NATIVE_USDC_TOKEN_ADDRESS, // collateral
    ZERO_COLLECTION_ID,        // parent collection
    conditionId,               // market condition ID
    [1, 2],                    // partition (YES, NO)
    parseUnits('10', 6),       // amount (10 USDC)
  ],
})

Redeem winning shares

// After market resolves to outcome index 0 (YES)
await writeContract({
  address: CONDITIONAL_TOKENS_CONTRACT,
  abi: conditionalTokensAbi,
  functionName: 'redeemPositions',
  args: [
    NATIVE_USDC_TOKEN_ADDRESS,
    ZERO_COLLECTION_ID,
    conditionId,
    [1], // index set for YES
  ],
})

Reading contract state

Check USDC allowance

import { useReadContract } from 'wagmi'

const { data: allowance } = useReadContract({
  address: NATIVE_USDC_TOKEN_ADDRESS,
  abi: erc20Abi,
  functionName: 'allowance',
  args: [userAddress, CTF_EXCHANGE_ADDRESS],
})

const hasAllowance = allowance && allowance > 0n

Get outcome token balance

const { data: balance } = useReadContract({
  address: CONDITIONAL_TOKENS_CONTRACT,
  abi: conditionalTokensAbi,
  functionName: 'balanceOf',
  args: [userAddress, positionId],
})

console.log('Outcome tokens:', Number(balance) / 1e6)

Check market resolution

const { data: payoutNumerators } = useReadContract({
  address: CONDITIONAL_TOKENS_CONTRACT,
  abi: conditionalTokensAbi,
  functionName: 'payoutNumerators',
  args: [conditionId, outcomeIndex],
})

// If payoutNumerators[0] === 1, YES won
// If payoutNumerators[1] === 1, NO won

Event listening

Listen for USDC transfers

import { createPublicClient, http, parseAbiItem } from 'viem'
import { polygon } from 'viem/chains'

const client = createPublicClient({
  chain: polygon,
  transport: http(),
})

const unwatch = client.watchEvent({
  address: NATIVE_USDC_TOKEN_ADDRESS,
  event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
  args: {
    to: userAddress,
  },
  onLogs: (logs) => {
    console.log('Received USDC:', logs)
  },
})

Listen for order fills

// Listen for trades on CTF Exchange
const unwatch = client.watchEvent({
  address: CTF_EXCHANGE_ADDRESS,
  event: parseAbiItem('event OrderFilled(bytes32 indexed orderId, address indexed taker, uint256 fillAmount)'),
  onLogs: (logs) => {
    console.log('Order filled:', logs)
  },
})

Gas estimation

import { useEstimateGas } from 'wagmi'

const { data: estimatedGas } = useEstimateGas({
  to: CTF_EXCHANGE_ADDRESS,
  data: encodeFunctionData({
    abi: exchangeAbi,
    functionName: 'fillOrder',
    args: [order, signature],
  }),
})

console.log('Estimated gas:', estimatedGas)
Typical gas usage:
  • USDC approval: ~46,000 gas
  • Split position: ~180,000 gas
  • Merge position: ~120,000 gas
  • Redeem position: ~90,000 gas

Security considerations

Always verify contract addresses before interacting. Scammers may deploy fake contracts.

Verify on PolygonScan

  1. Visit polygonscan.com
  2. Search for contract address
  3. Check “Contract” tab is verified
  4. Verify code matches expected implementation

Check token approvals

// Revoke approval if no longer needed
await writeContract({
  address: NATIVE_USDC_TOKEN_ADDRESS,
  abi: erc20Abi,
  functionName: 'approve',
  args: [
    CTF_EXCHANGE_ADDRESS,
    0n, // Revoke
  ],
})
Use revoke.cash to audit and revoke token approvals.

Multicall batching

Execute multiple operations in one transaction using Safe Multisend:
import { SAFE_MULTISEND_ADDRESS } from '@/lib/contracts'

// Batch: Approve USDC + Split position
const calls = [
  {
    to: NATIVE_USDC_TOKEN_ADDRESS,
    data: encodeFunctionData({
      abi: erc20Abi,
      functionName: 'approve',
      args: [CTF_EXCHANGE_ADDRESS, parseUnits('1000', 6)],
    }),
  },
  {
    to: CONDITIONAL_TOKENS_CONTRACT,
    data: encodeFunctionData({
      abi: conditionalTokensAbi,
      functionName: 'splitPosition',
      args: [NATIVE_USDC_TOKEN_ADDRESS, ZERO_COLLECTION_ID, conditionId, [1, 2], parseUnits('10', 6)],
    }),
  },
]

// Execute via Multisend
await executeMultisend(SAFE_MULTISEND_ADDRESS, calls)

Contract source code

Conditional Tokens

Core prediction market contracts

CTF Exchange

Order book exchange implementation

UMA Protocol

Optimistic oracle contracts

Safe Contracts

Multi-sig wallet contracts

Next steps

Polygon setup

Configure Polygon network

USDC operations

Learn USDC deposit and withdrawal

Trading API

Place orders via API

UMA oracles

How market resolution works

Build docs developers (and LLMs) love