mirror of
https://github.com/Such-Software/hash-wallet-prices.git
synced 2026-10-17 05:51:28 +02:00
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.
58 lines
3.0 KiB
Markdown
58 lines
3.0 KiB
Markdown
# hash-wallet-prices
|
||
|
||
Cloudflare Worker that aggregates USD prices for [Hash Wallet](https://github.com/Such-Software/hash-wallet) and serves them at one cached endpoint.
|
||
|
||
Why this exists: see the architectural notes in the wallet repo. Short version — having every user's phone hit Kraken/NonKYC directly leaks wallet-holder activity to the exchanges and spreads our rate-limit budget across thousands of IPs. One Worker with a cron-refreshed KV cache fixes both.
|
||
|
||
## Sources
|
||
|
||
* **Kraken** (`api.kraken.com/0/public/Ticker`) — BTC, XMR, LTC, DOGE, ETH, BCH, XNO (all → USD).
|
||
* **Nonlogs.io** (`api.nonlogs.io/api/markets`) — WOW. Algorithm averages `WOW-BTC × Kraken BTC/USD` and `WOW-USDT` when both exist. Lifted from `~/src/smirk-backend/src/infra/prices.rs`.
|
||
* **cexswap.cc** (`cexswap.cc/api/public/markets/summary`) — WOW backup. Endpoint returns `last_usd` precomputed per pair, so we average across all WOW spot pairs.
|
||
* **Pinned** — USDT, USDC, DAI all return 1.00.
|
||
|
||
WOW USD price is the **average of whichever Nonlogs and cexswap routes returned a value** — survives one source going down without a code change.
|
||
|
||
## Endpoints
|
||
|
||
| Path | Shape |
|
||
| --- | --- |
|
||
| `GET /v2/rates?base=BTC"e=USD` | `{ "results": { "BTC_USD": 67342.5 } }` — drop-in compatible with the wallet's existing fetch code |
|
||
| `GET /v1/prices` | `{ "rates": { ... }, "sources": { ... }, "fetched_at": "..." }` — preferred, returns everything in one call |
|
||
| `GET /v1/sparkline?coin=BTC&hours=24` | `{ coin, hours, points: [[ts_ms, price], ...] }` — hourly buckets, max 168 points (7 days) |
|
||
| `POST /v1/trocador-webhook` | Trocador POSTs the full trade body on every status change; we store it under `trade:<id>` for 14 days |
|
||
| `GET /v1/trade/:trade_id` | Returns the cached trade body (whatever Trocador last sent for that id), or 404 |
|
||
| `GET /healthz` | `{ ok: true, coins: N, fetched_at: ... }` |
|
||
|
||
Non-USD quotes convert through ECB daily reference rates (fetched each cron run); an unknown quote currency returns 0 and the wallet falls back to "price unavailable."
|
||
|
||
## Deploy
|
||
|
||
```bash
|
||
npm install
|
||
npx wrangler login
|
||
npx wrangler kv:namespace create PRICES
|
||
# Paste the returned id into wrangler.toml's kv_namespaces.id field.
|
||
npx wrangler deploy
|
||
```
|
||
|
||
After first deploy the worker is live at `https://hash-wallet-prices.<your-cloudflare-subdomain>.workers.dev`. To put it behind `prices.suchsoftware.com`, point that hostname's DNS at Cloudflare and uncomment the `[[routes]]` block in `wrangler.toml`.
|
||
|
||
## Local dev
|
||
|
||
```bash
|
||
npm install
|
||
npx wrangler dev # starts a local server with hot reload
|
||
curl localhost:8787/healthz
|
||
curl 'localhost:8787/v2/rates?base=BTC"e=USD'
|
||
```
|
||
|
||
## Adding a coin
|
||
|
||
1. If Kraken lists it: add `TICKER: "PAIRUSD"` to `KRAKEN_PAIRS` in `src/index.ts`.
|
||
2. If only smaller exchanges list it: add a new fetcher function alongside `fetchNonkyc()` and merge its results in `refreshPrices()`. Keep it `try`/`catch` wrapped so a single source failure doesn't poison the whole refresh.
|
||
|
||
## License
|
||
|
||
MIT.
|