morphit/docs/PRICE-SOURCES-RESEARCH.md

287 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# BLURT/USD price source research
**Status:** Research notes (not a design decision)
**Date:** 2026-04-21
**Scope:** Evaluate five proposed additional price sources
beyond the existing Klingex + Coingecko pair.
**Interacts with:** ADR-0011 (fee model consumes price),
OPERATIONS.md §13 (stale-price runbook)
---
## Context
The indexer's price path today:
```
Klingex → Coingecko → static_floor
```
Composite source with the first live feed winning, TTL
cache, and background refresh. `priceSource.current()`
returns the BLURT/USD rate used by order fee
verification in `apps/indexer/src/indexer/handlers/order.ts`.
The revisit list asked for evaluation of five additional
sources: **Tribaldex, Hive-Engine, CoinMarketCap,
Blockchair, Blockchain.com**. This document records what
I found about each and a recommendation for or against
integrating it.
The goal of additional sources is **not** diversification
for its own sake — every new source is another
background HTTP request, another failure mode, another
API policy to track. Additional sources earn their place
only if they narrow a real gap in the existing chain.
---
## Source-by-source findings
### CoinMarketCap — FEASIBLE, API KEY REQUIRED
- **Endpoint:** `https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?slug=blurt&convert=USD`
- **Auth:** `X-CMC_PRO_API_KEY` header. Free tier exists
with daily call-credit limit; paid tiers for higher
volume.
- **Response shape:** `data.<id>.quote.USD.price` (number,
USD per BLURT). Timestamp in `data.<id>.quote.USD.last_updated`.
- **BLURT is listed** on CMC (slug: `blurt`).
- **CAVEAT (important):** the BLURT page on
`coinmarketcap.com/currencies/blurt` shows `$0 USD` trading
volume as of 2026-04-21. This means either (a) CMC isn't
aggregating volume from Tribaldex / Hive-Engine sidechain
pools (the main BLURT trading venue today), or (b) the
listing is stale. A price source that reports `$0` volume
is a red flag even if it reports a non-zero price — the
price may be a frozen historical value, not a live rate.
**Operator verification required before making this a
primary or secondary source.**
- **Policy risk:** CMC Terms of Service allow API use for
data display, including commercial use on paid tiers.
Free-tier limits (typically ~10,000 credits/month) are
enough for an operator polling once every 60s
(43,200/month) only on the lowest paid tier — free-tier
polling must be slower (>5-min interval) to stay
under.
- **Recommendation:** FEASIBLE but de-prioritized until an
operator confirms the CMC BLURT price is live and
actively updating. The `$0 volume` flag means CMC could
be reporting a stuck number. If verified live, slot in
as an optional source between Klingex and Coingecko.
### Tribaldex — NOT FEASIBLE AS DIRECT SOURCE (sidechain depeg risk)
- **What it is:** Tribaldex is a front-end for
Hive-Engine sidechain trading. BLURT on Tribaldex is
actually `SWAP.BLURT`, a **wrapped** BLURT token
bridged via `blurt-swap`. Not BLURT itself.
- **Pricing geometry:** To derive BLURT/USD from
Tribaldex you'd need:
`SWAP.BLURT/SWAP.HIVE × HIVE/USD`
(three-hop: cross-chain bridge peg × sidechain pair ×
mainnet price provider)
- **Fundamental problem:** the `SWAP.BLURT` ↔ BLURT peg
depends on bridge liquidity. Under thin liquidity or a
bridge-operator issue, SWAP.BLURT can trade meaningfully
below (or above) BLURT's "real" rate. Using this as a
primary BLURT/USD feed would produce wrong fees during
bridge stress events — exactly when fee accuracy matters
most.
- **Endpoint details** (for reference if ever used as a
sanity-check): Hive-Engine RPC at
`https://api.hive-engine.com/rpc/contracts` — POST
JSON-RPC call to the `market` contract's `metrics` table
with `symbol: "SWAP.BLURT"` returns last price against
SWAP.HIVE.
- **Recommendation:** DO NOT add as a primary or secondary
source. Could serve a niche role as a **divergence
alarm** — if `SWAP.BLURT/SWAP.HIVE × HIVE/USD` disagrees
with the Klingex/Coingecko consensus by >10%, log a
warning for operator attention. But even that is
nice-to-have; a three-hop derived price isn't worth
the infrastructure it requires.
### Hive-Engine — SAME AS TRIBALDEX
- **Same chain, same problem.** Tribaldex IS a
Hive-Engine front-end; there's no independent
Hive-Engine "price" distinct from what Tribaldex
surfaces.
- API documentation:
`https://hive-engine.github.io/engine-docs/` (contract
tables) and
`https://hiveengine.readthedocs.io/en/latest/hiveengine.api.html`
(Python library reference, useful for endpoint
shapes).
- **Recommendation:** treat as identical to Tribaldex.
Do not integrate.
### Blockchair — NOT APPLICABLE
- **Supported chains:** ~48 blockchains as of 2025,
covering Bitcoin family (BTC, LTC, BCH, DOGE, DASH, ZEC, ARRR, DCR, SOL, ETH, XRP,
DGB, XEC, GRS), Ethereum family, Solana, TRON, Polygon,
and similar account-model / UTXO chains.
- **Graphene-family chains (BLURT, Hive, Steem) are NOT
supported.** Blockchair's model is built around
indexing UTXO and account-model chains; delegated-PoS
social chains like BLURT aren't in scope.
- **Not a BLURT price source at all.** Blockchair can't
return BLURT/USD because it doesn't index BLURT.
- **Useful elsewhere?** Yes — for BTC/XMR
fee-attestation. When an order's `fee_method` is
`btc` or `xmr` (ADR-0011 sub-phase 4b), an attestor
verifies the claimed payment on the external chain.
Blockchair's `/bitcoin/dashboards/transaction/{hash}`
endpoint is a clean way to look up a payment. This is
a separate workstream from BLURT/USD pricing — I'm
logging it here but it belongs in the attestor-UX
design, not in `priceSource`.
- **Recommendation:** do NOT integrate into
`priceSource`. Revisit in the ADR-0011 sub-phase 4b
attestor workstream as an explorer-rotation candidate.
### Blockchain.com — NOT APPLICABLE
- **Explorer APIs** are Bitcoin-focused: block data,
transaction lookup, charts/stats for BTC. Not a
multi-chain indexer.
- **Exchange API** lists pairs they run on
`exchange.blockchain.com` — BTC-USD, ETH-USD, etc.
**BLURT is not listed.**
- The `exchange_rates_api` endpoint returns fiat/BTC
conversion rates, not altcoin prices.
- **Recommendation:** do NOT integrate for BLURT price.
Same as Blockchair, could be useful in an attestor
role for BTC fee verification (as a Blockchair
alternate), but that's a separate workstream.
---
## Summary table
| Source | BLURT/USD? | Verdict | Priority |
|---|---|---|---|
| Klingex | direct | already integrated (primary) | — |
| Coingecko | direct | already integrated (fallback) | — |
| CoinMarketCap | direct (but volume=$0 concern) | FEASIBLE pending operator verification | Medium |
| Tribaldex | three-hop derived | NOT RECOMMENDED (sidechain depeg risk) | Low (divergence alarm only) |
| Hive-Engine | same as Tribaldex | NOT RECOMMENDED | Low |
| Blockchair | does not index BLURT | NOT APPLICABLE | — (reconsider for BTC attestor) |
| Blockchain.com | does not list BLURT | NOT APPLICABLE | — (reconsider for BTC attestor) |
---
## Recommendations
**Short term (this audit cycle):**
1. **Do NOT add any new primary price sources.** The
existing Klingex → Coingecko → static_floor chain is
working and the proposed additions each have
disqualifying issues.
2. **Have an operator verify CMC BLURT price freshness.**
If the `$0 volume` flag is just cosmetic (CMC not
aggregating sidechain volume, but price feed is live),
CMC slots in cleanly as a third provider. Required
check: poll
`https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?slug=blurt`
with a trial API key across a week, compare the
returned `price` against Klingex and Coingecko over
the same interval. If CMC tracks within 5% of the
consensus and `last_updated` advances steadily, green-
light integration.
3. **Document the decision not to integrate Tribaldex
and Hive-Engine** in `docs/adr/0004-price-feeds.md`
(the existing price feeds ADR) so the question
doesn't come back in a future session.
**Medium term (ADR-0011 sub-phase 4b):**
4. **Revisit Blockchair and Blockchain.com in the
attestor-UX design workstream.** For BTC/XMR
fee-attestation, a user who's attesting that a
payment landed needs to query an explorer to verify
the claimed tx. An explorer rotation with Blockchair +
Blockchain.com + mempool.space + one or two others is
the right shape for that problem, but it's separate
from `priceSource`.
**Long term (if BLURT gets listed on a major CEX):**
5. **Add direct exchange tickers** as primary sources
when they become available. Binance, Kraken, Gate.io
etc. would all be preferable to aggregators if BLURT
ever gets there. Today, no major CEX lists BLURT, so
this isn't actionable.
---
## What I'd integrate code-wise (if operator green-lights CMC)
Minimal skeleton (for reference, not shipped this
session):
```ts
// apps/indexer/src/indexer/priceFetchers/coinmarketcapFetcher.ts
export function createCmcFetcher(
apiKey: string,
baseUrl = 'https://pro-api.coinmarketcap.com'
): PriceFetcher {
return async (): Promise<PriceSample | null> => {
const url = `${baseUrl}/v1/cryptocurrency/quotes/latest?slug=blurt&convert=USD`;
const res = await fetch(url, {
headers: {
'X-CMC_PRO_API_KEY': apiKey,
Accept: 'application/json'
}
});
if (!res.ok) return null;
const body = await res.json();
// Shape: { data: { <id>: { quote: { USD: { price, last_updated } } } } }
const entries = Object.values(body.data ?? {});
const first = entries[0];
if (!first || typeof first !== 'object') return null;
const quote = (first as any).quote?.USD;
if (!quote || typeof quote.price !== 'number') return null;
return {
blurtUsd: quote.price,
source: 'coinmarketcap',
fetchedAt: new Date(),
observedAt: new Date(quote.last_updated)
};
};
}
```
Order in composite: `Klingex → CMC → Coingecko → static_floor`.
CMC slots in between Klingex and Coingecko because it's
the most authoritative aggregator; Coingecko remains
the backstop because it's free-tier-friendly.
Config additions needed:
- `MORPHIT_INDEXER_CMC_API_KEY` (secret, env-only, never
in logs)
- `MORPHIT_INDEXER_CMC_BASE_URL` (default
`https://pro-api.coinmarketcap.com`, override for
testing)
- `MORPHIT_INDEXER_PRICE_MODE` gains `cmc` as a valid
value, mostly for test scenarios.
---
## Files that would change if we ship CMC
- `apps/indexer/src/indexer/priceFetchers/coinmarketcapFetcher.ts` (new)
- `apps/indexer/src/indexer/priceFactory.ts` (wire cmc into
composite)
- `apps/indexer/src/config/index.ts` (+ 2 config fields)
- `OPERATIONS.md §13` (how to acquire a CMC API key, what
happens if CMC rate-limits)
- `docs/adr/0004-price-feeds.md` (document the third
source)
No schema changes. No migration. Pure additive.