> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polaris.supply/llms.txt
> Use this file to discover all available pages before exploring further.

# PropAMMs

> Discover PropAMM datasets, query standardized quote ladders, and compare size-dependent quotes across supported sources.

Use this guide when you want to study size-dependent quotes from proprietary
automated market makers. Polaris stores each PropAMM as a separate source under
`market="ethereum"` and standardizes its observed quote ladders into the same
event shape.

## Representative coverage

This coverage was verified against the public Catalog on `2026-08-27`. It is a
snapshot, not an exhaustive promise of future availability. Use
[Catalog](/reference/catalog) for current bounds and access metadata.

| PropAMM   | Source ID   | Market     | Access  | Source-specific field |
| --------- | ----------- | ---------- | ------- | --------------------- |
| FermiSwap | `fermiswap` | `ethereum` | Preview | Standard ladder       |
| BopAMM    | `bopamm`    | `ethereum` | Preview | Standard ladder       |
| Kipseli   | `kipseli`   | `ethereum` | Preview | Standard ladder       |
| Metric    | `metric`    | `ethereum` | Preview | Includes `pool`       |
| Tempest   | `tempest`   | `ethereum` | Preview | Nullable `oracle`     |
| TaurusFi  | `taurusfi`  | `ethereum` | Preview | Standard ladder       |

All six sources currently share coverage from
`2026-08-18T13:45:40.211Z` through `2026-08-26T00:37:03.400Z`, with a public
cutoff date of `2026-08-25`. Coverage and access can change after this snapshot.

## Understand quote-ladder identity

Use the dataset identity and event fields for different purposes:

| Field                                                   | Meaning                                                                       |
| ------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `source` + `market`                                     | Polaris dataset identity, such as `fermiswap:ethereum`                        |
| `event_id`                                              | Deterministic identity for one observed ladder                                |
| `chain_id` + `token_in` + `token_out`                   | Directed token pair; reversing the tokens creates a different quote direction |
| `router`, `oracle`, and optional `pool`                 | PropAMM contracts associated with the observation                             |
| `block_number`, `transaction_hash`, `transaction_index` | Onchain provenance and ordering context                                       |
| `collector_timestamp`, `collector_sequence`             | Polaris observation time and stored order                                     |

The dataset market is stored in file metadata and intentionally omitted from
individual quote-ladder rows. Retain the `source` and `market` used for the
query alongside any derived records.

## Choose a client method

| Task                           | Python                       | TypeScript                                 | Rust                                                   |
| ------------------------------ | ---------------------------- | ------------------------------------------ | ------------------------------------------------------ |
| Discover sources and bounds    | `catalog(...)`               | `catalog(...)`                             | `catalog(CatalogQuery)`                                |
| Read typed quote ladders       | `propamm_quote_ladders(...)` | Use `events(...)` and filter `data.series` | Use `events(HistoricalQuery)` and filter `data.series` |
| Read mixed standardized events | `events(...)`                | `events(...)`                              | `events(HistoricalQuery)`                              |
| Replay stored events           | `replay(...)`                | `replay(...)`                              | `replay(ReplayQuery)`                                  |
| Inspect venue-native payloads  | `raw(...)`                   | Not exposed                                | `raw(RawQuery)`                                        |

Python provides the dedicated typed method. In TypeScript and Rust, retain only
standardized records where `data.series == "quote_ladder"` when you use the
generic event surface.

## Query one bounded range

Start with one source and derive a short accessible range from its Catalog row.
Quote-ladder events can be large, so iterate them directly unless you need the
complete range in memory.

```python theme={null}
from datetime import timedelta

import pandas as pd
from polaris_data import PolarisClient

source = "fermiswap"
market = "ethereum"

with PolarisClient() as client:
    catalog = client.catalog(source=source, market=market)
    if not catalog["markets"]:
        raise ValueError(f"No Catalog row for {source}:{market}")

    coverage = catalog["markets"][0]
    coverage_start = pd.Timestamp(coverage["start"])
    coverage_end = pd.Timestamp(coverage["end"])
    public_cutoff = coverage["access"].get("public_cutoff_date")

    if public_cutoff:
        public_day = pd.Timestamp(public_cutoff, tz="UTC")
        start = max(coverage_start, public_day)
        end = min(coverage_end, start + timedelta(hours=1))
    else:
        end = coverage_end
        start = max(coverage_start, end - timedelta(hours=1))

    ladders = list(
        client.propamm_quote_ladders(
            source=source,
            market=market,
            from_=start.to_pydatetime(),
            to=end.to_pydatetime(),
            allow_gaps=True,
        )
    )

print(f"Loaded {len(ladders):,} quote ladders")
```

