Skip to main content
Pharos

DEX Liquidity

DEX Liquidity Score methodology for stablecoins: pool discovery, depth scoring, durability, pair diversity, cross-validation, and risk bands.

Agent navigation — Public methodology: DEX Liquidity Score · Measured volume availability · Discovery Cron · DEX Price Cross-Validation. Operator details have one owner in the implementation appendix.

Methodology Versioning

  • Current methodology version: <!-- GENERATED-START: methodology-version-liquidity-score -->v6.95<!-- GENERATED-END: methodology-version-liquidity-score -->
  • TVL-basis breaks: a liquidity release that changes how retained TVL is measured (not just weighting or volume admission) must also append its version to LIQUIDITY_TVL_BASIS_BREAK_VERSIONS in shared/lib/dex-liquidity-evidence.ts, which is append-only. The 30-day stability series never mix epochs across a listed break (see Basis homogeneity under Durability Sub-Component Weights); the source owns the current break list.

Reviewed execution targets require exact retained-pool identity, current independent references and quote-time factory/token/fee, freshness and execution proof. Supplemental discovery or configured targets alone establish neither zero liquidity nor execution capacity. Component weights, resource budgets and retained-TVL measurement are separate contracts.

The public changelog owns release history. Fixed-clock route comparison and owner review, fresh provider/quote observations and separate production resource evidence remain release prerequisites, not completed-equivalence or health claims.

PKT-5 no-admission disclosure: the conditional review activates no new family. V4 Base/BSC/Arbitrum/Polygon/Tempo, HyperSwap, Kodiak and native pending profiles remain score-ineligible; Meteora's writer stays stopped. Repeated mature observations, complete fork/drift/replay proof and native program/dependency closure with independent execution are still missing; HyperSwap also has five unresolved pinned execution-output mismatches. Reviewed addresses, local quotes, elapsed time or target presence waive none of these gates. The owning disposition changes no runtime admission, cadence, methodology version or resource budget.

DEX Liquidity Score

Hourly full publication admits recovered quotes at the next :16 instead of waiting for an even hour. Source requests and the :46 reuse path keep their existing cadence. Full generation and active-target writes run every hour; each uses the existing bounded persistence buffers and retention. Public history remains one reusable daily snapshot, not an hourly series. The reviewed DEX evidence maximum age remains four hours (DEX_LIQUIDITY_EVIDENCE_MAX_AGE_SEC), and measured-history high confidence remains three hours; operational cadence changes do not tighten those scoring bounds.

Published chain-label casing

Persisted DEX rows use the canonical internal chain id from canonicalExitRouteChain() (lowercase registry/alias keys). The chain_tvl_json keys, PoolEntry.chain, and top_pools_json chain values therefore use one canonical casing per chain; aggregate stages must not re-lowercase or substitute display names. Presentation adapters map those ids to CHAIN_META display names only.

Coverage normalization quarantines invalid class/confidence evidence per row as invalid-coverage-evidence, distinct from unobserved markets; it cannot supply a rating or trend. Trend-baseline confidence remains 0.50, durability 0.75, and both-null legacy coverage uses its conservative default. The /liquidity/ leaderboard keeps NR null and places NR rows after every rated row on every column and in either direction, including after observed zero.

In the full /api/dex-liquidity map (not the /api/dex-liquidity-table projection or history), each row carries liquidityScoreUnavailableReason: for a null liquidityScore, a machine code from whoever nulled it (LiquidityScoreUnavailableReasonSchema in shared/types/market.ts): the DEC-19 activity outcome from resolveVolumeActivityComponent (activity-coverage-below-floor, activity-missing, activity-stale, activity-completeness-unknown), no-retained-pools for a placeholder row, or invalid-coverage-evidence when the publisher quarantines the row. The producer records its code in score_components_json (no schema migration); rows scored before the field existed publish null, and consumers show plain NR rather than infer a cause. Rated rows publish null.

