Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Proof-labs/trading-sdk/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through the complete flow from a blank Node.js project to a confirmed limit order on the Proof devnet. The Proof Exchange runs on CometBFT and every action — from key generation to order submission — happens entirely over HTTP, with no node software to install or manage locally.
1
Install the SDK
2
Add the @proof/trading-sdk package to your project:
3
npm install @proof/trading-sdk
4
The package is a pure ESM module. Make sure your package.json includes "type": "module" and that you are running Node.js 18 or later.
5
Generate a keypair and derive your address
6
Key generation is fully local — no network request is needed. The SDK derives your 20-byte owner address from your Ed25519 public key using keccak256(pubkey)[12..32]:
7
import { generateKeypair, pubkeyToOwner, ownerToHex } from "@proof/trading-sdk";

const { publicKey, privateKey } = generateKeypair();
const address = pubkeyToOwner(publicKey);       // Uint8Array (20 bytes)
const addressHex = ownerToHex(address);         // hex string, no 0x prefix

console.log(`0x${addressHex}`); // your new address
8
Store privateKey (a Uint8Array) securely. It cannot be recovered from the address alone. Never log or commit private keys to source control.
9
Fund your address via the devnet faucet
10
The devnet faucet drips approximately 10,000 USDC (10,000,000,000 µUSDC) to any address, with a 24-hour cooldown per address. You need a faucet token to call the endpoint:
11
curl -X POST https://faucet.dev.proof.trade/drip \
  -H "Authorization: Bearer $PROOF_FAUCET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"address": "0x<your-hex-address>"}'
12
If you are a paper-trading competition participant, do not use the faucet flow above — it requires a privileged token you will not have. You receive a pre-funded private key by redeeming your access code instead.
13
After funding, wait a few seconds for the deposit transaction to be included in a block before querying your balance.
14
Create an ExchangeClient and load your private key
15
Construct an ExchangeClient with the devnet chainId, then load your private key. The client uses the key for all subsequent submitTx calls:
16
import { ExchangeClient } from "@proof/trading-sdk";

const client = new ExchangeClient({ chainId: "exchange-devnet-1" });
client.setPrivateKey(privateKey);
17
All three URL options (rpcUrl, apiUrl, gatewayUrl) default to https://api.dev.proof.trade, so no additional config is required for devnet.
18
Query the orderbook
19
Before trading, verify connectivity and check the current book for market 1 (BTC perpetual):
20
const book = await client.queryOrderbook(1);
// {
//   bids: [{ price: bigint, totalQty: bigint, orderCount: number }, ...],
//   asks: [...]
// }

if (book.bids.length > 0) {
  const best = book.bids[0];
  console.log(`Best bid: $${best.price}  qty=${best.totalQty}  orders=${best.orderCount}`);
}
21
You can also verify your account balance after the faucet drip:
22
const account = await client.queryAccount(addressHex);
// { balance: bigint, equity: bigint, totalMm: bigint, totalIm: bigint, positions: [...] }
console.log(`Balance: ${account?.balance} µUSDC`);
23
Place a limit order
24
Submit a limit buy order on market 1. Prices are integer cents (bigint) — $50,000.00 is 5000000n:
25
import { Side } from "@proof/trading-sdk";

const result = await client.submitTx({
  type: "PlaceOrder",
  data: {
    market: 1,
    owner: address,        // 20-byte Uint8Array from pubkeyToOwner()
    side: Side.Buy,
    price: 5000000n,       // $50,000.00 in integer cents
    quantity: 1n,          // 1 contract
  },
});

console.log(result);
// { code: 0, hash: "ABC123...", log: "" }
26
To wait for block inclusion rather than just CheckTx, use submitTxCommit instead:
27
const result = await client.submitTxCommit({
  type: "PlaceOrder",
  data: {
    market: 1,
    owner: address,
    side: Side.Buy,
    price: 5000000n,
    quantity: 1n,
  },
});
// result.height is set once the tx lands in a block
console.log(`Confirmed at block ${result.height}`);
28
Check the result code
29
Every submitTx and submitTxCommit call returns a TxResult. Always check code before assuming success:
30
if (result.code !== 0) {
  console.error(`Order failed: code=${result.code}  log=${result.log}`);
}
31
code: 0 means CheckTx passed — the gateway accepted the transaction and it was broadcast to CometBFT. A non-zero code on submitTx means the transaction was rejected before entering the mempool. With submitTxCommit, a non-zero code at height means the engine rejected the action at DeliverTx (block inclusion), even after CheckTx passed.

Full working example

The complete generate → fund → query → trade flow, taken directly from the SDK’s agent quickstart:
import {
  ExchangeClient,
  Side,
  Action,
  TxResult,
  generateKeypair,
  pubkeyToOwner,
  ownerToHex,
} from "@proof/trading-sdk";

// 1. Key
const { publicKey, privateKey } = generateKeypair();
const address = pubkeyToOwner(publicKey);

// 2. Client
const client = new ExchangeClient({ chainId: "exchange-devnet-1" });
client.setPrivateKey(privateKey);

// 3. Query
const book = await client.queryOrderbook(1);
const acct = await client.queryAccount();

// 4. Trade
const r: TxResult = await client.submitTx({
  type: "PlaceOrder",
  data: {
    market: 1,
    owner: address,
    side: Side.Buy,
    price: 50000000n,   // $500,000.00 in integer cents
    quantity: 1n,
  },
});
You can run the SDK’s end-to-end example directly without any setup:
PROOF_FAUCET_TOKEN=<token> npx tsx examples/connect-and-trade.ts

Common error codes

When result.code is non-zero, consult the table below. The result.log field usually contains a human-readable explanation alongside the code.
CodeNameWhat it means and how to handle it
0SuccessCheckTx passed. Transaction was accepted.
12InsufficientMarginNot enough free margin. Check account.equity and reduce order size.
17InvalidSignatureThe signature is malformed. Verify chainId matches the target network.
21TimestampNonceRejectedNonce was outside the sliding window or was a replay. Retry — the SDK auto-advances.
34PostOnlyWouldCrossA postOnly: true order would have matched immediately. Adjust the price.
401MissingApiKeyGateway requires an apiKey in ExchangeClientOptions.
429RateLimitedToo many requests. Back off and retry.

Error handling pattern

const r = await client.submitTx({ type: "PlaceOrder", data: { /* ... */ } });

if (r.code !== 0) {
  if (r.code === 21) {
    // Timestamp nonce collision — just retry (SDK auto-advances the nonce)
    return await client.submitTx({ type: "PlaceOrder", data: { /* ... */ } });
  }
  if (r.code === 12) {
    console.log("Insufficient margin — check account balance");
  }
  throw new Error(`Order failed: code=${r.code} log=${r.log}`);
}

Next steps

Installation

TypeScript, Python, and Rust setup guides with runtime requirements.

Key Management

Secure key generation, storage patterns, and address derivation details.

Placing Orders

Full guide to limit orders, market orders, cancel-replace, and basket orders.

Account Queries

Query balances, positions, open orders, history, and margin ratios.

Build docs developers (and LLMs) love