Use `allow_gaps=True` only when partial coverage is acceptable for the
analysis. Keep the default when continuity is required.

## Normalize quote amounts

`amount_in` and `amount_out` are decimal strings representing onchain integer
amounts. Convert them with the corresponding token decimals and Python's
`Decimal`; binary floating-point values can lose precision for uint256-sized
amounts.

```python theme={null}
from decimal import Decimal

records = []
seen_event_ids = set()

for event in sorted(
    ladders,
    key=lambda row: (
        row.get("collector_timestamp", 0),
        row.get("collector_sequence", 0),
    ),
):
    values = event["data"]["values"]
    event_id = values["event_id"]
    if event_id in seen_event_ids:
        continue
    seen_event_ids.add(event_id)

    input_scale = Decimal(10) ** values["token_in_decimals"]
    output_scale = Decimal(10) ** values["token_out_decimals"]

    for quote_index, quote in enumerate(values["quotes"]):
        amount_in = Decimal(quote["amount_in"]) / input_scale
        amount_out = Decimal(quote["amount_out"]) / output_scale
        if amount_in <= 0:
            continue

        records.append(
            {
                "timestamp": pd.to_datetime(
                    event["collector_timestamp"], unit="ms", utc=True
                ),
                "source": event["source"],
                "market": market,
                "event_id": event_id,
                "block_number": values["block_number"],
                "token_in": values["token_in"],
                "token_out": values["token_out"],
                "pool": values.get("pool"),
                "quote_index": quote_index,
                "amount_in": amount_in,
                "amount_out": amount_out,
                "output_per_input": amount_out / amount_in,
            }
        )

quotes = pd.DataFrame.from_records(records)
print(quotes.head())
```

Deduplicate complete ladders by `event_id`, not individual quote points. Each
event contains multiple sizes that belong to the same observed curve.

## Inspect price impact across a ladder

Select one event and compare its output-per-input rate with the smallest quoted
size. A negative rate change means the larger quote returned less output per
unit of input.

```python theme={null}
if quotes.empty:
    print("No quote points in the selected interval.")
else:
    latest_event_id = quotes.sort_values(
        ["timestamp", "block_number", "quote_index"]
    ).iloc[-1]["event_id"]
    curve = (
        quotes.loc[quotes["event_id"].eq(latest_event_id)]
        .sort_values("amount_in")
        .copy()
    )

    reference_rate = curve.iloc[0]["output_per_input"]
    curve["rate_change_bps"] = (
        curve["output_per_input"] / reference_rate - Decimal(1)
    ) * Decimal(10_000)

    print(
        curve[
            [
                "token_in",
                "token_out",
                "amount_in",
                "amount_out",
                "output_per_input",
                "rate_change_bps",
            ]
        ]
    )
```

<Warning>
  A recorded quote is an observation, not proof that the same amount was
  executable later. Account for block timing, gas, transaction ordering, token
  fees, and venue rules before treating a quote as a realizable fill.
</Warning>

## Compare PropAMMs safely

* Compare the same `chain_id`, directed token pair, and normalized token amounts.
* Keep Metric pools separate; two pools can produce different curves for the same pair.
* Align observations by block or a documented maximum time difference instead of treating the latest rows as simultaneous.
* Preserve `block_hash`, `parent_hash`, and transaction fields when canonical-chain provenance matters.
* Compare common input sizes. Do not assume that quote arrays from different sources use matching indices or amounts.
* Keep `Decimal` values through calculations and round only for presentation.

Only `quote_ladder` records are standardized for these sources. Heartbeats,
replay telemetry, state updates, and failures remain venue-native records.

## Related documentation

* [PropAMM Competitor Analysis](/guides/propamm-competitor-analysis) for aligned cross-source quote edge and curve-impact comparisons
* [PropAMM Quote Ladders](/schemas/propamm-quote-ladders) for the complete method signature and event fields
* [Catalog](/reference/catalog) for current source, bounds, and access metadata
* [Event envelope](/concepts/event-envelope) for timestamps and stored ordering
* [Snapshots](/reference/snapshots) for historical file discovery and data flow
* [Intents and RFQs](/guides/intents-and-rfqs) for request, quote, and settlement lifecycle analysis