External source construction runs hourly at :10. Both :16 and :46 use the same exact source-slot state machine: writing waits; ready scores and publishes; failed or missing terminal output can recover; consumed reuses the accepted generation without rewriting it. An exact accepted publication also prevents replay if the best-effort consumed marker failed. Only successful publication closes the slot; a guard-rejected candidate stays ready. A live producer is never overwritten; readiness remains 90 seconds from the original scheduled delivery time (logical slot time only when no scheduled time was supplied). At that deadline a live source lease yields nonproductive skipped_neutral scoring-stage-producer-running, without renewing freshness. Preparation independently verifies the last accepted generation under its unchanged evidence budget. Turnover follows actual publication, including late :46 publication, never a wait or reuse. Heavy has GRAPH_API_KEY and can reconstruct a missing/terminal stage inline under the source lease and inherited deadline; absent credentials still fail preflight rather than publish a reduced graph. Targets stay private until guarded liquidity publication commits.

ComponentWeightSourceHow Computed
TVL Depth<!-- GENERATED-START: liquidity-tvlDepth-weight -->30%<!-- GENERATED-END: liquidity-tvlDepth-weight -->DeFiLlama YieldsRatio-based log-scale: 35 * log10(depthRatio / 0.0007) where depthRatio = effectiveTvl / circulatingUsd. ~0.5%->30, ~1.5%->47, ~6%->67, ~14%->80, ~25%+->90+. Falls back to 35 * log10(tvl / 700_000) (parity with ratio formula at a $1B implied reference mcap) when circulatingUsd is unavailable.
Volume Activity<!-- GENERATED-START: liquidity-volumeActivity-weight -->20%<!-- GENERATED-END: liquidity-volumeActivity-weight -->DeFiLlama YieldsLog-scale V/T ratio: 38 * (log10(vtRatio) + 3). ~0.1%->0, ~0.3%->18, ~3.5%->59, ~19%->86, ~43%+->100. Admitted 24h volume / admitted TVL; rated when the window is complete or admitted pools cover ≥ 50% of retained TVL, otherwise null and the composite is NR (DEC-19, v6.9)
Pool Quality<!-- GENERATED-START: liquidity-poolQuality-weight -->20%<!-- GENERATED-END: liquidity-poolQuality-weight -->Curve API + DeFiLlamaVenue quality retention ratio: (qualityAdjustedTvl/totalTvlUsd - 0.15) / 0.65 * 100, rescaled from 15–80% range to 0–100 (see below). The scoring component uses mechanism and balance-health retention; pair quality affects effective TVL and pool stress.
Durability<!-- GENERATED-START: liquidity-durability-weight -->20%<!-- GENERATED-END: liquidity-durability-weight -->DeFiLlama Yields + History<!-- GENERATED-START: liquidity-durability-tvlStability-weight -->35%<!-- GENERATED-END: liquidity-durability-tvlStability-weight --> TVL stability, <!-- GENERATED-START: liquidity-durability-volumeConsistency-weight -->25%<!-- GENERATED-END: liquidity-durability-volumeConsistency-weight --> volume consistency, <!-- GENERATED-START: liquidity-durability-maturity-weight -->25%<!-- GENERATED-END: liquidity-durability-maturity-weight --> maturity, <!-- GENERATED-START: liquidity-durability-organicFraction-weight -->15%<!-- GENERATED-END: liquidity-durability-organicFraction-weight --> organic fraction (sqrt curve)
Diversity<!-- GENERATED-START: liquidity-pairDiversity-weight -->10%<!-- GENERATED-END: liquidity-pairDiversity-weight -->DeFiLlama YieldsPool count, diminishing returns: min(100, poolCount x 5)

Quality Multipliers (v2)

