DEX: Pool list — canonical / factory vs indexer context for N pairs #112

Closed
opened 2026-04-23 03:19:15 +00:00 by PlasticDigits · 8 comments
PlasticDigits commented 2026-04-23 03:19:15 +00:00 (Migrated from gitlab.com)

Problem

Liquidity Pools (/pools or pool route) shows ~117 pairs (and “indexed tokens”) from the indexer (getPairs total in PoolPage), but there is no “canonical” indication of how that list relates to the on-chain factory (e.g. getAllPairsPaginated in LimitOrdersPage / SwapPage). Users cannot tell if a row is factory-registered only, full indexer row, or default featured vs long tail.

Current code (reference)

  • frontend-dapp/src/pages/PoolPage.tsx
    • getPairs from frontend-dapp/src/services/indexer/client.ts with sort/filter/pagination (~556–567).
    • Header: {total} pair(s) + optional {indexerTokensQuery.data.length} indexed tokens (~591–597).
    • PoolCard uses verifyPairInFactory for an “Unverified” badge when factory check fails (~70–75, 270–280).
  • frontend-dapp/src/pages/SwapPage.tsx — getAllPairsPaginated for router token graph.
  • Types: IndexerPair vs PairInfo in frontend-dapp/src/types/index.ts (indexerPairToPairInfo).

Work to do (maintainability-oriented)

  1. Clarify data sources in UI

    • Add concise copy: e.g. “Pairs indexed for analytics / routing; verify marks mean …” and link to docs if needed.
    • Show whether the list is indexer-sorted vs factory order (today: indexer API).
  2. Canonical / featured marking (choose product rule)

    • Options: badge “In router graph” if pair exists in getAllPairsPaginated result; or “Factory verified” if verifyPairInFactory passes; or highlight pairs present in a governance/allowlist if one exists in config.
    • Centralize in one helper: getPairListBadges({ indexerPair, factoryPairsSet, verifyResult }) to keep PoolCard thin.
  3. Performance

    • If comparing to full factory list, avoid O(n²): fetch factory pairs once per page load (React Query) and use a Set of addresses.
  4. Empty / drift states

    • If indexer total > factory count (or vice versa), a one-line explainer in the page header to reduce support questions.
  5. Tests

    • PoolPage.test.tsx: mock indexer + optional factory set; expect badges.

Acceptance criteria

  • Header (or tooltips) explain what “117 pairs” means vs chain.
  • At least one machine-enforced badge or filter for “same as factory” / “router-known” (per agreed product rule).
  • No N+1 chain calls per card; document query strategy.
  • Tests for badge logic.
## Problem **Liquidity Pools** (`/pools` or pool route) shows **~117 pairs** (and “indexed tokens”) from the **indexer** (`getPairs` total in `PoolPage`), but there is **no “canonical” indication** of how that list relates to the **on-chain factory** (e.g. `getAllPairsPaginated` in `LimitOrdersPage` / `SwapPage`). Users cannot tell if a row is **factory-registered only**, **full indexer row**, or **default featured** vs long tail. ## Current code (reference) - `frontend-dapp/src/pages/PoolPage.tsx` - `getPairs` from `frontend-dapp/src/services/indexer/client.ts` with sort/filter/pagination (~556–567). - Header: `{total} pair(s)` + optional `{indexerTokensQuery.data.length} indexed tokens` (~591–597). - `PoolCard` uses `verifyPairInFactory` for an “Unverified” badge when factory check fails (~70–75, 270–280). - `frontend-dapp/src/pages/SwapPage.tsx` — `getAllPairsPaginated` for router token graph. - Types: `IndexerPair` vs `PairInfo` in `frontend-dapp/src/types/index.ts` (`indexerPairToPairInfo`). ## Work to do (maintainability-oriented) 1. **Clarify data sources in UI** - Add concise copy: e.g. “Pairs indexed for analytics / routing; verify marks mean …” and link to docs if needed. - Show whether the list is **indexer-sorted** vs **factory order** (today: indexer API). 2. **Canonical / featured marking (choose product rule)** - Options: badge “In router graph” if pair exists in `getAllPairsPaginated` result; or “Factory verified” if `verifyPairInFactory` passes; or highlight pairs present in a **governance/allowlist** if one exists in config. - Centralize in one helper: `getPairListBadges({ indexerPair, factoryPairsSet, verifyResult })` to keep `PoolCard` thin. 3. **Performance** - If comparing to full factory list, avoid O(n²): fetch factory pairs once per page load (React Query) and use a `Set` of addresses. 4. **Empty / drift states** - If indexer total > factory count (or vice versa), a one-line **explainer** in the page header to reduce support questions. 5. **Tests** - `PoolPage.test.tsx`: mock indexer + optional factory set; expect badges. ## Acceptance criteria - [ ] Header (or tooltips) explain what “117 pairs” means vs chain. - [ ] At least one **machine-enforced** badge or filter for “same as factory” / “router-known” (per agreed product rule). - [ ] No N+1 chain calls per card; document query strategy. - [ ] Tests for badge logic.
PlasticDigits commented 2026-04-23 03:19:15 +00:00 (Migrated from gitlab.com)

