Tycho API: Real-Time Pool Data
Orkid's routing engine is fast because its data is fast. You can't find the best route if your pool data is stale. Tycho — built by PropellerHeads — streams real-time protocol component data over WebSocket. Here's how it works, how Orkid uses it, and how you can build your own router on top of it.
The data layer problem
Every DEX router faces the same problem: you need to know the current state of every pool on every venue to find the best route. On Base alone, there are thousands of active pools across Uniswap V2, V3, V4, Aerodrome, SushiSwap, Balancer, and others.
The naive approach is to RPC-call each pool contract for reserves and fees. That's thousands of calls per route computation. At ~50ms per call, you're looking at minutes to compute a single route. Useless.
Tycho solves this. Built by PropellerHeads, it indexes every supported pool and streams state updates in real time. Instead of polling, you subscribe. When a pool's state changes — a swap occurs, liquidity is added, fees are adjusted — Tycho pushes the update to you within milliseconds.
The V3 API and protocol components
Tycho V3 is the current version. The key innovation over V2 is protocol components — a structured decomposition of each pool into its constituent parts.
Instead of just giving you "Pool 0xABC has 1000 USDC and 0.5 WETH," Tycho V3 gives you:
- Token pair: The two (or more) tokens in the pool
- Fee tier: The swap fee (e.g., 0.05%, 0.3%, 1%)
- Liquidity state: For V3/V4 concentrated pools, the current tick, tick spacing, and active liquidity range
- State deltas: What changed since the last update — swap in, swap out, LP deposit, LP withdrawal
- Timestamp: Block number and log index for ordering
This decomposition matters because it lets you compute exact output amounts without re-deriving the pool's internal state. You get the components, you run the AMM math, you get the price. No ambiguity, no rounding errors from stale reserves.
WebSocket vs HTTP
Tycho V3 offers two transport modes. Use the right one for your use case:
For a routing engine, WebSocket is mandatory. You subscribe to the pools you care about and receive push updates as state changes. The 2 concurrent connection limit on the free tier is enough for a single-chain router — one connection for pool state, one for block headers.
HTTP is useful for one-off queries: "give me the current state of pool 0xABC" or "list all USDC/WETH pools on Base." At 50 RPS, you can poll a few hundred pools per second — fine for analytics, too slow for competitive routing.
Orkid's integration architecture
Orkid uses Tycho as its primary pool data source on Base. Here's the architecture:
- 01
Pool index subscription
On startup, Orkid's solver subscribes to Tycho's WebSocket for all pools on Base matching a whitelist of tokens (USDC, WETH, cbETH, DAI, USDbC, EURC, and ~50 others). Tycho pushes the initial state of each pool, then deltas as they occur.
- 02
In-memory state cache
The solver maintains an in-memory map of pool addresses to their latest protocol components. Each WebSocket update mutates the map. This cache is the source of truth for route computation — no RPC calls needed during routing.
- 03
Route graph construction
From the in-memory cache, the solver builds a directed graph where nodes are tokens and edges are pools. Each edge has a weight derived from the pool's current liquidity state. The graph is rebuilt on every swap request using the latest cached state.
- 04
Path search and quote
The solver runs a modified Dijkstra's algorithm (or Dijkstra-with-splits for multi-path routing) on the graph to find the best route. Because pool state is fresh (< 10ms stale), the computed quote closely matches what the pool will actually return on-chain.
Building a simple router
Here's a pseudo-code example of a minimal router using Tycho V3. This is not production code — it's the skeleton to understand the flow:
// 1. Connect to Tycho WebSocket
const ws = tycho.connect({
chain: 'base',
protocols: ['uniswap_v3', 'uniswap_v2', 'aerodrome'],
tokens: ['USDC', 'WETH', 'DAI', 'USDbC'],
});
// 2. Maintain in-memory pool state
const pools = new Map();
ws.on('component', (update) => {
pools.set(update.poolAddress, {
tokenIn: update.tokenIn,
tokenOut: update.tokenOut,
fee: update.fee,
liquidity: update.liquidity,
sqrtPrice: update.sqrtPrice,
tick: update.tick,
timestamp: update.timestamp,
});
});
// 3. On swap request, find best route
function findRoute(tokenIn, tokenOut, amountIn) {
// Build graph from cached pool state
const graph = buildGraph(pools);
// Find best path (Dijkstra with AMM math as edge weight)
const path = dijkstra(graph, tokenIn, tokenOut, amountIn);
// Compute expected output along the path
const amountOut = simulateSwap(path, amountIn, pools);
return { path, amountOut };
}
// 4. Submit swap (via Orkid solver or direct)
const route = findRoute('USDC', 'WETH', 1000000n);
console.log(`Best route: ${route.amountOut} WETH`);
console.log(`Hops: ${route.path.length}`); The key insight: the pool state map is always fresh because Tycho pushes updates in real time. You never read stale data. When you compute a route, the AMM math uses the same state the pool will have when your transaction lands — assuming < 2 second block time on Base.
Rate limits and practical constraints
The free tier limits are real. Here's what you get and what you need to watch:
- 2 WebSocket connections: One for pool state, one for block headers. If you need more (e.g., separate connections per protocol), you'll hit the limit. Enterprise tier raises this.
- 50 HTTP requests/second: Enough for batch queries but not for polling-based routing. If you're hitting 50 RPS consistently, switch to WebSocket.
- Protocol coverage: Free tier includes major protocols (Uniswap V2/V3, SushiSwap). V4, Aerodrome, and Balancer may require a paid tier. Check current docs.
- Reconnection handling: WebSocket connections
drop. Your client must auto-reconnect and request a state
snapshot on reconnect — Tycho provides a
/v1/snapshotendpoint for this.
For production routing, Orkid uses the enterprise tier with higher limits and dedicated infrastructure. But the free tier is enough to build a working prototype and validate your routing logic.
FAQ
Is Tycho free to use?
Tycho offers a free tier with rate-limited access (2 concurrent WebSocket connections, 50 HTTP requests per second) that is sufficient for prototyping and light production use. For higher throughput or enterprise use, PropellerHeads offers paid tiers with increased rate limits and dedicated infrastructure. Orkid uses the enterprise tier for production routing. Check the PropellerHeads documentation for current pricing.
What is the difference between Tycho V2 and V3?
Tycho V2 provided pool-level data — reserves, fees, and prices per pool. V3 introduces protocol components: a higher-level abstraction that decomposes each pool into its constituent parts (token pairs, fee tiers, tick ranges for concentrated liquidity, and state deltas). V3 also adds WebSocket streaming with real-time state updates, whereas V2 was HTTP-only with polling. Orkid uses V3 exclusively. If you're starting fresh, go straight to V3 — V2 is deprecated.
Can I use Tycho without Orkid?
Yes. Tycho is a standalone product from PropellerHeads. You can use it to build your own routing engine, analytics dashboard, or arbitrage bot without any dependency on Orkid. Orkid uses Tycho as one of its data sources, but Tycho is agnostic — it streams pool data from any supported protocol. The free tier is enough to prototype a basic router.
Which chains does Tycho support?
Tycho supports Ethereum mainnet, Base, Arbitrum, Optimism, Polygon, and BNB Chain. Protocol coverage varies by chain — Ethereum and Base have the deepest coverage (Uniswap V2/V3/V4, Curve, Balancer, SushiSwap, PancakeSwap). Orkid uses Tycho primarily for Base and Ethereum mainnet routing. Check the PropellerHeads docs for the full protocol-by-chain matrix.