Pool TypeMultiplierDetection
Curve StableSwap A>=5001.0xregistryId not containing crypto + A>=500
Curve StableSwap A<5000.85xregistryId not containing crypto + A<500
Curve CryptoSwap0.5xregistryId containing crypto/twocrypto/tricrypto
Uniswap V3 1bp1.1xfee tier <= 100
Uniswap V3 5bp0.85xfee tier <= 500
Uniswap V3 30bp+0.4xfee tier > 500
Fluid DEX0.85xproject contains fluid
Aerodrome Stable (sAMM)0.85xdirect-source label only; DeFiLlama rows never resolve here
Aerodrome Volatile (vAMM)0.4xproject contains aerodrome, no concentrated-liquidity tag
Balancer Stable0.85xproject contains balancer + stable pattern
Balancer Weighted0.4xproject contains balancer, non-stable
Raydium CLMM0.85xdirect API type, or DL poolMeta marked Concentrated
Raydium AMM0.4xstandard AMM, wider spreads
Orca Whirlpool0.85xconcentrated liquidity (direct API or DL)
Meteora DLMM0.85xprotocol contains meteora
PancakeSwap V3 1bp1.1xprotocol contains pancakeswap + fee tier <= 1 bp
PancakeSwap V3 5bp0.85xprotocol contains pancakeswap + fee tier <= 5 bp
PancakeSwap V3 25bp0.7xprotocol contains pancakeswap + fee tier <= 25 bp
PancakeSwap V3 30bp0.4xprotocol contains pancakeswap + fee tier <= 30 bp
PancakeSwap V3 100bp0.25xprotocol contains pancakeswap + fee tier > 30 bp
Aerodrome Slipstream 1bp1.1xprotocol contains aerodrome-slipstream + fee tier <= 1 bp
Aerodrome Slipstream 5bp0.85xprotocol contains aerodrome-slipstream + fee tier <= 5 bp
Aerodrome Slipstream 30bp+0.4xprotocol contains aerodrome-slipstream + fee tier > 5 bp
Velodrome Slipstream 1bp1.1xprotocol contains velodrome-slipstream + fee tier <= 1 bp
Velodrome Slipstream 5bp0.85xprotocol contains velodrome-slipstream + fee tier <= 5 bp
Velodrome Slipstream 30bp+0.4xprotocol contains velodrome-slipstream + fee tier > 5 bp
Generic AMM0.3xfallback

Direct concentrated-liquidity fetchers (PancakeSwap V3, Aerodrome/Velodrome Slipstream) derive their -1bp/-5bp/-25bp/-30bp/-100bp bucket from the fee the source actually decoded. When the upstream fee is absent or out of range — a missing or malformed subgraph feeTier, a Sugar pool_fee outside [1, 10000] bps — the row keeps feeRate: null and publishes the neutral <protocol>-unknown-fee bucket (CL_UNKNOWN_FEE_BUCKET in worker/src/cron/dex-liquidity/direct-source-helpers.ts) instead of a fabricated tier, so the bucket never contradicts the row's own null fee. That bucket carries no tier multiplier and falls through to the generic 0.3x weight; pool-shape family and measured-execution targeting are unchanged.

Pool Quality Adjustments

  • Balance health: Continuous Math.pow(balanceRatio, 1.5) instead of binary threshold
  • Pair quality: Co-token scored using Pharos governance classification (CeFi->1.0, DeFi->0.9, CeFi-Dep->0.8) + static map for volatile assets (WETH->0.65, WBTC->0.6, unknown->0.3). Known quote aliases such as USD₮0, USDT0, aUSDC, aUSDT, USDbC, and .e bridged variants are normalized to canonical symbols before scoring. Composite Curve LP aliases such as 3Crv and FRAXBP inherit the best score from their underlying stablecoin basket. Multi-asset pools use best co-token score
  • MetaPool TVL dedup: Uses Curve's usdTotalExcludingBasePool to prevent double-counting base pool liquidity across metapools; the live Curve response owns the inventory.
  • Effective TVL: poolTvl x mechanismMultiplier x balanceHealth x pairQuality, summed across all pools
  • Zero depth: A measured zero effective-TVL aggregate stays zero in both relative and unavailable-market-cap depth formulas; raw TVL never replaces it.
  • Source-lane consistency: Secondary and remembered live pools use the same parsePoolSymbols parser as primary pools (USDC-USDT, USDC / USDT, and recognized composite names), unless a measured pair-quality override is supplied. Registry fallback preserves selected measured balance ratios and locked-liquidity fields for DeFiLlama and direct-API rows as well as CoinGecko; balanceMeasured accompanies the forwarded balance evidence, not an optimistic default.

For direct APIs, balance health is no longer uniformly neutral. Balancer, Raydium, Orca, and resolver-backed Fluid pools now contribute measured balance ratios when their APIs provide enough token-balance and pricing context. Fluid pools still default to 1.0 balance when the official resolver is unavailable or token decimals cannot be resolved safely.