assigned to @PlasticDigits

assigned to @PlasticDigits
PlasticDigits commented 2026-04-23 06:06:45 +00:00 (Migrated from gitlab.com)

mentioned in commit 55dca5ec89

mentioned in commit 55dca5ec8993968a42acd208b4813af364acd124
PlasticDigits commented 2026-04-23 06:06:58 +00:00 (Migrated from gitlab.com)

Ready for verification (merged to main @ 55dca5e)

@brouie — please verify the pool list UX and behavior when you have a moment. Issue left open per process.

What changed

  • Copy & context: Header explains that the pair count and sort order come from the indexer API, not factory enumeration; link to docs/frontend.md#liquidity-pools-list-indexer-vs-factory.
  • Single factory fetch: One React Query loads up to FACTORY_PAIRS_MAX_FOR_POOL_LIST (10k) factory pairs; Set membership for O(1) per row (no per-card verifyPairInFactory).
  • Badges: In router (factory) when the pair contract is in that set (same graph as Swap routing); Indexer only otherwise.
  • Drift: If indexer total ≠ factory list length, a one-line status note explains possible lag/cap.
  • Filter: Checkbox Router-known (factory) only on this page filters the current indexer page to factory rows.
  • Tests: pairListBadges.test.ts + extended PoolPage.test.tsx; vitest.config sets VITE_FACTORY_ADDRESS for tests that need factory-gated queries.
  • Docs: docs/frontend.md, docs/indexer-invariants.md, docs/README.md; cross-links to glab#112 and Cursor split to PRs / babysit skills (optional maintainer workflow).

Checklist for you

  • Open /pool: copy matches your expectations; Data sources (docs) opens the right anchor.
  • Header shows indexer total and on-chain (factory, router graph) when LCD/factory is reachable.
  • Rows show In router (factory) vs Indexer only; tooltips read sensibly.
  • When indexer count and factory count differ, the drift line appears and is accurate enough for support.
  • Toggle Router-known (factory) only on this page — only matching rows on the current page; empty state if none.
  • No obvious performance regression (one factory pagination, not N queries per card).
  • cd frontend-dapp && npm run test:unit passes locally if you pull main.

Skills / workflow: Optional: Cursor skills split-to-prs, babysit for follow-up PRs and CI (also mentioned in docs/frontend.md).

