Trade API Documentation

Overview

The Trade API provides functionality to list markets, get trade quotes, and execute trades on prediction markets.

Example

import { createPublicClient, createWalletClient, http, type Hex } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(),
})

const TRADE_API_URL = '<https://api.foresight.now/trade>'

// 1. Get available markets
const marketsResponse = await fetch(`${TRADE_API_URL}/markets`)
const markets = await marketsResponse.json()
console.log('Available markets:', markets)

// 2. Get a quote for a trade
const marketAddress = '0x...' // Market contract address
const amount = '100000000' // 100 USDC in base units (6 decimals)
const outcome = 1 // 1 = YES, 0 = NO
const tradeType = 'Buy'

const quoteResponse = await fetch(`${TRADE_API_URL}/quote`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    market: marketAddress,
    amount: amount,
    outcome: outcome,
    type: tradeType
  })
})
const quote = await quoteResponse.json()
console.log('Trade quote:', quote)

// 3. Check and handle token approval (required for buying)
const account = '0x...' // User wallet address
const tokenAddress = '0x...' // USDC token address
const spenderAddress = '0x...' // Market maker contract address

// Check current allowance
const allowance = await publicClient.readContract({
  address: tokenAddress,
  abi: erc20ABI,
  functionName: 'allowance',
  args: [account, spenderAddress]
})

// If allowance is insufficient, approve the spender
if (allowance < BigInt(amount)) {
  const approveHash = await walletClient.writeContract({
    address: tokenAddress,
    abi: erc20ABI,
    functionName: 'approve',
    args: [spenderAddress, BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')]
  })

  // Wait for approval confirmation
  await publicClient.waitForTransactionReceipt({ hash: approveHash })
  console.log('Token approval confirmed')
}

// 4. Execute the trade
const executeResponse = await fetch(`${TRADE_API_URL}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    market: marketAddress,
    amount: amount,
    outcome: outcome,
    type: tradeType,
    account: account
  })
})
const tradeData = await executeResponse.json()
console.log('Trade execution data:', tradeData)

// If the trade status is successful
if (tradeData.tx) {
  // Simulate the transaction first
  const callResult = await publicClient.call({
    account: tradeData.tx.account,
    data: tradeData.tx.data,
    to: tradeData.tx.to,
    value: BigInt(tradeData.tx.value),
  })
  console.log('Simulation result:', callResult)

  // Send the actual transaction
  const PRIVATE_KEY = process.env.PRIVATE_KEY as Hex
  const walletClient = createWalletClient({
    chain: mainnet,
    transport: http(),
  })
  const hash = await walletClient.sendTransaction({
    account: privateKeyToAccount(PRIVATE_KEY),
    data: tradeData.tx.data,
    to: tradeData.tx.to,
    value: BigInt(tradeData.tx.value),
  })
  console.log('Transaction hash:', hash)

// 5. Completion step (Deprecated): No longer needed — indexer auto-processes confirmed transactions
// Wait for on-chain confirmation; the indexer will pick it up automatically
await publicClient.waitForTransactionReceipt({ hash })
// No call to /trade/complete is required
}

// 6. Get user positions and redeem winning positions
async function redeemWinningPositions(userAddress: string) {
  // Get resolved positions
  const positionsResponse = await fetch(`${TRADE_API_URL}/positions?walletAddress=${userAddress}&type=resolved&pg=1&ps=20`)
  const positionsData = await positionsResponse.json()

  // Filter for claimable positions (resolved markets where user has winning shares)
  const claimablePositions = positionsData.positions.filter(position =>
    position.resolutionOutcome === position.outcome && position.totalShareAmount > 0
  )

  console.log(`Found ${claimablePositions.length} claimable positions`)

  // Redeem each claimable position
  for (const position of claimablePositions) {
    try {
      const redeemResponse = await fetch(`${TRADE_API_URL}/redeem`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          market: position.market,
          account: userAddress
        })
      })
      const redeemData = await redeemResponse.json()

      if (redeemData.tx) {
        // Simulate the transaction first
        const callResult = await publicClient.call({
          account: redeemData.tx.account,
          data: redeemData.tx.data,
          to: redeemData.tx.to,
          value: BigInt(redeemData.tx.value),
        })
        console.log('Redeem simulation successful')

        // Send the actual transaction
        const redeemHash = await walletClient.sendTransaction({
          data: redeemData.tx.data,
          to: redeemData.tx.to,
          value: BigInt(redeemData.tx.value),
        })
        console.log('Redeem transaction hash:', redeemHash)

        // Wait for confirmation and complete
        await publicClient.waitForTransactionReceipt({ hash: redeemHash })

        const completeRedeemResponse = await fetch(`${TRADE_API_URL}/complete`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ txHash: redeemHash })
        })
        const redeemCompletion = await completeRedeemResponse.json()
        console.log('Redeem completion:', redeemCompletion)
      }
    } catch (error) {
      console.error(`Error redeeming position for market ${position.market}:`, error)
    }
  }
}

// Usage example
// await redeemWinningPositions('0x...') // User wallet address

API Endpoints

1. GET /trade/markets - Get All Tradeable Markets

Returns a list of all available prediction markets.

Response:

interface MarketInfo {
  address: string;
  question: string;
  outcome1Price: number;
  outcome0Price: number;
  endDate: string;
  conditionDisplayName?: string;
}

Example:

const markets = await fetch(`${TRADE_API_URL}/markets`)
const data = await markets.json()

2. POST /trade/quote - Get Trade Quote

Get pricing information for a potential trade.

Request:

interface TradeQuoteRequest {
  market: string;        // Market contract address
  amount: string;        // Amount in base units (6 decimals for USDC)
  outcome: 0 | 1;       // 0 = NO, 1 = YES
  type: 'Buy' | 'Sell'; // Trade type
}

Response:

interface TradeQuote {
  market: string;
  amount: string;
  outcome: 0 | 1;
  type: 'Buy' | 'Sell';
  estimatedReturn: string;
  estimatedPricePerShare: number;
}

Example:

const quote = await fetch(`${TRADE_API_URL}/quote`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    market: "0x...",
    amount: "100000000", // 100 USDC
    outcome: 1, // YES
    type: "Buy"
  })
})
const data = await quote.json()