From a multi-lens adversarial review of the capabilities + prices work:
- PRICES_ASSETS="" now means NONE, not all (real bug): from_env used env_opt,
which collapses unset and present-but-empty into None, so the documented
"empty = none" silently served all five feeds. Read via env::var so unset =>
all, present (even empty) => the listed subset or none.
- PRICES_CURRENCY is now validated against a curated SUPPORTED_PRICE_CURRENCIES
allowlist. Previously a typo (e.g. "usdd") booted, advertised prices:true, and
served an empty feed forever (the provider returns empty quotes for an unknown
currency) — a fail-open path inconsistent with the adjacent provider/asset
checks.
- PRICES_PROVIDER is lowercased at read, matching the asset/currency
normalization (mixed-case no longer trips the allowlist).
- validate() now requires an Electrum URL for an enabled BTC/LTC chain (hard
error in prod, warn in dev), symmetric with the xmr/wow/grin secret checks.
Keeps /capabilities honest: a chain it can't serve won't boot advertising
itself as available.
Tests: config regressions (currency, utxo-electrum); a PriceClient feed-subset
selection unit test; the /prices integration test now populates the snapshot and
asserts the served quotes + RFC-3339 timestamp (the prior PRICES_ASSETS env-var
was inert under the harness); capabilities asserts network presence/null across
all five chains.
Dismissed after verification: coingecko json() was already switched to a
streaming read_capped; fleet refresh-jitter (no API key, single-node,
self-healing on 429); prices capability staying a bare bool (/prices carries the
currency + per-asset map).
Cached crypto→fiat price feed, refreshed by a background task and served from an
in-memory snapshot — no upstream call on the request path. Public and
feature-flagged: when FEATURE_PRICES is off, /prices is 404 and no upstream is
ever contacted.
Per-feed control, as a public server needs: PRICES_ASSETS narrows which feeds an
instance quotes (unset = all supported; an explicit list serves a subset; empty
serves none), validated fail-closed against SUPPORTED_PRICE_ASSETS. Provider
(PRICES_PROVIDER, coingecko) and currency (PRICES_CURRENCY, usd) are configurable;
the refresh interval is clamped to a provider-friendly minimum.
- infra/prices: PriceClient (feed whitelist → provider coin ids), bounded by the
HTTP client timeout; non-finite/negative/missing quotes are skipped, not faked.
A fetch failure keeps the last good snapshot. Drift guard: a test asserts the
provider mapping covers exactly SUPPORTED_PRICE_ASSETS.
- main: background refresh task only when enabled and at least one feed is set.
- AppState.prices snapshot; handler 404s when disabled.
- openapi (prices tag); unit tests + L1 test over both feature-flag states.