// Developers

TypeScript SDK

@routerx.exchange/sdk is a typed client for quotes and swaps, Cross via rx.cross, plus limit order and DCA. Swap quotes load GET /v1/:chain/quotePlan and run the calls on your RPC. Swaps settle on RXRouter. Cross history uses the Cross API.

Installation#

bash
npm install @routerx.exchange/sdk

Targets Node 18+. Reads (quotes, allowances, nonces) go over HTTPS JSON-RPC. Pass a wallet EIP-1193 provider only when you need to sign or send.

Creating a client#

Instantiate RouterX with a chainId. Quotes and other reads use rpcUrls when you set them, otherwise the built-in public HTTPS list. The wallet is a fallback only when the chain has no RPC, or every RPC is down and the wallet is already on that chain. Approve, swap, and Cross execute still need the wallet to sign and send.

client.ts
import { RouterX } from '@routerx.exchange/sdk'

const rx = new RouterX({
  chainId: 8453,
  // provider: window.ethereum, // signs and sends; not used for quotes
  // rpcUrls: ['https://…'],    // optional; replaces built-in RPCs for this chain
  // crossApiUrl: 'https://cross-api.routerx.exchange',
})

swap.quote()#

Loads GET /v1/:chain/quotePlan from https://api.routerx.exchange (override with quoteApiUrl; pass apiKey when the server requires x-api-key), then eth_calls the Multicall3 batches on your RPC. A chunk that reverts is split and retried. If every candidate misses, quote throws NO_ROUTE without a full-search fallback. quote.router is still the swap proxy. Amounts are decimal strings in base units. quote.quotedAt is milliseconds since epoch. Pass this object into swap or buildSwapTx to reuse it; a quote older than 30 seconds (maxQuoteAgeMs) is read again.

The plan's split probes run in the same round. When splitting across pools beats the single path (same impact tiers as /quote), quote.legs is set, amountOut is the sum of the legs, and swap encodes every leg. Orders under 10 bps of price impact stay on one path.

quote.ts
const quote = await rx.swap.quote({
  tokenIn: '0x4200000000000000000000000000000000000006', // WETH on Base
  tokenOut: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
  amountIn: '1000000000000000000',
  // maxSteps?: number
  // gasPrice?: string // wei
  // split?: 'auto' | 'force' | 'off'
})

console.log(quote.amountOut)
console.log(quote.offer.path)
console.log(quote.legs?.map((leg) => leg.split)) // e.g. [7000, 3000] when split
console.log(quote.router)
OptionTypeDescription
tokenInstringInput token. Required. Native: NATIVE_PLACEHOLDER.
tokenOutstringOutput token. Required.
amountInstringInput amount in base units. Required.
maxStepsnumberMax hops. Optional. On-chain query accepts 1–4; the SDK clamps to the chain default.
gasPricestringWei for gas-aware scoring. Optional.
split'auto' | 'force' | 'off'Split routing. Optional; default auto. force skips the small-order gate, off stays on one path.

swap.swap()#

Quotes, optionally approves the router, and sends the swap transaction. Pass the quote the user saw so the signed price matches it. Returns the built result plus hash.

swap.ts
const result = await rx.swap.swap({
  tokenIn: quote.tokenIn,
  tokenOut: quote.tokenOut,
  amountIn: quote.amountIn,
  to: account,           // recipient
  slippage: 0.5,         // percent; default 0.5
  quote,                 // reused while quotedAt is within 30s
  autoApprove: true,     // default true for ERC-20
  // approvalMode: 'exact' | 'infinite'
})

console.log(result.hash)
console.log(result.minAmountOut)
console.log(result.tx)

Provider required

swap, approve, and Cross execute need a wallet provider on the client.

swap.buildSwapTx()#

Same as swap without sending — returns minAmountOut, feeBps, and tx: { to, data, value } for your own broadcaster or simulator. minAmountOut is amountOut × (1 − feeBps / 10000) × (1 − slippage / 100), floored, with feeBps = max(fee, 10): the router takes its fee from amountIn and charges 10 bps to senders outside its fee whitelist.

build.ts
const built = await rx.swap.buildSwapTx({
  tokenIn: quote.tokenIn,
  tokenOut: quote.tokenOut,
  amountIn: quote.amountIn,
  to: account,
  slippage: 0.5,
  quote, // same reuse rule as swap()
})

// eth_call / Tenderly / your bot against built.tx

cross#

rx.cross.quote composes source/dest swap legs with the same quotePlan path as swap.quote, plus Circle Iris Fast+Forwarder fees. Transfer history uses https://cross-api.routerx.exchange (routerx-cross). HTTP POST /v1/quote on that host is disabled.

cross.ts
import { RouterX, NATIVE_PLACEHOLDER } from '@routerx.exchange/sdk'

const rx = new RouterX({
  chainId: 8453,
  provider: window.ethereum,
  crossApiUrl: 'https://cross-api.routerx.exchange',
})

const quote = await rx.cross.quote({
  srcChainId: 8453,
  dstChainId: 42161,
  tokenIn: NATIVE_PLACEHOLDER,
  tokenOut: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
  amountIn: '1000000000000000000',
  slippageBps: 50,
})

const { burnTxHash } = await rx.cross.execute({
  quote,
  from: account,
  provider: window.ethereum,
  srcChainId: 8453,
  dstChainId: 42161,
  tokenInDecimals: 18,
  tokenOutDecimals: 6,
  slippage: 0.5,
  onStatus: (status) => console.log(status),
})
Composer sources: Ethereum, Optimism, Unichain, Polygon, Base, Arbitrum, Avalanche, Monad, World Chain, HyperEVM, and Arc. See the Cross API for transfer endpoints and the Integration page for the CrossComposer CREATE2 address.

Types#

Core shapes from the SDK:

types.ts
interface QuoteResult {
  chainId: number
  tokenIn: string
  tokenOut: string
  amountIn: string
  amountOut: string // sum of legs when split
  offer: FormattedOffer
  router: string
  cached: boolean
  legs?: QuoteSplitLeg[] // only when splitting beats the single path
  quotedAt?: number // ms since epoch; swap reuses the quote while this is fresh
}

interface FormattedOffer {
  amounts: string[]
  adapters: { address: string; name: string }[]
  path: string[]
  gasEstimate: string
  extras: string[] // aligned with adapters; pass to hops[i].extra
}

interface QuoteSplitLeg {
  split: number // bps of post-fee amount; last leg takes remainder
  hops: Array<{ adapter: string; name?: string; tokenOut: string; extra: string }>
  amountIn?: string // floor(amountIn × split / 10000) as quoted
  amountOut: string
  gasEstimate?: string
}

interface SwapResult extends QuoteResult {
  minAmountOut: string // after feeBps, then slippage
  feeBps: number       // max(fee, 10); 0 for wrap/unwrap
  tx: { to: string; data: string; value: string }
}
  • Also: rx.limitOrder and rx.dca on LO-capable chains.
  • See the Integration guide for contract addresses and the API reference for HTTP quote, quotePlan, and swap. swap.quote uses quotePlan; it does not call GET /quote or POST /swap.