Data Quality Filters

  • isBroken === true Curve pools: skipped
  • Dead/rugged/deprecated protocols: excluded from dexProjects set and the explicit runtime blocklist (currently including Retro and Bunni variants)
  • exposure === "single" pools (lending deposits, not DEX liquidity): skipped
  • CryptoSwap pools: correctly classified via registryId
  • DL Raydium pools: classified from poolMeta (Concentrated -> raydium-clmm) since v6.0, because DeFiLlama ships every Raydium pool under the raydium-amm project slug; this lets the DL row and its direct-API CLMM twin share one pool-shape family and deduplicate instead of double-counting

Pool Stress Index (0-100)

Per-pool stress metric: 35x(1-balanceRatio) + 25x(1-organicFraction) + 20xImmaturityPenalty + 20x(1-pairQuality). TVL-weighted average stored as avg_pool_stress.

Durability Score (0-100)

Per-stablecoin durability metric combining: TVL stability from 30-day CV (35%), volume consistency from 30-day CV (25%), oldest pool maturity (25%), and organic fee fraction with sqrt curve (15%). Locked liquidity removed — no reliable data source. Stored as durability_score.

Pool Quality Formula

Pool Quality measures the venue quality retention ratio: the fraction of total TVL that survives after applying mechanism and balance-health multipliers.

poolQuality = min(100, max(0, (qualityAdjustedTvl / totalTvlUsd - 0.15) / 0.65 * 100))

Where qualityAdjustedTvl applies mechanism and balance-health multipliers to raw TVL, and totalTvlUsd is the pre-adjustment sum across all pools. Pair quality is already reflected upstream in effectiveTvl and the pool-stress diagnostics, but it is not part of this retention-ratio component. The linear rescaling maps the 15–80% retention range to 0–100, so a pool set retaining 15% or less of its raw TVL after quality adjustment scores 0, and one retaining 80% or more scores 100.

Exact Curve metapool joins use retained, base-pool-excluded TVL for both numerator and denominator. Balance evidence carries its own notional scope: a full-pool ratio cannot weight excluded-pool TVL. Mismatches omit measured balance diagnostics and use the existing unmeasured neutral fallback. With a scope-matched ratio 0.5, $2M retained TVL and multiplier 0.85 yield about $601,041 quality TVL (30.05% retention, Pool Quality 23), never a $3.005M full-pool numerator.

Durability Sub-Component Weights

  • 35% TVL stability — 1 - min(1, CV) over 30-day snapshots (CV = coefficient of variation)
  • 25% Volume consistency — same CV formula over 30-day daily 24h turnover (volume / TVL). Since v6.9 a recorded day counts when its window is complete (measured volume / retained TVL) or its admitted pools cover at least DEX_VOLUME_COVERAGE_MIN of retained TVL (partialGrossUsd / admittedTvlUsd); below the floor the day is skipped, never estimated. Legacy days without a record keep their stored volume over stored TVL. Fewer than 7 qualifying days in 30 still falls back to the neutral 50 (durabilityVolumeConsistencyDefault).
  • 25% Maturity — oldest pool age, capped at 365 days: min(1, oldestDays / 365) × 100
  • 15% Organic fraction — sqrt(organicFraction) × 100 (diminishing returns past 50%; 25% organic → 50 score, 50% → 71 score, 100% → 100 score)
  • Basis homogeneity: each 30-day TVL/turnover series uses one retained-TVL measurement epoch, selected as the latest epoch with at least seven qualifying samples. It never mixes epochs; without seven it falls back to neutral 50. Seven calendar days need not supply seven admitted turnover samples. liquidityTvlBasisEpoch compares stored versions numerically (missing means earliest), and the append-only LIQUIDITY_TVL_BASIS_BREAK_VERSIONS registry owns breaks. Retained-TVL remeasurement must append a break in the same version-bump change; reweighting, volume admission and discovery-admission changes are not automatically breaks. The structured changelog owns past cutover effects.

Measured volume availability

