# LP dashboard

> A pools screener, a pool page, a range planner and a positions view for liquidity providers on Arc.

Source: https://getchord.xyz/docs/recipes/lp-dashboard/

**Goal**: the liquidity side of a trading app — where the fees are, whether a pool is honest, what range to take, and how open positions are doing.

## Headline strip

`GET /lp/overview?chain=5042` — fees paid to LPs in 24 hours, the best real yield (≥ 25 traders, not suspect), liquidity added and removed, volume, TVL and providers over pools with ≥ $10k TVL, the six hottest pools by fees (`hot`) and the three biggest net inflows (`inflow`). One call, memoised 30 s.

## Pools screener

```ts
const { pools, total, hidden } = await fetch(`${A}/lp/pools?chain=5042&sort=fee_tvl&interval=24h&limit=50`).then((r) => r.json());
```

Columns: pair (`token0` / `token1` with logos and `impostor` flags), venue (`dex`), fee tier (`feeBps`), TVL, volume and fees for the interval, `feeTvlPct`, `aprPct`, traders (`wallets24h`), LP net flow (`lpAdd24h − lpRemove24h`), providers, age (`createdTs`), `score`.

- Sorts: `fee_tvl` · `vol_24h` · `vol_1h` · `tvl` · `fees_24h` · `first_seen` · `lp_net_24h` · `trades_24h` · `score`.
- Filters: `quote=USDC` (anchor), `dex=uniswap_v4`, `search=argus`, `minTvl=`, `small=1` (under $10k), `flagged=1` (show suspect pools, greyed).
- `hidden` is how many rows the filters removed — show it; users ask.
- `lpAccess: "hooked"` means a V4 hook can refuse adds. Do not offer a mint button on those.

## Pool page

`GET /lp/pools/{pool}?chain=5042` returns the row plus:

- `hourly` — 7 days of volume, trades and price for the chart.
- `topLps` — providers over 7 days with net dollars.
- `health` — the score, its six parts and `reasons` in plain English.
- `launch` — who launched it, the launcher's share of all liquidity ever added, and when it last pulled.
- `mint` — what a wallet needs to add liquidity: manager, pool key, Permit2, tick spacing, native flag.

`GET /lp/pools/{pool}/positions?chain=5042&limit=20` lists the open positions in the pool, largest first, valued live. `GET /lp/events?chain=5042&pool={pool}&minUsd=1000` is the add/remove tape.

## Range planner

```ts
const plan = await fetch(`${A}/lp/plan?chain=5042&token=${addr}&amountUsd=1000&days=7`).then((r) => r.json());
```

`bands.profiles` gives tight, balanced and wide ranges from the token's own volatility with the share of the last seven days inside each; `sims[]` backtests each against holding — fees, impermanent loss, exits, net versus hold, capital efficiency. Draw `bands.histogram` (hours the price spent in each bucket) behind the ranges. `young: true` means fewer than two days of candles: say so instead of drawing bands. For a user-drawn range call `GET /lp/simulate` with `lower` and `upper`.

## Positions

`GET /lp/positions?chain=5042&owner={wallet}&status=open` — each position with `valueUsd`, `uncollectedUsd`, `inRange`, `edgePct` (distance to the nearest edge), `pnlUsd` and `ageHours`; `summary` for the header. `GET /lp/position/{chain}/{manager}/{id}` opens one with its events and a hold-instead comparison. Closed positions page with `status=closed&limit=25&offset=25`, newest first, and `pool=` keeps one pool.

Alerts: `POST /lp/watch { chain, wallet }` turns on out-of-range, fee-bar and drain alerts and returns a Telegram deep link; `GET /lp/watch?chain=&wallet=` is the inbox.

## Leaderboard

`GET /lp/leaderboard?chain=5042&sort=profit&limit=48` — providers by profit (all time, or `profit_7d` / `profit_30d`), win rate, fees, EV, age, invested, monthly profit or last activity, with inclusive filters (`minPositions`, `minWinRate`, `minEv`, `lastActiveDays`, …) and the last seven days of profit per wallet for a sparkline. Wallets whose profit came from the token's price rather than fees are left out and counted in `hidden`; `all=1` keeps them.

## One wallet, one pool's providers

`GET /lp/wallet/{address}?chain=5042` is the page behind a leaderboard row: the same figures for that wallet whether it is ranked or not (`summary`), one row per UTC day on which a position ended with the profit and the fees that landed on it (`history`: draw it as bars with a running total, or as a calendar), and the pools it provided to. `unscored` says how many of its positions the figures leave out and why.

`GET /lp/pools/{pool}/lps?chain=5042` ranks a pool's providers by what they made there (profit, fees, positions, average age, win rate), where the pool's `topLps` ranks them by how much they moved.

## Cadence

Overview and screener every 30 s, pool page every 30 s, positions every 60 s. All are cached server-side at those intervals, so faster polling returns the same bytes.
