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

# Takers

> Audience: searchers, solvers, and aggregators routing flow or arbitrage paths through pAMM liquidity in Titan blocks.

### Multi-candidate bundle submission

Send us N candidate bundles for the same trade, each routing differently. At build time we evaluate every candidate against live state, including the freshest streamed quote from every pAMM, and include whichever gives the best outcome.

* Construct your normal path through CFMM liquidity.
* Construct additional variants where one or more hops route through pAMMs.
* Submit all variants. We evaluate each against current state at build time and re-evaluate on every pAMM quote update until inclusion.

Use the same bundle submission path you already use.

### pAMM state stream

Takers can consume a JSON stream of pAMM state overrides for makers that opt in to publishing their state. The stream is intended for searchers, solvers, and dex aggregators that want fresher routing inputs for pAMM liquidity before submitting candidate bundles.

The stream is maker opt-in. Makers choose whether to publish state, and configure the update thresholds and delay applied before state is emitted.

Some maker streams may require permissioned access. For example, a maker may only allow whitelisted takers such as dex aggregators to consume their stream. Please reach out if there are pAMM quotes you want access to that are not currently available.

### pAMM stream addresses

Current expected top-level stream addresses:

| Protocol  | Top-level stream address                     | Simulator call target                                        | Oracle touched in `state_override`           |
| --------- | -------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------- |
| FermiSwap | `0xb1076fe3ab5e28005c7c323bac5ac06a680d452e` | `quote(...)` on `0x5979458912F80B96d30D4220af8E2e4925A33320` | `0xb1076fe3ab5e28005c7c323bac5ac06a680d452e` |
| Kipseli   | `0x5cdbe59400cc2efdcc2b54acca4a99fe00dd588c` | `quote(...)` on `0x71e790dd841c8A9061487cb3E78C288E75cE0B3d` | `0x5cdbe59400cc2efdcc2b54acca4a99fe00dd588`  |
| bopAMM    | `0x160141a205f5ddcf096ba3f48b7ed21eb52c62ea` | `quote(...)` on `0xdb13ad0fcd134e9c48f2fdaea8f6751a0f5349ca` | `0xBC60639345dFa607d73b74e88C2d54D8B8AD7Cc3` |

The public no-auth stream currently exposes FermiSwap, Kipseli and bopAMM.

#### Endpoints

| Region         | WebSocket endpoint                                   | JSON-RPC endpoint                 |
| -------------- | ---------------------------------------------------- | --------------------------------- |
| eu-central-1   | `wss://eu.rpc.titanbuilder.xyz/ws/pamm_quote_stream` | `https://eu.rpc.titanbuilder.xyz` |
| ap-northeast-1 | `wss://ap.rpc.titanbuilder.xyz/ws/pamm_quote_stream` | `https://ap.rpc.titanbuilder.xyz` |
| us-east-1      | `wss://us.rpc.titanbuilder.xyz/ws/pamm_quote_stream` | `https://us.rpc.titanbuilder.xyz` |

#### Format

Each WebSocket message is JSON. Every other top-level key is a pAMM quote stream address. The value is an object with a `stateOverride` field.

```json
{
  "slot": 14285824,
  "blockNumber": 25051224,
  "timestamp": 1778253913749564761,
  "0xb1076fe3ab5e28005c7c323bac5ac06a680d452e": {
    "stateOverride": {
      "0x1038c87766e36d1925889e6f26d10e0012d50fed": {
        "balance": "0x0",
        "nonce": "0x1",
        "stateDiff": {
          "0x156b1d71de08fed89d0fce38008e2b9d03a8998077e394b20597ef3d148f5ebc": "0x000000000000000000000000000000000000000000000000000000017e405801"
        }
      }
    }
  }
}

```

`stateOverride` uses the same structure as the Ethereum eth\_call State Override Set.

The keys inside `stateOverride` are Ethereum account addresses. Each account override may include:

* balance&#x20;
* nonce&#x20;
* code&#x20;
* state&#x20;
* stateDiff

`stateDiff` maps storage slot keys to overridden storage values.

The object can be passed directly as the third parameter to `eth_call` or `eth_simulateV1`.

If a taker has access to multiple pAMM feeds, Titan merges all maker updates into a single flat `stateOverride` object keyed by account address.

#### Latest state over JSON-RPC

Takers that do not want to maintain a WebSocket connection can request the latest flattened pAMM state view over JSON-RPC.

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "titan_getPammStateOverrides",
  "params": []
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "blockNumber": "0x16f3a10",
    ...
  }
}
```

#### Example (Python)

```python
import asyncio
import json
import urllib.request
import websockets