Rows written before v6.9 remain legacy rows (no availability record, unknown completeness). They are not backfilled or restamped. Measured volume preserves actual provider values and clocks, separately from decaying inventory TVL.

  • Shared authority: shared/lib/dex-volume-availability.ts owns the admission window (DEX_VOLUME_OBSERVATION_MAX_AGE_SEC) and coverage floor (DEX_VOLUME_COVERAGE_MIN) constants, window classification, storage reads, consumer interpretation, the volume-activity formula, and the composite rule. Wire vocabulary lives in shared/types/market.ts (DexVolumeCompleteness, DexVolumeAvailabilityReason, DexVolumeAvailability).
  • Producer readings: every retained pool carries its raw provider reading and original observation clock (volumeReading, internal, never published). Live DeFiLlama/direct-API readings retain their source-fetch clocks; registry readings retain the selected row's refresh clock. Resolver preference is highest-trust usable reading within 24h, else within 72h, else freshest stale reading; TVL confidence decay never scales volume. Missing/unparseable trailing volume is null, not zero; CoinGecko Onchain stores a zero only with explicit zero volume and zero 24h buys/sells. Pre-activation zeros from non-exempt registry sources remain absent under DEX_VOLUME_ZERO_PROVENANCE_SINCE_SEC (2026-09-28 07:29:14 UTC); CoinGecko Onchain retains its exempt provenance. Since v6.93, a row after the captured registry evaluation clock is rejected whole before resolution. Legitimate refreshes between source start and registry-read completion retain their original observations and are evaluated in the same generation, without changing source/quote clocks.
  • Pool eligibility: a reading is measured when it has finite non-negative value and a provable observation clock within DEX_VOLUME_OBSERVATION_MAX_AGE_SEC (72h, inclusive). This unchanged budget is wider than the 24h staged TVL/price freshness window because registry discovery can leave readings one to three days old. The admitted value remains the provider's rolling volume as of its original clock, not a 72h sum or an unbiased census; the record names oldest/newest observation clocks and maxObservationAgeSec. Older readings are stale, absent/invalid value or clock is missing, and measured zero remains valid. Since v6.93, applyPoolVolumeEligibility, retention predicates and coin/global summaries use registryEvaluatedAtSec frozen in payload v4, not a later publication/reuse clock. Every downstream volumeUsd1d/volumeUsd7d is the admitted value or null; flags and volumeObservation { status, observedAtSec } retain that admission.
  • Window completeness over the complete retained contributing pool set (not the visible top ten): complete (every pool measured; an empty set is vacuously complete at 0), partial (some measured), missing (none measured, at least one missing), stale (none measured, every observation aged), unknown (legacy row without a record, or an unreadable record). Every non-complete state carries a machine-readable reason.
  • Public fields (in place): totalVolume24hUsd, totalVolume7dUsd, history volume24h and pool volumeUsd1d are widened to nullable. The measured total is a number only for a complete window; otherwise it is null and the additive volume24hAvailability / volume7dAvailability record (history: volume24hAvailability) carries completeness, reason, a separately labelled partialGrossUsd (observed volume over the admitted pools — a lower bound, never the complete statistic), pool counts, the observation-window clock (windowSec, asOfSec, maxObservationAgeSec, oldest/newest observation) and, since v6.9, the bound published with that statistic: admittedTvlUsd (retained scoring TVL of admitted pools), retainedTvlUsd (all retained scoring TVL, post protocol caps) and volumeCoverage = admitted / retained (null when the set carries no TVL). Records written before v6.9 omit the three coverage fields. Pools may carry volumeObservation { status, observedAtSec }. Rows without a record omit these fields: consumers read them as unknown completeness and keep the historical number, never labelling it measured.
  • Storage: migration 0249_dex_volume_availability.sql adds nullable volume_availability_json to dex_liquidity, dex_liquidity_run_rows and dex_liquidity_history. NULL marks a legacy row. Since v6.9 every current, placeholder, __global__ and daily-history row writes a record. The NOT NULL legacy volume columns hold the complete sum, else the admitted partial gross, else 0, and are never published as measured unless the record says complete. total_volume_7d_measured mirrors a complete 7d window. Placeholder rows retain no pool, so they record the vacuous complete-zero window. A same-day history row that is carried forward keeps its own record. An unreadable record publishes null with reason availability-record-unreadable. There is no backfill: legacy completeness cannot be reconstructed from stored totals.
  • LiquidityScore (DEC-19, coverage-gated since v6.9): Volume Activity applies the existing log-scale formula to admitted 24h volume / admitted TVL; stale and missing pools enter neither the numerator nor the denominator and nothing is estimated, zero-filled or decayed for them. The component — and therefore the composite — is rated when the 24h window is complete or volumeCoverage >= DEX_VOLUME_COVERAGE_MIN (0.50, exported from shared/lib/dex-volume-availability.ts; the exact floor is rated). A complete measured zero scores 0 activity under the full weight denominator. Below the floor (including a coin with no admitted reading, missing/stale, or unknown completeness) the component is unavailable (scoreComponents.volumeActivity: null) and the composite LiquidityScore NR (liquidity_score = NULL). No renormalization, no denominator shrink, and no earlier score is carried forward. The 7d window is display-only. Valid components remain displayable beside the NR component. Coverage is an evidence-sufficiency floor, not an unbiasedness proof: unobserved pools may trade differently from observed ones, which is why the floor, the admitted TVL and the observation clocks are published with the score. Publication coverage guards and same-day history reconciliation count NR rows as observed (a rated score, or a non-unobserved coverage class), not as placeholders.
  • Downstream readers: the DEX API/history handlers, Depeg Resolver context (current and 30d volume baseline), public dataset snapshot and durability volume-consistency series apply the storage read; durability volume consistency takes coverage-qualified days only (see Durability Sub-Component Weights). Safety Score does not consume the composite LiquidityScore or volume: its native DEX capture carries updatedAt, exit-route observations and their coverage, so an NR composite alone does not make its Exit evidence unavailable. An NR composite reaches score-dependent readers as unavailable, not as a low score: the Selector's trading profile requires liquidityScore, so an NR coin is a coverage skip there (shared/lib/selector/exclusions.ts); the Depeg Resolver's legacy K5 thin-liquidity triggers (liquidityScore < 20 / < 30) cannot fire for an NR coin, and its current and 30-day volume inputs are null for non-complete windows, so K6 wind-down and calm-catastrophic paths that need them cannot fire (shared/lib/depeg-resolver/resolution.ts, worker/src/cron/depeg-resolver/context.ts); and the DEWS liquidity signal is unavailable while liquidityScore is null (worker/src/lib/dews/signal-families.ts).
  • Frontend display: src/lib/dex-volume-display.ts renders a non-complete window as an em dash with a Partial ≥ $X label in card cells. The /liquidity/ leaderboard shows the admitted partial gross in-cell as a muted ≥ $X, and its hero 24h DEX volume row headlines it as an explicit lower bound (≥ $X, detail Partial lower bound: pools holding N% of TVL); neither drops the ≥ or presents the bound as the complete total (R1/R7).
  • Exit portfolio completeness is a separate policy: isDexExitRouteCoverageWithinRouteBudget() in shared/lib/p4-exit-route-capability-policy.ts owns the existing gap-accounting carve-outs; exact-route scoring keeps the stricter isDexExitRouteCoverageComplete(). Neither borrows the volume coverage floor or Economic Control's circulating-supply materiality threshold. A small missing pool count, top-ten TVL, or missing liquidity value cannot establish an immaterial unobserved remainder. Pools without admitted exact observations add no executable capacity, but an unresolved coverage gap retains its own scoped cause.

