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:
| Preset | HTTP base URL | TxFlow chain id | Wallet signing chain |
|---|---|---|---|
testnet | https://rpc.txflow-testnet.xyz | 2511 | 421614 |
mainnet | https://rpc.txflow.com | 869 | 42161 |
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:
| Error | Meaning |
|---|---|
AuthenticationError | An exchange method or context has no signer |
NetworkError | The built-in transport sent a request but received no response |
TxFlowApiError | HTTP 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
stringorbigintfor order and TWAP ids that can exceed2^53 - 1. - Resolve exchange
assetindices 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
- Info API — typed query patterns
- Exchange API — signed method catalog
- Signing — protocol details behind the SDK