Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Advanced Usage

Use the TxFlow class for the simplest API. For bundle-sensitive applications, custom networking, or vault accounts, the SDK also exposes lower-level configuration points without exposing raw exchange requests.

Tree-shakable functions

Creating TxFlow keeps all Info and Exchange methods reachable. Browser applications that only need a few operations can import standalone functions instead:

import {
  cancelOrder,
  createExchangeContext,
  createInfoContext,
  l2Book,
  perpMeta,
  placeLimitOrder,
} from 'txflow-typescript-sdk'
 
const agentPrivateKey = process.env.TXFLOW_AGENT_PRIVATE_KEY
 
if (!agentPrivateKey?.startsWith('0x')) {
  throw new Error('TXFLOW_AGENT_PRIVATE_KEY is missing')
}
 
const info = createInfoContext('testnet')
const meta = await perpMeta(info)
const book = await l2Book(info, { coin: '1' })
 
const exchange = createExchangeContext({
  network: 'testnet',
  privateKey: agentPrivateKey as `0x${string}`,
})
 
await placeLimitOrder(exchange, {
  asset: 1,
  side: 'buy',
  px: '60000',
  sz: '0.001',
})
 
await cancelOrder(exchange, {
  asset: 1,
  oid: 1770779909233n,
})

Every public client method has a standalone equivalent with the same name. Standalone functions use fn(context, params); the advanced placeOrder function takes { orders, grouping }, while the class method takes orders, grouping?. createExchangeContext requires either privateKey or wallet.

Subscription channels are the one exception: several share a name with an Info method, so they are exported under the ws namespace and take their own contexts. See Subscriptions.

Network presets

The public SDK network presets are:

PresetHTTP base URLTxFlow chain idWallet signing chain
testnethttps://rpc.txflow-testnet.xyz2511421614
mainnethttps://rpc.txflow.com86942161

Each preset also includes usdcTokenAddress — the TxFlow-side USDC contract used by withdraw3. Withdrawals are USDC-only today, so the SDK injects this address automatically; callers do not pass it. The shared constant is exported as TXFLOW_USDC_TOKEN_ADDRESS.

Always choose testnet or mainnet explicitly:

const sdk = new TxFlow({
  network: 'testnet',
  timeout: 30_000,
})

Each preset also carries the two WebSocket endpoints, resolvable through resolveWsUrls. You can inspect presets through NETWORK_PRESETS or resolveNetwork. Do not mix a base URL from one network with the signing configuration from another.

Custom HTTP transport

Inject a transport to add tracing, headers, proxying, retries, or an application-specific HTTP stack:

import {
  TxFlow,
  type TxFlowHttpClient,
} from 'txflow-typescript-sdk'
 
const baseUrl = 'https://rpc.txflow-testnet.xyz'
 
const httpClient: TxFlowHttpClient = {
  async post<T>(endpoint: string, payload: unknown): Promise<T> {
    const response = await fetch(`${baseUrl}${endpoint}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Request-Source': 'my-app',
      },
      body: JSON.stringify(payload),
    })
 
    if (!response.ok) {
      throw new Error(`TxFlow request failed: ${response.status}`)
    }
 
    return await response.json() as T
  },
}
 
const sdk = new TxFlow({
  network: 'testnet',
  httpClient,
})

The custom client only replaces the HTTP transport. Request shaping and signing remain inside the SDK. A custom transport is also responsible for its own retry policy and error normalization. The WebSocket transport is configured separately — see Transport tuning.

Errors

The SDK exports three error classes:

ErrorMeaning
AuthenticationErrorAn exchange method or context has no signer
NetworkErrorThe built-in transport sent a request but received no response
TxFlowApiErrorHTTP error, API error, or request setup failure
import {
  AuthenticationError,
  NetworkError,
  TxFlowApiError,
} from 'txflow-typescript-sdk'
 
try {
  await sdk.exchange.cancelOrder({
    asset: 1,
    oid: '1770779909233',
  })
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Configure a signer first')
  } else if (error instanceof NetworkError) {
    console.error('No response from the node')
  } else if (error instanceof TxFlowApiError) {
    console.error(error.code, error.message, error.details)
  } else {
    throw error
  }
}

Exchange business errors are different: they can arrive in a successful HTTP response and do not throw automatically.

const result = await sdk.exchange.cancelOrder({
  asset: 1,
  oid: '1770779909233',
})
 
if (result.status !== 'ok') {
  console.error(result.response)
}

Vault routing

The class API defaults to the owner's personal account:

sdk.exchange.setVaultAddress('0xVaultAddress')
 
await sdk.exchange.placeLimitOrder({
  asset: 1,
  side: 'buy',
  px: '60000',
  sz: '0.001',
})
 
sdk.exchange.setVaultAddress(null)

With standalone functions, pass vaultAddress to createExchangeContext. Only vault-capable actions use this default; owner-scoped actions can force personal-account routing.

Precision and identifiers

  • Pass prices, quantities, USD amounts, and rates as decimal strings.
  • Prefer string or bigint for order and TWAP ids that can exceed 2^53 - 1.
  • Resolve exchange asset indices from metadata instead of hard-coding them.
  • Reuse one exchange client or context so its nonce generator remains monotonic within the process.

Current boundaries

  • No raw Info or Exchange method.
  • No sign-only or build-only Exchange method.
  • Browser wallet support covers EIP-1193, ethers v6 signers, and viem local accounts.
  • Some lower-frequency actions and TWAP response details remain beta.

Next steps