Liquidity Page

/liquidity/ uses the instrument header (methodology line labelled "Liquidity Score methodology") and a stacked FeatureHeroSplit:

  • Beam: "Secondary exit depth", the global row's totalTvlUsd; "—" plus a "Depth unavailable" chip when the global row is missing or quarantined. The universe chip counts observed markets (isObservedOnDex in src/app/liquidity/model.ts) over the active roster. A degraded or stale response (or an API Warning) becomes an OpsStatusChip beside the beam label, naming the snapshot time and the endpoint's fresh budget (API_FRESHNESS_MAX_AGE_SEC.dexLiquidity × FRESHNESS_RATIOS.FRESH when the header omits it); warn-110 reads "Stale data". The body shows a notice only for a hard error. A quarantined global row withholds its 24h volume with its depth.
  • Facts: the 7d change is labelled "coins with 7d history" because it is a pool-TVL-weighted change over coins with a 7d baseline, not the global total's own change (the global row has no history series); 24h DEX volume as above; rated and observed-NR counts.
  • Visual: the exit route map, unframed on the hero surface (src/components/exit-route-map.tsx). Doors and lanes show their share of depth; the throat, drawn from HHI, shows the crowding index; below 768px two short door/lane lists, led by the crowding index, replace the scene. At rest the aggregate throat is selected so no route is dimmed.
  • Ledger: the hero footer (src/components/exit-route-ledger.tsx) draws venue and chain mix in the map's exact door and lane colours with exact dollar depth, and breaks "Other routes" into its named tail plus a counted remainder (the tail sentence is hidden below 640px).
  • Below the hero: the leaderboard (rated rows, then unranked observed NR rows with their reason label; a partial window whose admitted sum rounds to $0.00 shows "—", not "≥ $0.00"), then folds for pool quality and for tracked coins not observed on DEX, then a source and snapshot-age footer.