WS_URI = "wss://eu.rpc.titanbuilder.xyz/ws/pamm_quote_stream"
RPC_URL = "https://eu.rpc.titanbuilder.xyz/"


def get_pamm_state_overrides():
    body = json.dumps({
        "jsonrpc": "2.0",
        "id": 1,
        "method": "titan_getPammStateOverrides",
        "params": [],
    }).encode()
    req = urllib.request.Request(
        RPC_URL, data=body, headers={"Content-Type": "application/json"}
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        return json.loads(resp.read())["result"]


async def main():
    # One-shot snapshot.
    snapshot = get_pamm_state_overrides()
    print(int(snapshot["blockNumber"], 16), snapshot["stateOverrides"])
    
    # Live updates.
    async with websockets.connect(WS_URI) as ws:
        async for message in ws:
            update = json.loads(message)
            block_number = int(update["block_number"])
            state_overrides = update["state_override"]
            print(block_number, state_overrides)


asyncio.run(main())
```

### pAMM price level

Takers can also consume a live pAMM price level stream. Unlike the state override stream, this stream is already quoted by Titan and grouped per pAMM.

Order book levels are available in two variants. `Simulated` quotes are derived from EVM simulations using synthesized taker transactions. The quoted sizes are distributed according to a geometric progression to provide coverage across a range of trade sizes.

To improve quote granularity, we also generate `Interpolated` levels between the simulated quotes. These intermediate levels are computed using linear spline interpolation, providing a more convenient set of quote sizes at the cost of a small approximation error.

Each message is a complete snapshot. Consumers should keep the newest message and treat older messages as superseded.

Endpoints are the same as pAMM state stream just use the `/ws/pamm_price_levels` path.

**Latest price levels over websocket**

Each WebSocket message is JSON. The pamms array contains one ladder per pAMM.

```json
{
  "slot": 14581462,
  "blockNumber": 25345763,
  "timestamp": 1781801564588230787,
  "pamms": [
    {
      "pamm": "0x5979458912f80b96d30d4220af8e2e4925a33320",
      "pairs": [
        {
          "tokenIn": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
          "tokenOut": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
          "orderBook": [
            {
              "amountIn": "0x989680",
              "amountOut": "0x174b67393",
              "variant": "Simulated"
            },
            {
              "amountIn": "0xaa810a",
              "amountOut": "0x1a0781260",
              "variant": "Interpolated"
            },
            ...
          ],
        },
        ...
      ],
    },
    ...
  ]
}
```

**You can also query latest price levels over JSON-RPC**

Request:

```json
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "titan_getPammPriceLevels",
    "params": []
}
```

Both methods return the same response shape:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "slot": 14581462,
    ...
  }
}
```

### pAMM quote helpers

Titan exposes two JSON-RPC quote helpers backed by the latest pAMM price level snapshot.

titan\_getPammQuoteVenue mirrors the LambdaClass [router](https://github.com/lambdaclass/propamm-router-contracts/blob/main/src/PropAMMRouter.sol) style `quoteVenueV1` and `quoteV1` flow.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "titan_getPammQuoteVenue",
  "params": [
    "0xVenue",
    "0xTokenIn",
    "0xTokenOut",
    "0xAmountIn"
  ]
}
```

`titan_getPammQuote` scans all pAMMs in the latest snapshot and returns the best quote plus the pAMM that produced it.

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "titan_getPammQuote",
  "params": [
    "0xTokenIn",
    "0xTokenOut",
    "0xAmountIn"
  ]
}
```

Both methods return the same response shape:

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tokenIn": "0x..12",
    "tokenOut": "0x..34",
    "amountIn": "0xde0b6b3a7640000",
    "amountOut": "0xd09dc300",
    "pamm": "0x..56",
    "router": "0x..78",
    "blockNumber": 25051224,
    "slot": 14285824,
    "timestamp": 1778253913749564761
  }
}
```

### On-chain routing

On-chain routing is another integration path for pAMM liquidity. This is not a separate Titan endpoint, but a router or solver-side pattern that can be used alongside the bundle flow above.

The idea is to move route selection into the execution transaction. Instead of submitting a single pre-selected path, the transaction could carry multiple candidates per hop. For a route from asset A to asset B to asset C, the A → B hop could have several candidate venues, and the B → C hop could have several candidate venues. Some candidates may route through standard AMM liquidity, while others may route through pAMMs.

Because execution happens onchain, the router evaluates the candidate set against the exact execution state and selects the best valid combination. This is especially attractive for pAMM routing because quote state can change between path construction and inclusion. If a maker update lands earlier in the same block, the router sees the updated state when the taker transaction executes.