## Ready for verification (merged to `main` @ 55dca5e) @brouie — please verify the pool list UX and behavior when you have a moment. Issue left open per process. ### What changed - **Copy & context:** Header explains that the pair count and sort order come from the **indexer** API, not factory enumeration; link to [docs/frontend.md#liquidity-pools-list-indexer-vs-factory](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/frontend.md#liquidity-pools-list-indexer-vs-factory). - **Single factory fetch:** One React Query loads up to `FACTORY_PAIRS_MAX_FOR_POOL_LIST` (10k) factory pairs; `Set` membership for **O(1)** per row (no per-card `verifyPairInFactory`). - **Badges:** **In router (factory)** when the pair contract is in that set (same graph as Swap routing); **Indexer only** otherwise. - **Drift:** If indexer total ≠ factory list length, a one-line status note explains possible lag/cap. - **Filter:** Checkbox **Router-known (factory) only on this page** filters the current indexer page to factory rows. - **Tests:** `pairListBadges.test.ts` + extended `PoolPage.test.tsx`; `vitest.config` sets `VITE_FACTORY_ADDRESS` for tests that need factory-gated queries. - **Docs:** `docs/frontend.md`, `docs/indexer-invariants.md`, `docs/README.md`; cross-links to glab#112 and Cursor **split to PRs** / **babysit** skills (optional maintainer workflow). ### Checklist for you - [ ] Open `/pool`: copy matches your expectations; **Data sources (docs)** opens the right anchor. - [ ] Header shows **indexer total** and **on-chain (factory, router graph)** when LCD/factory is reachable. - [ ] Rows show **In router (factory)** vs **Indexer only**; tooltips read sensibly. - [ ] When indexer count and factory count differ, the **drift** line appears and is accurate enough for support. - [ ] Toggle **Router-known (factory) only on this page** — only matching rows on the current page; empty state if none. - [ ] No obvious performance regression (one factory pagination, not N queries per card). - [ ] `cd frontend-dapp && npm run test:unit` passes locally if you pull `main`. **Skills / workflow:** Optional: [Cursor skills](https://docs.cursor.com/context/skills) `split-to-prs`, `babysit` for follow-up PRs and CI (also mentioned in `docs/frontend.md`).
Brouie commented 2026-04-24 00:48:52 +00:00 (Migrated from gitlab.com)

@PlasticDigits verified on a428ba9 / 55dca5e.

Vitest baseline: 266/266 passing (up from 238 yesterday). New pairListBadges.test.ts 3/3.

Code review:

  • getPairListBadges in utils/pairListBadges.ts — clean O(1) Set lookup per row, single paginated factory fetch of up to 10k pairs via FACTORY_PAIRS_MAX_FOR_POOL_LIST constant
  • PoolPage.tsx line 804-805: single shared factoryPairAddresses query keyed on the max constant; line 1030: per-row badge call reuses the Set
  • Badge render at line 345-365: 'In router (factory)' (cyan) vs 'Indexer only' (red) with hover tooltip text explaining the distinction
  • Directly addresses the #10 smoke finding about 'multiple same-token pairs with no canonical indication' — now cleanly answered per row

Good UX resolution. Closing as verified.

@PlasticDigits verified on `a428ba9` / `55dca5e`. Vitest baseline: 266/266 passing (up from 238 yesterday). New `pairListBadges.test.ts` 3/3. Code review: - `getPairListBadges` in `utils/pairListBadges.ts` — clean O(1) Set lookup per row, single paginated factory fetch of up to 10k pairs via `FACTORY_PAIRS_MAX_FOR_POOL_LIST` constant - `PoolPage.tsx` line 804-805: single shared factoryPairAddresses query keyed on the max constant; line 1030: per-row badge call reuses the Set - Badge render at line 345-365: 'In router (factory)' (cyan) vs 'Indexer only' (red) with hover tooltip text explaining the distinction - Directly addresses the #10 smoke finding about 'multiple same-token pairs with no canonical indication' — now cleanly answered per row Good UX resolution. Closing as verified.
Brouie (Migrated from gitlab.com) closed this issue 2026-04-24 00:48:54 +00:00
Brouie commented 2026-04-24 07:47:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #114

mentioned in issue #114
Brouie commented 2026-05-05 23:55:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #133

mentioned in issue #133
PlasticDigits commented 2026-08-17 10:26:07 +00:00 (Migrated from gitlab.com)

mentioned in issue #547

mentioned in issue #547
PlasticDigits commented 2026-08-17 10:26:10 +00:00 (Migrated from gitlab.com)

marked as related to #547

marked as related to #547
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#112
No description provided.