Discovery Cron

Census authority belongs to a successfully completed, exhaustive same-run query, not a provider's advertised chains or a missing next-page marker. Capped/failed queries retain observed pools but cannot certify no pools; supplemental venue indexes cannot prove chain-wide absence. The source/scope contract owns provider routing and resumable-window mechanics.

Successful CG/GT transport suppresses the next fallback only with paginationComplete: true; capped inventories keep their observed pools and still allow GT/DexScreener reads. Osmosis, Noble, Kava and Aquarius quarantine malformed rows while staging healthy matches and reporting positive observed counts under degraded, non-exhaustive checks. Aquarius collapses identical duplicates and quarantines conflicting pool identities.

Aquarius discovery includes the nine reviewed Spiko Soroban registers, including CHFSAFO's exact issuer-listed contract. This is supplemental venue coverage, not an exhaustive Stellar/Soroban census: an empty Aquarius response remains non-exhaustive, while positive pool evidence establishes only observed inventory. Registration does not admit an execution model, manufacture a price, or establish asset-wide no-exit evidence.

Supported footprints without a published liquidity row receive the same due-time census maintenance as explicit zero-pool rows. This is discovery scheduling eligibility, not measured-zero liquidity or market-absence evidence. The existing 18-hour sweep target, two-hour tick, rotating deployment windows and provider budgets remain unchanged; missing or superseded outcomes stay unknown until real provider results persist.

D21 — execution model: discovery stays cron-native after the long-run Queue/Workflow review. Each invocation uses a setup-inclusive bounded work slice, checkpoints the unfinished cohort, and resumes it on the existing two-hour trigger instead of running toward the wrapper deadline. The admitted cohort sequence and per-deployment resume markers survive continuation; a checkpoint never certifies unqueried scope or refreshes evidence timestamps. The discovery execution contract owns budget and checkpoint details.

Address-bound QuoterV2 identity enrichment shares its existing 128-pool cap round-robin across reviewed deployment groups rather than admitting the first group exclusively. Sorted physical addresses rotate hourly within each group, and the first serialized group rotates too, so stable source insertion order cannot permanently starve later pools or chains. The 160-request/90-second budgets, serial RPC execution, exact factory membership checks, and active-versus-shadow admission remain unchanged. Selection, deferred probes, and failed reads prove no execution capacity; only subsequently accepted exact quotes contribute route evidence. Full portfolio coverage is not asserted merely because a bounded enrichment packet completed.

Exact route admission uses the consumer's scoring clock, not the source-stage start: factory/reserve captures performed minutes into that stage and measured cohorts already published before consumption are available evidence rather than lookahead. The measured-cohort read ceiling remains pinned to that consumer clock, and validators retain their future and freshness checks. Original block, reference-price, target, registry-read and generation clocks are not restamped; registry volume continues to use its separately captured read-consumption clock.

DEX Price Cross-Validation

DEX-implied prices publish hourly with the liquidity consumer. Genuine pool prices come only from the deduplicated retained pool set after quality filters/caps, weighted by observed liquidity and source confidence. Exchange tickers are a separate price-only channel weighted by observed flow; they supply no synthetic pool TVL or executable orderbook depth. Missing trusted primary price withholds DEX publication rather than bypassing plausibility/outlier checks.

Price and liquidity have separate clocks. API price fields become unavailable for invalid/stale/future or publication-mismatched evidence; a fresh price cannot make stale liquidity fresh. Depeg corroboration uses a stricter 75-minute/≥$1M source-liquidity gate, while the summary display uses 60 minutes/≥$250K. Ticker-only zero-TVL evidence clears neither floor. A contradictory DEX price can suppress a new false-positive event under the confirmation rules, not automatically close an existing event.