Skip to content

About

Aggregated price feed for the Nockchain ecosystem — multi-source medians computed in a Hoon kernel

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

16 Commits

Folders and files

Repository files navigation

nock-oracle

A multi-source price feed for the Nockchain ecosystem. Prices are pulled from public venues, aggregated to a median inside a Hoon kernel running on the NockApp runtime, and served as JSON with every input disclosed — so any consumer can re-run the aggregation and check the number.

Coverage: NOCK and PRL as first-class pairs (per-venue, multi-source), plus ~49 liquid majors for reference. 51 pairs from ~5 upstream requests per minute, all free public APIs, no keys.

Public instance: https://nockoracle.xyz — try /price/nock-usd.

API

GET /prices          all pairs
GET /price/<pair>    one pair, e.g. /price/nock-usd
GET /funding         donation wallet balance and anchoring runway
GET /anchors         daily on-chain anchors: sha-256, txid, data snapshot
GET /snapshots/<f>   the exact price set a given anchor hashed
GET /api             endpoint and pair index (JSON; / serves the web page)
{
  "pair": "nock-usd",
  "price": 0.02031,
  "method": "median",
  "sources": [
    { "source": "coingecko",   "price": 0.02027908, "ts": 1782948684 },
    { "source": "kraken",      "price": 0.02031,    "ts": 1782948684 },
    { "source": "dexscreener", "price": 0.02069,    "ts": 1782948684 }
  ],
  "live_sources": 3,
  "updated": 1782948684,
  "stale": false
}

Pair ids are lowercase <ticker>-usd. Unknown pairs return 404. stale is true when no source has reported for over 300 seconds.

How aggregation works

The Rust wrapper is plumbing; the Hoon kernel is the authority.

  1. A fetch driver polls the venues every 60 s and pokes each observation into the kernel as [%observe pair source price ts] (prices fixed-point 1e8).
  2. The kernel keeps one observation per source per pair (newer reports replace older ones), evicts sources unseen for 300 s, and recomputes the median (mean of the two middle values when the count is even).
  3. The HTTP layer answers by peeking kernel state. Nothing is served that the kernel did not compute.

The computation is deterministic from the disclosed inputs: sort the sources array from any response by price and take the middle — you get price.

Sources, and an honest note about them

Venue Feeds Notes
DexScreener NOCK deepest-liquidity Base pool
Kraken NOCK NOCKUSD last trade
CoinGecko (simple price) NOCK + majors one batched call
CoinGecko (tickers) PRL per-venue: SafeTrade, CoinEx, BigONE, … each a separate source; tickers flagged stale/anomalous by CoinGecko are skipped
Binance majors one batched call

Honesty note: CoinGecko's simple price is itself an aggregate that already includes venues we also query directly, so the majors are reference-grade (two partially-correlated sources), while NOCK and PRL are genuinely multi-venue. live_sources in every response tells you which case you are looking at. New PRL venue listings join the median automatically.

This service is value-added aggregation with sources credited per response — not raw data resale.

Why prices are not settled on-chain every minute

Nockchain fees are per word of transaction data: 16,384 nicks (0.25 NOCK) per seed word, witness words at a quarter rate, so cost scales with payload size, not with computation. We measured the real numbers on a fakenet with the actual wallet planner rather than trusting documentation:

plain send:            seed_words=13  witness_words=62  fee=3,648 nicks
with 49-byte payload:  seed_words=21  witness_words=56  fee=4,480 nicks

A 49-byte data entry costs 1 + ceil(49/8) = 8 extra seed words, exactly as the fee code predicts. Translated to mainnet constants, one data-carrying transaction costs 8.5 NOCK (measured on mainnet: 557,056 nicks). Which means:

Cadence Cost/month
every 5 minutes ~$1,500 — not viable
hourly ~$130 — not viable for a free feed
daily anchor ~$5 — planned

So the design is: the live feed stays off-chain and free, and a single daily commitment — a hash of the published price set — anchors it on-chain for tamper-evidence. Anyone can hash the served data and compare it with the anchored note. The commitment payload is versioned and reserves a slot for a succinct proof, so if app-level proving ships on Nockchain, it slots in without a redesign.

The stock nockchain-wallet cannot attach arbitrary note-data to an output; tools/nockchain-wallet-note-data.patch adds an opt-in NOCK_NOTE_DATA=key:hex environment variable to create-tx for that purpose.

Build and run

Prerequisites: the Nockchain toolchain built from the monorepo (cargo install --path crates/nockup and crates/hoonc). The pinned nightly in rust-toolchain.toml is required — nockvm uses feature gates that stable rejects.

# from the directory containing this project
nockup project build nock-oracle

# or directly
cargo build --release
hoonc hoon/app/app.hoon        # writes out.jam

# run (reads ./out.jam; binds 127.0.0.1)
./target/release/nock-oracle

The port is HTTP_PORT, else NOCKD_APP_PORT, else 8087. Tests: cargo test --release. On virtualized CPUs without an invariant TSC the binary sets TRACY_NO_INVARIANT_CHECK=1 for itself; export it manually when running hoonc.

Notes on the NockApp stack (things that cost us time)

  • nockvm needs the pinned nightly (#![feature(cold_path)]); project templates omit rust-toolchain.toml, so builds fail on stable.
  • The Tracy profiler compiled into the runtime aborts on CPUs without an invariant TSC (most cloud VMs). TRACY_NO_INVARIANT_CHECK=1 is the escape hatch — and it is not inherited by non-interactive shells, so set it in-process if your supervisor cannot inject environment.
  • poke_sync/peek_sync panic inside a tokio runtime. The supported pattern is IO drivers: make_driver(|handle| …), handle.poke/peek, and app.run() to drive them.
  • The API at your pinned rev is not the API at HEAD. Read the sources cargo actually builds (~/.cargo/git/checkouts/…/<rev>/), not the repo tip.
  • noun-serde at rev 336f744 prints debug lines to stdout from its bool, Option, HashMap and Result decoders. Unwrap Hoon units by hand and decode only clean types (u64, String, tuples, Vec).
  • hoonc keeps global state in ~/.nockapp/hoonc; two concurrent instances corrupt its event log. Never parallelize kernel builds.
  • Wallet CLI: global flags go before the subcommand; pass --fakenet or a fakenet node's coinbase notes appear as zero balance; balances go through the node's private gRPC; create-tx writes ./txs/<name>.tx rather than printing the transaction.

Supporting the feed

Donations in $NOCK fund the daily on-chain anchors and the server: 9WzHyhnanLweqrPJe3KzKNsU8srmzjkXE2oiKZpV1BecK3XuPXS3Ges (also shown with a QR on the web page). The /funding endpoint reports the wallet balance and how many days of anchoring it covers.

License

MIT

About

Aggregated price feed for the Nockchain ecosystem — multi-source medians computed in a Hoon kernel

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages