Skip to main content

Best practices

Signer setup

The SDK supports three signer formats:

Private key

The simplest option — pass a hex-encoded private key:
const ctx = new ContextClient({
  apiKey: "...",
  signer: { privateKey: "0xabc123..." as `0x${string}` },
})

Viem account

Pass a viem Account object directly:
import { privateKeyToAccount } from "viem/accounts"

const ctx = new ContextClient({
  apiKey: "...",
  signer: { account: privateKeyToAccount("0xabc123...") },
})

Viem wallet client

Pass an existing WalletClient for full control over transport and chain:
import { createWalletClient, http } from "viem"
import { privateKeyToAccount } from "viem/accounts"
import { baseSepolia } from "viem/chains"

const walletClient = createWalletClient({
  account: privateKeyToAccount("0xabc123..."),
  chain: baseSepolia,
  transport: http("https://your-rpc.com"),
})

const ctx = new ContextClient({
  apiKey: "...",
  signer: { walletClient },
})
Use private key for scripts and bots. Use viem account when you already have an account object. Use wallet client when you need custom RPC or chain configuration.

Wallet onboarding

The critical flow before first trade: check status, setup, fund, deposit.
import { ContextClient } from "context-markets";
import { privateKeyToAccount } from "viem/accounts";

const ctx = new ContextClient({
  apiKey: process.env.CONTEXT_API_KEY!,
  signer: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
  chain: "mainnet", // or "testnet"
});

// Always check status first
const status = await ctx.account.status()

// Setup if needed — chain-aware:
//   testnet: uses gasless relay (free, no ETH needed)
//   mainnet: uses on-chain transactions (requires ETH for gas)
if (!status.isReady) {
  await ctx.account.setup()
}

// Mint test USDC (testnet only)
await ctx.account.mintTestUsdc(1000)

// Deposit to exchange — same chain-aware behavior as setup()
await ctx.account.deposit(1000)
You must call setup() before your first trade. The SDK will throw if contracts aren’t approved.
The deprecated gaslessSetup() and gaslessDeposit() methods still work as aliases, but new code should use the chain-aware setup() and deposit() which automatically select the right strategy based on your configured chain.

Price encoding

Prices are in cents (1-99), not decimals:
// Correct — 45 cents
await ctx.orders.create({ priceCents: 45, ... })

// Wrong — this is less than 1 cent
await ctx.orders.create({ priceCents: 0.45, ... })

Chain-aware operations

The setup() and deposit() methods automatically pick the right strategy based on your configured chain:
Chainsetup()deposit()
TestnetGasless relay (no ETH needed)Gasless permit signature
MainnetOn-chain transactions (requires ETH)On-chain USDC transfer
For granular control on mainnet, you can call the explicit methods directly:
// Explicit on-chain approvals
await ctx.account.approveUsdc()
await ctx.account.approveOperator()

// Explicit on-chain deposit
await ctx.account.onchainDeposit(1000)

Pagination

// Auto-paginate all results
const allMarkets = await ctx.markets.listAll({ status: "active" })
const allOrders = await ctx.orders.allMine()

// Manual cursor pagination
let cursor: string | undefined
do {
  const page = await ctx.markets.list({ cursor, limit: 50 })
  // process page.markets
  cursor = page.cursor
} while (cursor)

Common mistakes

  1. Must call setup() before first trade — the SDK will throw ContextApiError if contracts aren’t approved
  2. Prices are in cents (45), not decimals (0.45) — a price of 0.45 means less than 1 cent
  3. Outcomes are "yes" / "no" strings, not booleans
  4. mintTestUsdc() only works on testnet — it will fail on mainnet
  5. SDK doesn’t read env vars — pass apiKey explicitly to the constructor
  6. Specify orderbook depth — default may be insufficient for analysis
  7. Use simulate() before large orders to preview slippage and fill price

Error handling

The SDK throws typed errors:
ErrorWhen
ContextApiErrorHTTP errors (4xx/5xx) — includes status and body
ContextSigningErrorEIP-712 signing failures
ContextConfigErrorMissing signer when calling write operations
import { ContextApiError, ContextConfigError } from "context-markets"

try {
  await ctx.orders.create({ ... })
} catch (err) {
  if (err instanceof ContextApiError) {
    console.error(`API error ${err.status}:`, err.body)
  }
  if (err instanceof ContextConfigError) {
    console.error("Missing signer:", err.message)
  }
}