# @predictdotfun/sdk The Predict SDK is a TypeScript library for interacting with the Predict.fun prediction market protocol on BNB Chain. It provides a complete interface for building, signing, and submitting orders, managing approvals, and interacting with conditional token markets including both standard and NegRisk (winner-takes-all) market types. The SDK supports both Externally Owned Accounts (EOA) and Smart Wallet ("Predict Account") interactions, with built-in support for EIP-712 typed data signing, order amount calculations for LIMIT and MARKET strategies, and direct contract interactions for trading, position redemption, merging, and splitting operations. ## OrderBuilder.make - Initialize OrderBuilder Instance Creates a new OrderBuilder instance for interacting with the Predict protocol. When a signer is provided, the method returns a Promise and enables full contract functionality including approvals and transactions. The `predictAccount` option enables Smart Wallet interactions using a Privy-exported wallet. ```typescript import { Wallet } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; // Initialize without signer (limited functionality - order building only) const orderBuilderNoSigner = OrderBuilder.make(ChainId.BnbMainnet); // Initialize with signer for full functionality const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Initialize with Predict Account (Smart Wallet) const privyWallet = new Wallet("YOUR_PRIVY_WALLET_PRIVATE_KEY"); const orderBuilderSmartWallet = await OrderBuilder.make(ChainId.BnbMainnet, privyWallet, { predictAccount: "0xYOUR_DEPOSIT_ADDRESS", // From account settings }); // Access contracts after initialization if (orderBuilder.contracts) { const balance = await orderBuilder.contracts.USDT.contract.balanceOf("0xAddress"); console.log(`USDT Balance: ${balance}`); } ``` ## setApprovals - Set All Trading Approvals Sets all necessary ERC-20 and ERC-1155 approvals for trading on the Predict protocol. This includes approvals for both standard and NegRisk exchanges, as well as yield-bearing variants. Should be called once per wallet before trading. ```typescript import { Wallet } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Set all approvals at once const result = await orderBuilder.setApprovals(); if (result.success) { console.log("All approvals set successfully"); console.log(`Transactions completed: ${result.transactions.length}`); } else { // Check which approvals failed result.transactions.forEach((tx, index) => { if (!tx.success) { console.error(`Approval ${index} failed:`, tx.cause); } }); } // Set individual approvals if needed await orderBuilder.setCtfExchangeApproval(false, true); // Standard exchange, yield-bearing await orderBuilder.setCtfExchangeApproval(true, true); // NegRisk exchange, yield-bearing await orderBuilder.setNegRiskAdapterApproval(true); // NegRisk adapter, yield-bearing await orderBuilder.setCtfExchangeAllowance(false, true); // USDT allowance for standard exchange ``` ## getLimitOrderAmounts - Calculate LIMIT Order Amounts Calculates the maker and taker amounts for a LIMIT strategy order based on the desired price per share and quantity. Returns amounts in wei for direct use in order building. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Calculate amounts for a BUY order at $0.40 per share for 10 shares const buyAmounts = orderBuilder.getLimitOrderAmounts({ side: Side.BUY, pricePerShareWei: parseEther("0.4"), // $0.40 per share quantityWei: parseEther("10"), // 10 shares }); console.log(`Price Per Share: ${buyAmounts.pricePerShare}`); // 400000000000000000n console.log(`Maker Amount (USDT): ${buyAmounts.makerAmount}`); // 4000000000000000000n (4 USDT) console.log(`Taker Amount (shares): ${buyAmounts.takerAmount}`); // 10000000000000000000n (10 shares) // Calculate amounts for a SELL order const sellAmounts = orderBuilder.getLimitOrderAmounts({ side: Side.SELL, pricePerShareWei: parseEther("0.6"), // $0.60 per share quantityWei: parseEther("5"), // 5 shares }); console.log(`Maker Amount (shares): ${sellAmounts.makerAmount}`); // 5000000000000000000n (5 shares) console.log(`Taker Amount (USDT): ${sellAmounts.takerAmount}`); // 3000000000000000000n (3 USDT) ``` ## getMarketOrderAmounts - Calculate MARKET Order Amounts Calculates order amounts for MARKET strategy orders based on the current orderbook. Supports both quantity-based and value-based orders, with optional slippage tolerance in basis points. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Example orderbook from GET /markets/{marketId}/orderbook const orderbook = { updateTimestampMs: Date.now(), asks: [[0.45, 100], [0.46, 200], [0.48, 150]], // [price, quantity] bids: [[0.43, 80], [0.42, 120], [0.40, 200]], }; // Calculate MARKET BUY by quantity with 1% slippage const buyAmounts = orderBuilder.getMarketOrderAmounts( { side: Side.BUY, quantityWei: parseEther("50"), // Buy 50 shares slippageBps: 100n, // 1% slippage tolerance }, orderbook ); console.log(`Last Price: ${buyAmounts.lastPrice}`); console.log(`Avg Price Per Share: ${buyAmounts.pricePerShare}`); console.log(`Maker Amount (USDT with slippage): ${buyAmounts.makerAmount}`); console.log(`Taker Amount (shares): ${buyAmounts.takerAmount}`); console.log(`Slippage Applied: ${buyAmounts.slippageBps} bps`); // Calculate MARKET BUY by value (spend X USDT) const valueBasedBuy = orderBuilder.getMarketOrderAmounts( { side: Side.BUY, valueWei: parseEther("10"), // Spend 10 USDT slippageBps: 50n, // 0.5% slippage }, orderbook ); // Calculate MARKET SELL const sellAmounts = orderBuilder.getMarketOrderAmounts( { side: Side.SELL, quantityWei: parseEther("30"), // Sell 30 shares slippageBps: 100n, // 1% slippage }, orderbook ); ``` ## buildOrder - Build Order Object Constructs a complete order object with all required fields for submission to the Predict API. Supports both LIMIT and MARKET strategies with automatic salt generation and expiration handling. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Build a LIMIT order const limitOrder = orderBuilder.buildOrder("LIMIT", { side: Side.BUY, tokenId: "12345678901234567890", // Outcome token ID from API makerAmount: parseEther("4"), // 4 USDT takerAmount: parseEther("10"), // 10 shares feeRateBps: 100, // 1% fee (from GET /markets) nonce: 0n, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours }); // Build a MARKET order (expiration auto-set to 5 minutes) const marketOrder = orderBuilder.buildOrder("MARKET", { side: Side.SELL, tokenId: "12345678901234567890", makerAmount: parseEther("10"), // 10 shares takerAmount: parseEther("4"), // 4 USDT expected feeRateBps: 100, nonce: 0n, }); // With Predict Account (maker/signer auto-set) const predictAccountOrder = orderBuilder.buildOrder("LIMIT", { side: Side.BUY, tokenId: "12345678901234567890", makerAmount: parseEther("4"), takerAmount: parseEther("10"), feeRateBps: 100, nonce: 0n, }); console.log(`Order salt: ${limitOrder.salt}`); console.log(`Order maker: ${limitOrder.maker}`); console.log(`Order expiration: ${limitOrder.expiration}`); ``` ## buildTypedData - Build EIP-712 Typed Data Generates EIP-712 typed data structure for an order, required for signing. The `isNegRisk` and `isYieldBearing` flags determine which exchange contract is used for verification. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); const order = orderBuilder.buildOrder("LIMIT", { side: Side.BUY, tokenId: "12345678901234567890", makerAmount: parseEther("4"), takerAmount: parseEther("10"), feeRateBps: 100, nonce: 0n, }); // Build typed data for a NegRisk yield-bearing market const typedData = orderBuilder.buildTypedData(order, { isNegRisk: true, // Multi-outcome market isYieldBearing: true, // Yield-enabled market }); console.log(`Primary Type: ${typedData.primaryType}`); console.log(`Domain Name: ${typedData.domain.name}`); console.log(`Verifying Contract: ${typedData.domain.verifyingContract}`); console.log(`Chain ID: ${typedData.domain.chainId}`); // Build typed data for standard market const standardTypedData = orderBuilder.buildTypedData(order, { isNegRisk: false, isYieldBearing: false, }); ``` ## signTypedDataOrder - Sign Order with EIP-712 Signs an order using EIP-712 typed data standard. Returns a SignedOrder object ready for API submission. Supports both EOA and Predict Account (Smart Wallet) signing. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Build order and typed data const order = orderBuilder.buildOrder("LIMIT", { side: Side.BUY, tokenId: "12345678901234567890", makerAmount: parseEther("4"), takerAmount: parseEther("10"), feeRateBps: 100, nonce: 0n, }); const typedData = orderBuilder.buildTypedData(order, { isNegRisk: true, isYieldBearing: true, }); // Sign the order const signedOrder = await orderBuilder.signTypedDataOrder(typedData); console.log(`Signature: ${signedOrder.signature}`); console.log(`Signed maker: ${signedOrder.maker}`); // Compute order hash const orderHash = orderBuilder.buildTypedDataHash(typedData); console.log(`Order Hash: ${orderHash}`); // Prepare for API submission const createOrderPayload = { data: { order: { ...signedOrder, hash: orderHash }, pricePerShare: parseEther("0.4").toString(), strategy: "LIMIT", }, }; ``` ## cancelOrders - Cancel Open Orders Cancels one or more open orders on-chain. Orders must be grouped by `isNegRisk` and `isYieldBearing` properties before cancellation. ```typescript import { Wallet } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Orders fetched from GET /orders endpoint const ordersToCancel = [ { order: { /* order object */ }, isNegRisk: true, isYieldBearing: true }, { order: { /* order object */ }, isNegRisk: true, isYieldBearing: true }, ]; // Group orders by type const negRiskYieldBearingOrders = ordersToCancel .filter(o => o.isNegRisk && o.isYieldBearing) .map(o => o.order); // Cancel orders const result = await orderBuilder.cancelOrders(negRiskYieldBearingOrders, { isNegRisk: true, isYieldBearing: true, withValidation: true, // Validates token IDs (default: true) }); if (result.success) { console.log("Orders cancelled successfully"); console.log(`Transaction receipt: ${result.receipt?.hash}`); } else { console.error("Failed to cancel orders:", result.cause); } // Cancel without validation (faster but less safe) const fastResult = await orderBuilder.cancelOrders(negRiskYieldBearingOrders, { isNegRisk: true, isYieldBearing: true, withValidation: false, }); ``` ## redeemPositions - Redeem Winning Positions Redeems winning positions after a market has resolved. Supports both standard and NegRisk markets with yield-bearing variants. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Redeem standard market position (conditionId and indexSet from GET /positions) const standardResult = await orderBuilder.redeemPositions({ conditionId: "0x1234567890abcdef...", // From API indexSet: 1, // 1 for YES, 2 for NO isNegRisk: false, isYieldBearing: true, }); if (standardResult.success) { console.log("Standard positions redeemed:", standardResult.receipt?.hash); } // Redeem NegRisk market position (requires amount) const negRiskResult = await orderBuilder.redeemPositions({ conditionId: "0xabcdef1234567890...", indexSet: 1, amount: parseEther("100"), // Amount to redeem (from API) isNegRisk: true, isYieldBearing: true, }); if (negRiskResult.success) { console.log("NegRisk positions redeemed:", negRiskResult.receipt?.hash); } else { console.error("Redemption failed:", negRiskResult.cause); } ``` ## mergePositions - Merge Outcome Tokens to Collateral Merges equal amounts of both outcome tokens (YES and NO) back into the collateral token (USDT). Useful when holding equal positions on both outcomes. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Merge 100 tokens of each outcome back to USDT const result = await orderBuilder.mergePositions({ conditionId: "0x1234567890abcdef...", amount: parseEther("100"), // Amount of each outcome token to merge isNegRisk: false, isYieldBearing: true, }); if (result.success) { console.log("Positions merged successfully:", result.receipt?.hash); } else { console.error("Merge failed:", result.cause); } // Merge NegRisk market positions const negRiskMerge = await orderBuilder.mergePositions({ conditionId: "0xabcdef1234567890...", amount: parseEther("50"), isNegRisk: true, isYieldBearing: true, }); ``` ## splitPositions - Split Collateral to Outcome Tokens Splits collateral (USDT) into equal amounts of both outcome tokens. This is the inverse of mergePositions. ```typescript import { Wallet, parseEther } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Split 100 USDT into 100 YES and 100 NO tokens const result = await orderBuilder.splitPositions({ conditionId: "0x1234567890abcdef...", amount: parseEther("100"), // USDT to split isNegRisk: false, isYieldBearing: true, }); if (result.success) { console.log("Positions split successfully:", result.receipt?.hash); } else { console.error("Split failed:", result.cause); } // Split for NegRisk market const negRiskSplit = await orderBuilder.splitPositions({ conditionId: "0xabcdef1234567890...", amount: parseEther("50"), isNegRisk: true, isYieldBearing: true, }); ``` ## balanceOf - Check USDT Balance Retrieves the USDT balance for the connected wallet or a specified address. ```typescript import { Wallet, formatEther } from "ethers"; import { OrderBuilder, ChainId } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // Get balance of connected wallet const balanceWei = await orderBuilder.balanceOf(); console.log(`USDT Balance: ${formatEther(balanceWei)} USDT`); // Get balance of specific address const otherBalance = await orderBuilder.balanceOf("USDT", "0xOtherAddress..."); console.log(`Other wallet balance: ${formatEther(otherBalance)} USDT`); // Check if balance is sufficient for order const orderAmountWei = 10000000000000000000n; // 10 USDT if (balanceWei >= orderAmountWei) { console.log("Sufficient balance for order"); } else { console.log("Insufficient balance"); } ``` ## Contract Interactions - Direct Contract Access Access underlying contract instances for custom interactions. All contracts include both the contract instance and ABI codec for encoding/decoding. ```typescript import { Wallet } from "ethers"; import { OrderBuilder, ChainId, AddressesByChainId, CTFExchangeAbi, ConditionalTokensAbi, ERC20Abi, } from "@predictdotfun/sdk"; const signer = new Wallet("YOUR_PRIVATE_KEY"); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); if (orderBuilder.contracts) { // Access USDT contract const usdt = orderBuilder.contracts.USDT.contract; const balance = await usdt.balanceOf(signer.address); const decimals = await usdt.decimals(); // Access CTF Exchange const ctfExchange = orderBuilder.contracts.YIELD_BEARING_CTF_EXCHANGE.contract; // Access Conditional Tokens const conditionalTokens = orderBuilder.contracts.YIELD_BEARING_CONDITIONAL_TOKENS.contract; const tokenBalance = await conditionalTokens.balanceOf(signer.address, "TOKEN_ID"); // Use codec for encoding calldata const usdtCodec = orderBuilder.contracts.USDT.codec; const encodedApprove = usdtCodec.encodeFunctionData("approve", [ AddressesByChainId[ChainId.BnbMainnet].YIELD_BEARING_CTF_EXCHANGE, 1000000000000000000n, ]); // Access multicall versions for batched reads const multicall = orderBuilder.contracts.multicall; const [balance1, balance2] = await Promise.all([ multicall.USDT.contract.balanceOf("0xAddress1"), multicall.USDT.contract.balanceOf("0xAddress2"), ]); } // Access addresses directly const addresses = AddressesByChainId[ChainId.BnbMainnet]; console.log(`CTF Exchange: ${addresses.YIELD_BEARING_CTF_EXCHANGE}`); console.log(`USDT: ${addresses.USDT}`); ``` ## Complete Trading Flow Example End-to-end example demonstrating the complete flow from initialization to order submission. ```typescript import { Wallet, parseEther, formatEther } from "ethers"; import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk"; async function main() { // 1. Initialize OrderBuilder const signer = new Wallet(process.env.WALLET_PRIVATE_KEY!); const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer); // 2. Set approvals (one-time setup) const approvalResult = await orderBuilder.setApprovals(); if (!approvalResult.success) { throw new Error("Failed to set approvals"); } // 3. Check balance const balance = await orderBuilder.balanceOf(); console.log(`Available balance: ${formatEther(balance)} USDT`); // 4. Calculate order amounts const amounts = orderBuilder.getLimitOrderAmounts({ side: Side.BUY, pricePerShareWei: parseEther("0.45"), quantityWei: parseEther("20"), }); // 5. Build order const order = orderBuilder.buildOrder("LIMIT", { side: Side.BUY, tokenId: "OUTCOME_TOKEN_ID_FROM_API", makerAmount: amounts.makerAmount, takerAmount: amounts.takerAmount, feeRateBps: 100, // From GET /markets nonce: 0n, }); // 6. Build typed data and sign const typedData = orderBuilder.buildTypedData(order, { isNegRisk: true, isYieldBearing: true, }); const signedOrder = await orderBuilder.signTypedDataOrder(typedData); const orderHash = orderBuilder.buildTypedDataHash(typedData); // 7. Prepare API payload const payload = { data: { order: { ...signedOrder, hash: orderHash }, pricePerShare: amounts.pricePerShare.toString(), strategy: "LIMIT", }, }; console.log("Order ready for submission:", JSON.stringify(payload, null, 2)); // Submit to POST /orders endpoint on Predict API } main().catch(console.error); ``` ## Summary The Predict SDK provides a comprehensive toolkit for building trading applications on the Predict.fun prediction market protocol. Primary use cases include programmatic trading with LIMIT and MARKET orders, portfolio management through position redemption/merging/splitting, and automated market making. The SDK handles all complexity around EIP-712 signing, contract interactions, and approval management. Integration patterns typically involve initializing a single OrderBuilder instance per wallet, setting approvals once during setup, then using the order building and signing methods in response to market data. The SDK supports both traditional EOA wallets and Predict Account Smart Wallets, with the latter requiring the Privy-exported wallet as the signer. All contract interactions return standardized TransactionResult objects with success status and optional receipt/error information for robust error handling.