> For the complete documentation index, see [llms.txt](https://docs.fynd.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fynd.xyz/reference/architecture.md).

# Architecture

## Overview

Fynd is a solver built on Tycho that finds optimal swap routes across DeFi protocols. It is organized as a multi-crate Rust workspace:

* **`fynd-core`** - Pure solving logic with no HTTP dependencies
* **`fynd-rpc`** - HTTP RPC server library
* **`fynd`** - CLI binary that runs the complete routing service

This modular architecture allows users to:

* Use just the routing algorithms (`fynd-core`) in their own applications
* Build custom HTTP servers with their own middleware (`fynd-rpc`)
* Run the complete solver as a standalone service (`fynd` binary)

## Design Decisions

* **Concurrency Model**: Hybrid async/threaded -- I/O on tokio, route finding on dedicated OS threads
* **Data Sharing**: `Arc<RwLock<>>` with write-preferring lock for MarketState (single writer, many readers)
* **Path-Finding**: Pluggable `Algorithm` trait with associated graph types, allowing each algorithm to use its preferred graph representation
* **Graph Management**: `GraphManager` trait with incremental updates from market events; built-in implementation uses `petgraph::StableDiGraph`
* **Multi-Solver Competition**: Multiple worker pools with different configurations compete per request; WorkerPoolRouter selects the best result
* **Output Format**: Structured `Quote` objects (routes, amounts, gas estimates) with optional encoded transaction
* **Derived Data Pipeline**: Pre-computed spot prices, pool depths, and token gas prices fed to algorithms via a separate computation framework
* **Observability**: Prometheus metrics on port 9898, structured tracing, health endpoint

***

## Architecture Diagram

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           HTTP Layer (Actix Web)                            │
│                         Async I/O - Non-blocking                            │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                           RouterApi                                  │   │
│  │        POST /v1/quote      GET /v1/health      GET /v1/info          │   │
│  └───────────────────────────────┬──────────────────────────────────────┘   │
└──────────────────────────────────┼──────────────────────────────────────────┘
                                   │
                                   │ QuoteRequest
                                   ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                            WorkerPoolRouter                                 │
│           Orchestrates multiple solver pools, selects best solution         │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  • Fan-out: Send each order to ALL solver pools in parallel           │  │
│  │  • Timeout: Configurable deadline per request                         │  │
│  │  • Early return: Optional min_responses for fast path                 │  │
│  │  • Selection: Choose best solution by amount_out_net_gas              │  │
│  │  • Encoding: Optionally encode solution into on-chain transaction     │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────┬──────────────────────────────────────────┘
                                   │
                    ┌──────────────┴──────────────┐
                    │                             │
                    ▼                             ▼
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│  Worker Pool A                  │ │  Worker Pool B                  │
│  (most_liquid, 2 hops, fast)    │ │  (most_liquid, 3 hops, deep)    │
│  ┌───────────┐                  │ │  ┌───────────┐                  │
│  │ TaskQueue │ (per-pool)       │ │  │ TaskQueue │ (per-pool)       │
│  └─────┬─────┘                  │ │  └─────┬─────┘                  │
│        │                        │ │        │                        │
│  ┌─────┴─────┐  ┌───────────┐   │ │  ┌─────┴─────┐  ┌───────────┐   │
│  │  Worker 1 │  │  Worker N │   │ │  │  Worker 1 │  │  Worker M │   │
│  │(SolverWkr)│  │(SolverWkr)│   │ │  │(SolverWkr)│  │(SolverWkr)│   │
│  └───────────┘  └───────────┘   │ │  └───────────┘  └───────────┘   │
└─────────────────────────────────┘ └─────────────────────────────────┘
                    │                             │
                    └──────────────┬──────────────┘
                                   │ Reads shared data
                                   ▼
┌────────────────────────────────────────────────────────────────────────────────────┐
│                         MarketState (Arc<RwLock<>>, via MarketData handle)          │
│  ┌────────────────────────────────────────────────────────────────────────────┐    │
│  │  components: HashMap<ComponentId, ProtocolComponent>                       │    │
│  │  simulation_states: HashMap<ComponentId, Box<dyn ProtocolSim>>             │    │
│  │  tokens: HashMap<Address, Token>                                           │    │
│  │  gas_price: Option<BlockGasPrice>                                          │    │
│  │  protocol_sync_status: HashMap<String, SynchronizerState>                  │    │
│  │  last_updated: Option<BlockInfo>                                           │    │
│  └────────────────────────────────────────────────────────────────────────────┘    │
└──────────────────────────────────▲─────────────────────────────────────────────────┘
                                   │ WRITE lock
                                   │
┌──────────────────────────────────┴──────────────────────────────────────────┐
│                              TychoFeed                                      │
│                     Background task (single instance)                       │
│  ┌────────────────────────────────────────────────────────────────────┐     │
│  │  Tycho Stream ──► Update MarketState ──► Broadcast Event            │     │
│  └────────────────────────────────────────────────────────────────────┘     │
│                                   │                                         │
│                                   ▼ broadcast::Sender<MarketEvent>          │
└──────────────────────────────────┬──────────────────────────────────────────┘
                                   │
                    ┌──────────────┼──────────────┐
                    ▼              ▼              ▼
              ┌──────────┐   ┌──────────┐   ┌──────────┐
              │SolverWkr │   │SolverWkr │   │SolverWkr │
              │GraphMngr │   │GraphMngr │   │GraphMngr │
              │ updates  │   │ updates  │   │ updates  │
              │ graph    │   │ graph    │   │ graph    │
              │ on event │   │ on event │   │ on event │
              └──────────┘   └──────────┘   └──────────┘

┌──────────────────────────────────────────────────────────────────┐
│                     Derived Data Pipeline                        │
│                                                                  │
│  TychoFeed events ──► ComputationManager                         │
│                          │                                       │
│                          ├─ SpotPriceComputation                 │
│                          ├─ PoolDepthComputation (needs spots)   │
│                          ├─ TokenGasPriceComputation(needs spots)│
│                          │                                       │
│                          ▼                                       │
│                     DerivedData Store ──► broadcast events       │
│                                              │                   │
│                                    ┌─────────┼──────────┐        │
│                                    ▼         ▼          ▼        │
│                              Worker 1  Worker 2  Worker N        │
│                              (update edge weights on graph)      │
└──────────────────────────────────────────────────────────────────┘
```

***

## Components

### 1. API Layer (RouterApi)

**Crate:** `fynd-rpc` **Location:** `fynd-rpc/src/api/`

Actix Web HTTP handlers. Validates requests, delegates to WorkerPoolRouter, returns JSON responses.

**Endpoints:**

* `POST /v1/quote` -- Submit quote requests
* `GET /v1/health` -- Health check (data freshness, derived data readiness, gas-price staleness, pool count)
* `GET /v1/info` -- Instance info (chain ID, router address, Permit2 address)
* `GET /metrics` -- Prometheus metrics (separate server, port 9898 by default)

***

### 2. WorkerPoolRouter

**Crate:** `fynd-core` **Location:** `fynd-core/src/worker_pool_router/`

Orchestrates quote requests across multiple worker pools:

1. Fans out each order to all pools in parallel
2. Manages per-request timeouts with optional early return
3. Refines gas estimates using `estimate_gas_usage` (tycho-execution) before cross-pool ranking — algorithms use a fast naive estimate internally; this step applies a more accurate one that accounts for token transfers and protocol overhead
4. Selects the best solution by refined `amount_out_net_gas`
5. Optionally encodes winning solutions into on-chain transactions (when `EncodingOptions` are provided)
6. Reports failures with error types and metrics

***

### 3. Worker Pool

**Crate:** `fynd-core` **Location:** `fynd-core/src/worker_pool/`

Manages dedicated OS threads for CPU-bound route finding. Each pool has:

* A name and algorithm assignment
* A bounded `TaskQueue` (via `async_channel`)
* N `SolverWorker` instances on separate threads

Pools can use either a built-in algorithm by name (e.g., `"most_liquid"`) or a custom `Algorithm` implementation via `WorkerPoolBuilder::with_algorithm`. Pools are configured via `worker_pools.toml` for built-in algorithms, or programmatically via the builder for custom algorithms. Multiple pools can use the same algorithm with different parameters (e.g., fast 2-hop vs deep 3-hop).

***

### 4. SolverWorker

**Crate:** `fynd-core` **Location:** `fynd-core/src/worker_pool/worker.rs`

Each worker:

1. Initializes a graph from market topology
2. Runs a prioritized `select!` loop: shutdown > market events > derived events > solve tasks
3. Maintains a `ReadinessTracker` for derived data requirements
4. Calls the algorithm's `find_best_route` with the local graph and shared market data

***

### 5. Algorithm Trait

**Crate:** `fynd-core` **Location:** `fynd-core/src/algorithm/`

Pluggable interface for route-finding algorithms:

* Specifies preferred graph type and graph manager via associated types
* Stateless: receives graph as parameter
* Declares derived data requirements (fresh vs stale)

**Built-in algorithms:**

* `MostLiquidAlgorithm` -- BFS path enumeration, depth-weighted scoring, ProtocolSim simulation, gas-adjusted ranking.
* `BellmanFordAlgorithm` -- Bellman-Ford relaxation with gas-aware edge weights, configurable via `AlgorithmConfig.gas_aware`.
* `PathFrankWolfeAlgorithm` -- Frank-Wolfe path-based optimization for multi-hop routing.
* `WaterFillAlgorithm` -- portfolio split router: exhaustive plus bounded amount-aware candidate discovery, then the best net of a single path, a coarse disjoint floor, a refined 256-chunk disjoint split, and a shared-pool fill-and-spill; gas-aware net ranking when derived token gas prices are available.

***

### 6. Encoding

**Crate:** `fynd-core` **Location:** `fynd-core/src/encoding/`

Encodes solved routes into on-chain transactions. When `EncodingOptions` are provided, delegates to `TychoEncoder` to produce ABI-encoded calldata for the appropriate router function (`singleSwap`, `sequentialSwap`, `splitSwap`, and their Permit2/Vault variants). Supports optional `ClientFeeParams` for client fee configuration.

***

### 7. Graph Module

**Crate:** `fynd-core` **Location:** `fynd-core/src/graph/`

Graph management infrastructure:

* `GraphManager` trait: initialize + incremental updates from events
* `PetgraphStableDiGraphManager`: Implementation using `petgraph::StableDiGraph`
* `EdgeWeightUpdaterWithDerived`: Updates edge weights from derived data (pool depths)
* `Path` type: Sequence of edges for route representation

***

### 8. MarketState / MarketData

**Crate:** `fynd-core` **Location:** `fynd-core/src/feed/market_data.rs`

`MarketState` is the single source of truth for all market state. Contains components, simulation states, tokens, gas prices, sync status, and block info. Protected by `Arc<RwLock<>>` (write-preferring). `MarketData` is the cheap-to-clone shared handle used to access it — call `read()` for a base view or `read_labeled(label)` for an overlay-aware view.

Provides `extract_subset_with_overlay()` for creating filtered snapshots that algorithms can use without holding the main lock.

***

### 9. TychoFeed

**Crate:** `fynd-core` **Location:** `fynd-core/src/feed/tycho_feed.rs`

Background task that connects to Tycho's WebSocket API, processes component/state updates, updates `MarketState` (via `MarketData`), and broadcasts `MarketEvent`s. Applies TVL filtering with hysteresis (components are added at `min_tvl` and removed at `min_tvl / tvl_buffer_ratio`), token recency filtering (`traded_n_days_ago`), blocklisting, and token quality filtering.

***

### 10. Derived Data System

**Crate:** `fynd-core` **Location:** `fynd-core/src/derived/`

Pre-computes analytics from raw market data:

* `SpotPriceComputation`: Spot prices for all pool pairs
* `PoolDepthComputation`: Liquidity depth at configured slippage
* `TokenGasPriceComputation`: Token prices relative to gas token

Computations run in dependency order. Workers use `ReadinessTracker` to wait for required data before solving.

***

### 11. Gas Price Fetcher

**Crate:** `fynd-core` **Location:** `fynd-core/src/feed/gas.rs`

Background worker that fetches gas prices from the RPC node. Signaled by TychoFeed after each block update.

***

### 12. Builder

**Crate:** `fynd-rpc` **Location:** `fynd-rpc/src/builder.rs`

`FyndRPCBuilder` assembles the entire system: creates feed, worker pools, computation manager, worker pool router, and HTTP server. `FyndRPC` runs the system and handles graceful shutdown.

***

### 13. CLI Binary

**Crate:** `fynd` **Location:** `src/main.rs` and `src/cli.rs`

Command-line application that parses CLI arguments, sets up observability (tracing, metrics), and uses `FyndRPCBuilder` to run the complete routing service.

***

## Data Flow

### Quote Request Flow

```
Client POST /v1/quote
    │
    ▼
RouterApi (validate)
    │
    ▼
WorkerPoolRouter (fan-out to all pools)
    │
    ├──► Pool A Queue ──► Worker ──► Algorithm ──► Quote
    ├──► Pool B Queue ──► Worker ──► Algorithm ──► Quote
    ├──► Pool C Queue ──► Worker ──► Algorithm ──► Timeout
    │
    ▼
WorkerPoolRouter (select best by amount_out_net_gas)
    │
    ▼ (optional)
Encoder (encode solution into on-chain transaction)
    │
    ▼
JSON Response to Client
```

### Market Update Flow

```
Tycho WebSocket Stream
    │
    ▼
TychoFeed
    ├──► Write MarketState (RwLock write)
    ├──► Broadcast MarketEvent
    │       ├──► Worker 1 GraphManager (update graph)
    │       ├──► Worker 2 GraphManager (update graph)
    │       └──► Worker N GraphManager (update graph)
    └──► Trigger Gas Price Fetcher
    └──► ComputationManager
            ├──► SpotPriceComputation
            ├──► PoolDepthComputation
            ├──► TokenGasPriceComputation
            └──► Broadcast DerivedDataEvent
                    └──► Workers (update edge weights + readiness)
```

***

## Threading Model

```
Actix/Tokio Runtime (async I/O)
├── HTTP Server handlers
├── TychoFeed (WebSocket client)
├── WorkerPoolRouter (async fan-out)
├── Gas Price Fetcher
└── Computation Manager

Worker Pool A (dedicated OS threads)
├── Thread 1: SolverWorker (local graph + single-thread tokio rt)
├── Thread 2: SolverWorker
└── Thread N: SolverWorker

Worker Pool B (dedicated OS threads)
├── Thread 1: SolverWorker
└── Thread M: SolverWorker
```

**Communication channels:**

* HTTP -> WorkerPoolRouter: direct call (same async runtime)
* WorkerPoolRouter -> Workers: `async_channel` per pool (bounded, backpressure)
* Workers -> WorkerPoolRouter: `oneshot` channel (single response)
* TychoFeed -> Workers: `broadcast` channel (MarketEvent)
* ComputationManager -> Workers: `broadcast` channel (DerivedDataEvent)
* All -> MarketState (via MarketData): `Arc<RwLock<>>` (read-heavy)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.fynd.xyz/reference/architecture.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
