This morning we stopped a one-cent pool on cexswap from pricing WOW. The same
rule was missing on the nonlogs last-trade path, where the test was volume
greater than zero, which one print satisfies.
Today it cost us the desk. We sold 209 WOW by hand at 0.0361, near four times
fair, into a bid standing above our whole ask ladder. That print became
WOW-USDT's last trade. Its book is 42% wide, so the midpoint was refused and
the print stood in for it, and the route carried $12 of daily volume of which
$7.56 was that one trade. WOW marked 15.6 sat against a consensus near 10.7,
and wowdesk's divergence rail then held every WOW market it makes, correctly:
the feed was quoting our own trade back at us.
A last trade must now clear $25 of 24h volume, the same floor cexswap got and
the same one the desk uses for a consensus venue. A live book keeps needing no
floor, because it is somebody else's standing offer and has already passed
both-sides, ask-above-bid and the spread limit.
Verified against the live payloads, since this repo has no test framework:
WOW-BTC prices from its book at $0.00918 with $105 of volume and is unchanged.
WOW-USDT drops, having $12. The blended mark moves 15.63 sat to 12.00, and
divergence against the desk's consensus moves 33.0% to 2.1%, inside its 8%
limit, so WOW can quote again.
We lowered MAX_BOOK_SPREAD_PCT to 25 earlier today to refuse a WOW-USDT book
we stand on both sides of, at 42% wide. That worked, but 25 sat directly on
top of this market's ordinary breathing: WOW-BTC widened to 26.1% within the
hour, failed the limit, and fell back to a stale last print at 12.0 sat
against a 10.5 sat book. A 14% error in the feed then tripped the desk's own
divergence rail, which held every WOW market.
35 clears the normal case and still refuses the reflection. The docblock we
replaced said a 30% spread is a normal Tuesday on these venues; today is
evidence for that.
Verified against today's live books rather than a fixture, since this repo
has no test framework: WOW-BTC at 11/13 sat is 16.7% wide and passes at both
limits, so the served mark does not move today. WOW-USDT at 42.0% and WOW-XMR
at 40.8% fail at both. The change buys headroom for the next time the book
breathes past 25, and nothing else. GRIN is unaffected: it prices from Gate.io
and is deliberately outside NICHE_TICKERS.
On 2026-09-17 this feed marked WOW at $0.00041 while its real book sat at
$0.00805, twenty times low, for hours. Two guards did it, each behaving exactly
as written against an input its author never saw.
nonlogs served WOW-BTC at 10 bid / 11 ask with every 24h counter reading zero.
fetchNonlogs requires quote_volume > 0 on every route, so all three WOW routes
were discarded and nonlogs vanished from the sources entirely. But a book
midpoint and a last trade are not equally trustworthy and should not face the
same gate: the midpoint has already proved both sides exist, that the ask is
above the bid, and that the spread is inside MAX_BOOK_SPREAD_PCT. Demanding an
odometer reading on top of that discards a live market for having a quiet day.
A last print has proved none of those things and still needs volume.
That left cexswap alone, where the 12-hour staleness gate dropped WOW-XMR at
$1,064 of volume for being 18.2h old and kept WOW-DOGE, carrying ONE CENT, for
being 3.7h old. One sample, and WOW was priced by a pool nobody trades. Recent
and meaningful are different questions, so niche samples now need both: the
floor matches the desk's consensus_min_venue_vol_usd, which exists because a
$24/day pool once carried 86% of a consensus.
MAX_BOOK_SPREAD_PCT drops 60 to 25. Sixty excluded the absurd and admitted the
reflexive: nonlogs WOW-USDT read 0.0079/0.0121, a 42% spread with our own ladder
on both sides and no counterparty between, and its midpoint dragged the blend to
$0.00901. At 25 that route is refused and the mark is $0.00802470 against a book
truth of $0.00802470.
Verified against the live payloads that produced the fault rather than fixtures;
this repo has no test harness, and the data that broke it is the better witness.
Kraken does not list GRIN, and the niche-ticker path averages nonlogs and
cexswap, the same venues our own desk quotes into. An oracle that reads back
our own quotes is the circularity the desk divergence rail exists to catch,
so Gate.io is wired as its own source rather than folded into that average.
We prefer the book mid over `last`: on a thin market a print can sit outside
the current spread, while bid and ask are live quotes. Kraken still wins
wherever it lists the coin, and a Gate.io failure degrades to no GRIN rate
rather than to a wrong one.
The feed read $0.008546 while cross-venue consensus was $0.009280, low by 8.6%,
and wowdesk's fair guard is anchored to it: the desk was refusing to bid at
prices the market was actually trading, because the feed did not believe those
prices existed.
Two causes, both last-trade artefacts. Nonlogs WOW-BTC last traded at 10 sat
while its book stood 10 bid, 13 ask, so the live midpoint was 11.5 and we were
quoting a print instead. And CexSwap's WOW-XMR sample, which carries $635 of
seven-day volume against Nonlogs' $169 and therefore dominates the average, was
the 24-hour low and 11.5 hours old.
Nonlogs now prefers the midpoint of the best bid and ask, guarded: both sides
present, ask above bid, spread at or under 60%, else fall back to the last
trade. CexSwap publishes no book, so the only guard available there is age, and
a print older than 12 hours no longer anchors the feed.
Measured against live venues: Nonlogs moves $0.007989 to $0.009187, three dead
CexSwap pairs expire, and the feed as a whole moves $0.008546 to $0.008796.
GET /v1/oracle now returns the method, the guard values and the known limits
next to the rates, served by the code that implements them so the description
cannot drift from the behaviour. README carries the same in prose.
The cexswap leg drops pairs with no 7-day volume and says why: a stale
last print on a dead pair must never drag the average. The nonlogs leg
did not, and averaged WOW-USDT — a 0.00723 print with null volume — against
a WOW-BTC route with real trades behind it.
Today that pulls the nonlogs leg 15% low, and since the leg is half the
WOW blend, the published price 8.4% low: 0.009830 against 0.010653. The
drag grows as WOW moves away from whenever that print happened.
Both routes are now volume-weighted by 24h quote volume, and a venue with
no volume anywhere is omitted so the other venue's sample stands alone —
the same shape as the cexswap function.
This feed is what Hash Bags, Smirk, wowlet and the desk's own fair value
display, so the number moves for all of them on deploy.
fetchEcbFiat() converts the ECB EUR-based table to USD multipliers each
cron run; /v2/rates multiplies COIN_USD for any known fiat quote. Feed
failure degrades to USD-only, never to a stale-wrong number. Deployed
and verified: WOW/EUR, GBP, JPY, MXN all serving.
The naive mean across all WOW pairs let stale prints on zero-volume
markets (WOW-ETH last traded at $0.000087) drag the cexswap component
~40% below its live markets, and the published WOW rate ~20% under fair.
Weight by volume7d_usd and drop pairs with no 7-day volume; if every
pair is dead the ticker falls back to the Nonlogs sample alone.
- POST /v1/trocador-webhook: Trocador hits this on every trade status change;
stored in KV under trade:<id> for 14 days (matching Trocador's retention).
- GET /v1/trade/🆔 returns the cached trade body so the wallet can poll us
instead of Trocador, dramatically reducing load on their infra per their
commercial team's request.
- GET /v1/sparkline?coin=BTC&hours=24: returns hourly history points for
rendering balance sparklines. Cron appends one entry per UTC hour per coin,
capped at 168 points (1 week).
Per source repos in ~/src:
- ~/src/smirk-backend/src/infra/prices.rs uses Nonlogs api/markets,
averaging (WOW-BTC * Kraken BTC/USD) and WOW-USDT routes.
- ~/src/neroswap-site/scrapers/scrape_cexswap.py hits
cexswap.cc/api/public/markets/summary which already returns last_usd
per pair.
WOW now sourced from BOTH and averaged — survives one source going down
without code changes.
Single endpoint serving USD spot prices for Hash Wallet, sourcing from
Kraken (majors) and NonKYC (Wownero), KV-cached and refreshed via cron
every minute. Drop-in /v2/rates shape compatible with the existing wallet
client; preferred /v1/prices returns everything in one call.