From a3f3c5467586ce1435087097bccd90f820060fe0 Mon Sep 17 00:00:00 2001 From: nym21 Date: Thu, 4 Jun 2026 15:38:01 +0200 Subject: [PATCH] oracle: v4 --- crates/brk_client/src/lib.rs | 34 +- crates/brk_computer/src/cointime/compute.rs | 4 +- .../src/cointime/prices/compute.rs | 4 +- .../src/cointime/reserve_risk/compute.rs | 4 +- .../src/cointime/supply/compute.rs | 4 +- .../src/cointime/value/compute.rs | 4 +- .../src/distribution/addr/exposed/mod.rs | 4 +- .../src/distribution/addr/reused/mod.rs | 4 +- .../src/distribution/cohorts/addr/groups.rs | 6 +- .../src/distribution/cohorts/addr/vecs.rs | 6 +- .../src/distribution/cohorts/traits.rs | 6 +- .../src/distribution/cohorts/utxo/groups.rs | 6 +- .../distribution/cohorts/utxo/vecs/core.rs | 4 +- .../distribution/cohorts/utxo/vecs/minimal.rs | 4 +- .../src/distribution/cohorts/utxo/vecs/mod.rs | 4 +- .../distribution/cohorts/utxo/vecs/type.rs | 4 +- .../src/distribution/metrics/activity/core.rs | 4 +- .../src/distribution/metrics/activity/full.rs | 4 +- .../distribution/metrics/activity/minimal.rs | 4 +- .../src/distribution/metrics/activity/mod.rs | 8 +- .../src/distribution/metrics/cohort/all.rs | 4 +- .../src/distribution/metrics/cohort/basic.rs | 4 +- .../src/distribution/metrics/cohort/core.rs | 6 +- .../distribution/metrics/cohort/extended.rs | 4 +- .../metrics/cohort/extended_adjusted.rs | 4 +- .../distribution/metrics/cohort/minimal.rs | 6 +- .../src/distribution/metrics/cohort/type.rs | 6 +- .../src/distribution/metrics/mod.rs | 4 +- .../src/distribution/metrics/profitability.rs | 8 +- .../src/distribution/metrics/realized/core.rs | 4 +- .../src/distribution/metrics/realized/full.rs | 4 +- .../distribution/metrics/realized/minimal.rs | 4 +- .../distribution/metrics/supply/avg_amount.rs | 4 +- .../src/distribution/metrics/supply/base.rs | 4 +- .../src/distribution/metrics/supply/core.rs | 4 +- .../distribution/metrics/unrealized/full.rs | 4 +- .../distribution/metrics/unrealized/mod.rs | 8 +- crates/brk_computer/src/distribution/vecs.rs | 4 +- .../src/indicators/rarity_meter/mod.rs | 4 +- .../per_block/ratio/price_extended.rs | 8 +- .../src/internal/per_block/value/base.rs | 4 +- .../src/internal/per_block/value/block.rs | 4 +- .../internal/per_block/value/cumulative.rs | 6 +- .../per_block/value/cumulative_rolling.rs | 6 +- .../src/internal/per_block/value/full.rs | 4 +- .../src/internal/with_addr_types.rs | 4 +- crates/brk_computer/src/investing/compute.rs | 4 +- crates/brk_computer/src/lib.rs | 40 +- crates/brk_computer/src/market/ath/compute.rs | 4 +- crates/brk_computer/src/market/compute.rs | 4 +- .../src/market/lookback/compute.rs | 4 +- .../src/market/moving_average/compute.rs | 4 +- .../brk_computer/src/market/range/compute.rs | 4 +- .../src/market/returns/compute.rs | 4 +- .../src/market/technical/compute.rs | 4 +- .../brk_computer/src/market/technical/macd.rs | 4 +- crates/brk_computer/src/mining/compute.rs | 4 +- .../src/mining/rewards/compute.rs | 4 +- crates/brk_computer/src/outputs/compute.rs | 4 +- .../brk_computer/src/outputs/value/compute.rs | 4 +- crates/brk_computer/src/pools/major.rs | 4 +- crates/brk_computer/src/pools/mod.rs | 4 +- .../src/{prices => price}/by_unit.rs | 0 .../src/{prices => price}/compute.rs | 29 +- .../brk_computer/src/{prices => price}/mod.rs | 2 +- .../src/{prices => price}/ohlcs.rs | 0 .../brk_computer/src/supply/burned/compute.rs | 4 +- crates/brk_computer/src/supply/compute.rs | 4 +- .../brk_computer/src/transactions/compute.rs | 4 +- .../src/transactions/volume/compute.rs | 4 +- .../brk_mempool/src/stores/live_histograms.rs | 11 +- crates/brk_oracle/README.md | 28 +- crates/brk_oracle/examples/determinism.rs | 63 +- crates/brk_oracle/examples/experiment.rs | 690 ++++++++++++++++++ crates/brk_oracle/examples/report.rs | 47 +- crates/brk_oracle/examples/report_from.rs | 32 +- crates/brk_oracle/src/config.rs | 11 +- crates/brk_oracle/src/filter.rs | 173 ++++- crates/brk_oracle/src/lib.rs | 75 +- crates/brk_oracle/src/seed.rs | 60 ++ crates/brk_oracle/src/shape.rs | 72 -- crates/brk_oracle/src/stencil.rs | 257 +++++-- crates/brk_query/src/impl/block/info.rs | 2 +- .../brk_query/src/impl/mining/block_fees.rs | 2 +- .../src/impl/mining/block_rewards.rs | 2 +- crates/brk_query/src/impl/oracle.rs | 10 +- crates/brk_query/src/impl/price.rs | 4 +- crates/brk_query/src/impl/urpd.rs | 2 +- crates/brk_server/src/api/series_legacy.rs | 2 +- crates/brk_website/examples/website.rs | 7 +- modules/brk-client/index.js | 18 +- packages/brk_client/brk_client/__init__.py | 16 +- website/AGENTS.md | 5 - .../{ => assets/favicon}/apple-touch-icon.png | Bin .../{ => assets/favicon}/favicon-96x96.png | Bin website/{ => assets/favicon}/favicon.ico | Bin website/{ => assets/favicon}/favicon.svg | 0 .../assets/favicon/site.webmanifest | 0 .../web-app-manifest-192x192.png | Bin .../web-app-manifest-512x512.png | Bin .../Lilex-Italic[wght]-v2_620.woff2.woff2 | Bin website/index.html | 214 ++++-- website/manifest.webmanifest | 16 +- {website_bkp => website}/scripts/_types.js | 0 website/{ => scripts}/entry.js | 0 .../scripts/explorer/address.js | 0 .../scripts/explorer/block.js | 0 .../scripts/explorer/chain.js | 0 .../scripts/explorer/cube.js | 0 .../scripts/explorer/index.js | 0 .../scripts/explorer/mempool.js | 0 .../scripts/explorer/render.js | 0 .../scripts/explorer/tx.js | 0 {website_bkp => website}/scripts/main.js | 0 .../scripts/modules/.gitignore | 0 .../scripts/modules/brk-client/.gitignore | 0 .../scripts/modules/brk-client/index.js | 0 .../scripts/modules/brk-client/jsconfig.json | 0 .../scripts/modules/brk-client/package.json | 0 .../scripts/modules/brk-client/tests/basic.js | 0 .../modules/brk-client/tests/consistency.js | 0 .../modules/brk-client/tests/metric_data.js | 0 .../scripts/modules/brk-client/tests/tree.js | 0 .../scripts/modules/brk-client/tsconfig.json | 0 .../scripts/modules/lean-qr/.gitignore | 0 .../scripts/modules/lean-qr/2.7.1/index.d.ts | 0 .../scripts/modules/lean-qr/2.7.1/index.mjs | 0 .../modules/lightweight-charts/.gitignore | 0 ...ghtweight-charts.standalone.production.mjs | 0 .../5.2.0/dist/typings.d.ts | 0 .../modules/quickmatch-js/0.5.0/src/index.js | 0 .../scripts/modules/tsconfig.json | 0 .../scripts/modules/unpkg.sh | 0 .../scripts/options/cointime.js | 0 .../scripts/options/constants.js | 0 .../scripts/options/distribution/activity.js | 0 .../options/distribution/cost-basis.js | 0 .../scripts/options/distribution/data.js | 0 .../scripts/options/distribution/holdings.js | 0 .../scripts/options/distribution/index.js | 0 .../scripts/options/distribution/prices.js | 0 .../options/distribution/profitability.js | 0 .../scripts/options/distribution/valuation.js | 0 .../scripts/options/full.js | 0 .../scripts/options/investing.js | 0 .../scripts/options/market.js | 0 .../scripts/options/mining.js | 0 .../scripts/options/network.js | 0 .../scripts/options/partial.js | 0 .../scripts/options/series.js | 0 .../scripts/options/shared.js | 0 .../scripts/options/types.js | 0 .../scripts/options/unused.js | 0 .../scripts/panes/chart.js | 0 .../scripts/panes/search.js | 0 .../scripts/panes/share.js | 0 .../scripts/utils/array.js | 0 .../scripts/utils/chart/capture.js | 0 .../scripts/utils/chart/index.js | 0 .../scripts/utils/chart/legend.js | 0 .../scripts/utils/client.js | 0 .../scripts/utils/colors.js | 0 {website_bkp => website}/scripts/utils/dom.js | 0 .../scripts/utils/elements.js | 0 {website_bkp => website}/scripts/utils/env.js | 0 .../scripts/utils/format.js | 0 .../scripts/utils/persisted.js | 0 .../scripts/utils/price.js | 0 .../scripts/utils/serde.js | 0 .../scripts/utils/storage.js | 0 .../scripts/utils/theme.js | 0 .../scripts/utils/time.js | 0 .../scripts/utils/timing.js | 0 .../scripts/utils/units.js | 0 {website_bkp => website}/scripts/utils/url.js | 0 .../src/explorer/chain/cube/index.js | 0 .../src/explorer/chain/cube/style.css | 0 .../src/explorer/chain/index.js | 0 .../src/explorer/chain/style.css | 0 .../src/heatmap/controls/dates.js | 0 .../src/heatmap/controls/index.js | 0 .../src/heatmap/controls/shared.js | 0 .../src/heatmap/controls/y.js | 0 .../src/heatmap/format.js | 0 {website_bkp => website}/src/heatmap/grid.js | 0 {website_bkp => website}/src/heatmap/index.js | 0 .../src/heatmap/loader.js | 0 {website_bkp => website}/src/heatmap/lut.js | 0 .../src/heatmap/oracle.js | 0 .../src/heatmap/renderer.js | 0 .../src/heatmap/style.css | 0 {website_bkp => website}/src/heatmap/time.js | 0 .../src/heatmap/tooltip/index.js | 0 .../src/heatmap/tooltip/view.js | 0 {website_bkp => website}/src/heatmap/types.js | 0 {website_bkp => website}/src/heatmap/urpd.js | 0 {website_bkp => website}/styles/chart.css | 0 .../styles/components.css | 0 {website_bkp => website}/styles/elements.css | 0 website/styles/fonts.css | 14 +- website/styles/main.css | 179 ++++- {website_bkp => website}/styles/nav.css | 0 .../styles/panes/chart.css | 0 .../styles/panes/explorer.css | 0 {website_bkp => website}/styles/search.css | 0 website/styles/variables.css | 9 + website_bkp/index.html | 194 ----- website_bkp/styles/main.css | 162 ---- {website_bkp => website_next}/.gitignore | 0 .../.well-known/ai-plugin.json | 0 {website_bkp => website_next}/AGENTS.md | 5 + .../apple-touch-icon.png | Bin .../assets/fonts/InstrumentSerif-Italic.woff2 | Bin .../fonts/InstrumentSerif-Regular.woff2 | Bin .../fonts/Lilex-Italic[wght]-v2_620.woff2 | Bin .../assets/fonts/Lilex[wght]-v2_620.woff2 | Bin .../assets/logo/.gitignore | 0 .../assets/logo/demo-svg.html | 0 .../assets/logo/demo.html | 0 .../assets/logo/logo-dark.svg | 0 .../assets/logo/logo-light.svg | 0 .../assets/logo/logo-orange.svg | 0 .../assets/logo/logo.svg | 0 {website_bkp => website_next}/assets/pools.sh | 0 .../assets/pools/1thash.svg | 0 .../assets/pools/antpool.svg | 0 .../assets/pools/arkpool.svg | 0 .../assets/pools/binancepool.svg | 0 .../assets/pools/bitcoincom.svg | 0 .../assets/pools/bitfufupool.svg | 0 .../assets/pools/bitfury.svg | 0 .../assets/pools/braiinspool.svg | 0 .../assets/pools/braiinssolo.svg | 0 .../assets/pools/btccom.svg | 0 .../assets/pools/btclab.svg | 0 .../assets/pools/btctop.svg | 0 .../assets/pools/default.light.svg | 0 .../assets/pools/default.svg | 0 .../assets/pools/emcdpool.svg | 0 .../assets/pools/est3lar.svg | 0 .../assets/pools/f2pool.svg | 0 .../assets/pools/foundryusa.light.svg | 0 .../assets/pools/foundryusa.svg | 0 .../assets/pools/gdpool.svg | 0 .../assets/pools/huobipool.svg | 0 .../assets/pools/innopolistech.svg | 0 .../assets/pools/kucoinpool.svg | 0 .../assets/pools/luxor.svg | 0 .../assets/pools/marapool.svg | 0 .../assets/pools/maxipool.svg | 0 .../assets/pools/minerium.svg | 0 .../assets/pools/miningsquared.svg | 0 .../assets/pools/mononaut.svg | 0 .../assets/pools/neopool.svg | 0 .../assets/pools/nicehash.svg | 0 .../assets/pools/ocean.svg | 0 .../assets/pools/okexpool.svg | 0 .../assets/pools/okkong.svg | 0 .../assets/pools/parasite.svg | 0 .../assets/pools/pegapool.svg | 0 .../assets/pools/phoenix.svg | 0 .../assets/pools/poolin.svg | 0 .../assets/pools/publicpool.svg | 0 .../assets/pools/rawpool.svg | 0 .../assets/pools/sbicrypto.svg | 0 .../assets/pools/secpool.svg | 0 .../assets/pools/sigmapoolcom.svg | 0 .../assets/pools/slushpool.svg | 0 .../assets/pools/solopoolcom.svg | 0 .../assets/pools/spiderpool.svg | 0 .../assets/pools/terrapool.svg | 0 .../assets/pools/titan.svg | 0 .../assets/pools/ultimuspool.light.svg | 0 .../assets/pools/ultimuspool.svg | 0 .../assets/pools/unknown.light.svg | 0 .../assets/pools/unknown.svg | 0 .../assets/pools/viabtc.svg | 0 .../assets/pools/wayicn.svg | 0 .../assets/pools/whitepool.light.svg | 0 .../assets/pools/whitepool.svg | 0 .../assets/pools/wiz.svg | 0 .../assets}/web-app-manifest-192x192.png | Bin .../assets}/web-app-manifest-512x512.png | Bin {website => website_next}/build/index.js | 0 {website => website_next}/build/style.css | 0 {website => website_next}/cube/index.js | 0 {website => website_next}/cube/style.css | 0 .../scripts => website_next}/entry.js | 0 {website => website_next}/explore/index.js | 0 {website => website_next}/explore/style.css | 0 .../favicon-96x96.png | Bin .../favicon => website_next}/favicon.ico | Bin .../favicon => website_next}/favicon.svg | 0 {website => website_next}/header/index.js | 5 +- {website => website_next}/header/style.css | 28 +- {website => website_next}/home/index.js | 0 {website => website_next}/home/style.css | 0 website_next/index.html | 94 +++ {website_bkp => website_next}/jsconfig.json | 0 {website => website_next}/learn/data.js | 0 {website => website_next}/learn/index.js | 0 {website => website_next}/learn/style.css | 0 {website_bkp => website_next}/llms-full.txt | 0 {website_bkp => website_next}/llms.txt | 0 {website => website_next}/main.js | 0 .../manifest.webmanifest | 16 +- {website_bkp => website_next}/robots.txt | 0 .../service-worker.js | 0 .../styles/fonts.css | 14 +- website_next/styles/main.css | 33 + .../styles/reset.css | 0 .../styles/variables.css | 9 - {website_bkp => website_next}/tsconfig.json | 0 313 files changed, 1980 insertions(+), 996 deletions(-) rename crates/brk_computer/src/{prices => price}/by_unit.rs (100%) rename crates/brk_computer/src/{prices => price}/compute.rs (91%) rename crates/brk_computer/src/{prices => price}/mod.rs (99%) rename crates/brk_computer/src/{prices => price}/ohlcs.rs (100%) create mode 100644 crates/brk_oracle/examples/experiment.rs create mode 100644 crates/brk_oracle/src/seed.rs delete mode 100644 crates/brk_oracle/src/shape.rs rename website/{ => assets/favicon}/apple-touch-icon.png (100%) rename website/{ => assets/favicon}/favicon-96x96.png (100%) rename website/{ => assets/favicon}/favicon.ico (100%) rename website/{ => assets/favicon}/favicon.svg (100%) rename {website_bkp => website}/assets/favicon/site.webmanifest (100%) rename website/assets/{ => favicon}/web-app-manifest-192x192.png (100%) rename website/assets/{ => favicon}/web-app-manifest-512x512.png (100%) rename {website_bkp => website}/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 (100%) rename {website_bkp => website}/scripts/_types.js (100%) rename website/{ => scripts}/entry.js (100%) rename {website_bkp => website}/scripts/explorer/address.js (100%) rename {website_bkp => website}/scripts/explorer/block.js (100%) rename {website_bkp => website}/scripts/explorer/chain.js (100%) rename {website_bkp => website}/scripts/explorer/cube.js (100%) rename {website_bkp => website}/scripts/explorer/index.js (100%) rename {website_bkp => website}/scripts/explorer/mempool.js (100%) rename {website_bkp => website}/scripts/explorer/render.js (100%) rename {website_bkp => website}/scripts/explorer/tx.js (100%) rename {website_bkp => website}/scripts/main.js (100%) rename {website_bkp => website}/scripts/modules/.gitignore (100%) rename {website_bkp => website}/scripts/modules/brk-client/.gitignore (100%) rename {website_bkp => website}/scripts/modules/brk-client/index.js (100%) rename {website_bkp => website}/scripts/modules/brk-client/jsconfig.json (100%) rename {website_bkp => website}/scripts/modules/brk-client/package.json (100%) rename {website_bkp => website}/scripts/modules/brk-client/tests/basic.js (100%) rename {website_bkp => website}/scripts/modules/brk-client/tests/consistency.js (100%) rename {website_bkp => website}/scripts/modules/brk-client/tests/metric_data.js (100%) rename {website_bkp => website}/scripts/modules/brk-client/tests/tree.js (100%) rename {website_bkp => website}/scripts/modules/brk-client/tsconfig.json (100%) rename {website_bkp => website}/scripts/modules/lean-qr/.gitignore (100%) rename {website_bkp => website}/scripts/modules/lean-qr/2.7.1/index.d.ts (100%) rename {website_bkp => website}/scripts/modules/lean-qr/2.7.1/index.mjs (100%) rename {website_bkp => website}/scripts/modules/lightweight-charts/.gitignore (100%) rename {website_bkp => website}/scripts/modules/lightweight-charts/5.2.0/dist/lightweight-charts.standalone.production.mjs (100%) rename {website_bkp => website}/scripts/modules/lightweight-charts/5.2.0/dist/typings.d.ts (100%) rename {website_bkp => website}/scripts/modules/quickmatch-js/0.5.0/src/index.js (100%) rename {website_bkp => website}/scripts/modules/tsconfig.json (100%) rename {website_bkp => website}/scripts/modules/unpkg.sh (100%) rename {website_bkp => website}/scripts/options/cointime.js (100%) rename {website_bkp => website}/scripts/options/constants.js (100%) rename {website_bkp => website}/scripts/options/distribution/activity.js (100%) rename {website_bkp => website}/scripts/options/distribution/cost-basis.js (100%) rename {website_bkp => website}/scripts/options/distribution/data.js (100%) rename {website_bkp => website}/scripts/options/distribution/holdings.js (100%) rename {website_bkp => website}/scripts/options/distribution/index.js (100%) rename {website_bkp => website}/scripts/options/distribution/prices.js (100%) rename {website_bkp => website}/scripts/options/distribution/profitability.js (100%) rename {website_bkp => website}/scripts/options/distribution/valuation.js (100%) rename {website_bkp => website}/scripts/options/full.js (100%) rename {website_bkp => website}/scripts/options/investing.js (100%) rename {website_bkp => website}/scripts/options/market.js (100%) rename {website_bkp => website}/scripts/options/mining.js (100%) rename {website_bkp => website}/scripts/options/network.js (100%) rename {website_bkp => website}/scripts/options/partial.js (100%) rename {website_bkp => website}/scripts/options/series.js (100%) rename {website_bkp => website}/scripts/options/shared.js (100%) rename {website_bkp => website}/scripts/options/types.js (100%) rename {website_bkp => website}/scripts/options/unused.js (100%) rename {website_bkp => website}/scripts/panes/chart.js (100%) rename {website_bkp => website}/scripts/panes/search.js (100%) rename {website_bkp => website}/scripts/panes/share.js (100%) rename {website_bkp => website}/scripts/utils/array.js (100%) rename {website_bkp => website}/scripts/utils/chart/capture.js (100%) rename {website_bkp => website}/scripts/utils/chart/index.js (100%) rename {website_bkp => website}/scripts/utils/chart/legend.js (100%) rename {website_bkp => website}/scripts/utils/client.js (100%) rename {website_bkp => website}/scripts/utils/colors.js (100%) rename {website_bkp => website}/scripts/utils/dom.js (100%) rename {website_bkp => website}/scripts/utils/elements.js (100%) rename {website_bkp => website}/scripts/utils/env.js (100%) rename {website_bkp => website}/scripts/utils/format.js (100%) rename {website_bkp => website}/scripts/utils/persisted.js (100%) rename {website_bkp => website}/scripts/utils/price.js (100%) rename {website_bkp => website}/scripts/utils/serde.js (100%) rename {website_bkp => website}/scripts/utils/storage.js (100%) rename {website_bkp => website}/scripts/utils/theme.js (100%) rename {website_bkp => website}/scripts/utils/time.js (100%) rename {website_bkp => website}/scripts/utils/timing.js (100%) rename {website_bkp => website}/scripts/utils/units.js (100%) rename {website_bkp => website}/scripts/utils/url.js (100%) rename {website_bkp => website}/src/explorer/chain/cube/index.js (100%) rename {website_bkp => website}/src/explorer/chain/cube/style.css (100%) rename {website_bkp => website}/src/explorer/chain/index.js (100%) rename {website_bkp => website}/src/explorer/chain/style.css (100%) rename {website_bkp => website}/src/heatmap/controls/dates.js (100%) rename {website_bkp => website}/src/heatmap/controls/index.js (100%) rename {website_bkp => website}/src/heatmap/controls/shared.js (100%) rename {website_bkp => website}/src/heatmap/controls/y.js (100%) rename {website_bkp => website}/src/heatmap/format.js (100%) rename {website_bkp => website}/src/heatmap/grid.js (100%) rename {website_bkp => website}/src/heatmap/index.js (100%) rename {website_bkp => website}/src/heatmap/loader.js (100%) rename {website_bkp => website}/src/heatmap/lut.js (100%) rename {website_bkp => website}/src/heatmap/oracle.js (100%) rename {website_bkp => website}/src/heatmap/renderer.js (100%) rename {website_bkp => website}/src/heatmap/style.css (100%) rename {website_bkp => website}/src/heatmap/time.js (100%) rename {website_bkp => website}/src/heatmap/tooltip/index.js (100%) rename {website_bkp => website}/src/heatmap/tooltip/view.js (100%) rename {website_bkp => website}/src/heatmap/types.js (100%) rename {website_bkp => website}/src/heatmap/urpd.js (100%) rename {website_bkp => website}/styles/chart.css (100%) rename {website_bkp => website}/styles/components.css (100%) rename {website_bkp => website}/styles/elements.css (100%) rename {website_bkp => website}/styles/nav.css (100%) rename {website_bkp => website}/styles/panes/chart.css (100%) rename {website_bkp => website}/styles/panes/explorer.css (100%) rename {website_bkp => website}/styles/search.css (100%) delete mode 100644 website_bkp/index.html delete mode 100644 website_bkp/styles/main.css rename {website_bkp => website_next}/.gitignore (100%) rename {website_bkp => website_next}/.well-known/ai-plugin.json (100%) rename {website_bkp => website_next}/AGENTS.md (64%) rename {website_bkp/assets/favicon => website_next}/apple-touch-icon.png (100%) rename {website_bkp => website_next}/assets/fonts/InstrumentSerif-Italic.woff2 (100%) rename {website_bkp => website_next}/assets/fonts/InstrumentSerif-Regular.woff2 (100%) rename {website => website_next}/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 (100%) rename {website_bkp => website_next}/assets/fonts/Lilex[wght]-v2_620.woff2 (100%) rename {website_bkp => website_next}/assets/logo/.gitignore (100%) rename {website_bkp => website_next}/assets/logo/demo-svg.html (100%) rename {website_bkp => website_next}/assets/logo/demo.html (100%) rename {website_bkp => website_next}/assets/logo/logo-dark.svg (100%) rename {website_bkp => website_next}/assets/logo/logo-light.svg (100%) rename {website_bkp => website_next}/assets/logo/logo-orange.svg (100%) rename {website_bkp => website_next}/assets/logo/logo.svg (100%) rename {website_bkp => website_next}/assets/pools.sh (100%) rename {website_bkp => website_next}/assets/pools/1thash.svg (100%) rename {website_bkp => website_next}/assets/pools/antpool.svg (100%) rename {website_bkp => website_next}/assets/pools/arkpool.svg (100%) rename {website_bkp => website_next}/assets/pools/binancepool.svg (100%) rename {website_bkp => website_next}/assets/pools/bitcoincom.svg (100%) rename {website_bkp => website_next}/assets/pools/bitfufupool.svg (100%) rename {website_bkp => website_next}/assets/pools/bitfury.svg (100%) rename {website_bkp => website_next}/assets/pools/braiinspool.svg (100%) rename {website_bkp => website_next}/assets/pools/braiinssolo.svg (100%) rename {website_bkp => website_next}/assets/pools/btccom.svg (100%) rename {website_bkp => website_next}/assets/pools/btclab.svg (100%) rename {website_bkp => website_next}/assets/pools/btctop.svg (100%) rename {website_bkp => website_next}/assets/pools/default.light.svg (100%) rename {website_bkp => website_next}/assets/pools/default.svg (100%) rename {website_bkp => website_next}/assets/pools/emcdpool.svg (100%) rename {website_bkp => website_next}/assets/pools/est3lar.svg (100%) rename {website_bkp => website_next}/assets/pools/f2pool.svg (100%) rename {website_bkp => website_next}/assets/pools/foundryusa.light.svg (100%) rename {website_bkp => website_next}/assets/pools/foundryusa.svg (100%) rename {website_bkp => website_next}/assets/pools/gdpool.svg (100%) rename {website_bkp => website_next}/assets/pools/huobipool.svg (100%) rename {website_bkp => website_next}/assets/pools/innopolistech.svg (100%) rename {website_bkp => website_next}/assets/pools/kucoinpool.svg (100%) rename {website_bkp => website_next}/assets/pools/luxor.svg (100%) rename {website_bkp => website_next}/assets/pools/marapool.svg (100%) rename {website_bkp => website_next}/assets/pools/maxipool.svg (100%) rename {website_bkp => website_next}/assets/pools/minerium.svg (100%) rename {website_bkp => website_next}/assets/pools/miningsquared.svg (100%) rename {website_bkp => website_next}/assets/pools/mononaut.svg (100%) rename {website_bkp => website_next}/assets/pools/neopool.svg (100%) rename {website_bkp => website_next}/assets/pools/nicehash.svg (100%) rename {website_bkp => website_next}/assets/pools/ocean.svg (100%) rename {website_bkp => website_next}/assets/pools/okexpool.svg (100%) rename {website_bkp => website_next}/assets/pools/okkong.svg (100%) rename {website_bkp => website_next}/assets/pools/parasite.svg (100%) rename {website_bkp => website_next}/assets/pools/pegapool.svg (100%) rename {website_bkp => website_next}/assets/pools/phoenix.svg (100%) rename {website_bkp => website_next}/assets/pools/poolin.svg (100%) rename {website_bkp => website_next}/assets/pools/publicpool.svg (100%) rename {website_bkp => website_next}/assets/pools/rawpool.svg (100%) rename {website_bkp => website_next}/assets/pools/sbicrypto.svg (100%) rename {website_bkp => website_next}/assets/pools/secpool.svg (100%) rename {website_bkp => website_next}/assets/pools/sigmapoolcom.svg (100%) rename {website_bkp => website_next}/assets/pools/slushpool.svg (100%) rename {website_bkp => website_next}/assets/pools/solopoolcom.svg (100%) rename {website_bkp => website_next}/assets/pools/spiderpool.svg (100%) rename {website_bkp => website_next}/assets/pools/terrapool.svg (100%) rename {website_bkp => website_next}/assets/pools/titan.svg (100%) rename {website_bkp => website_next}/assets/pools/ultimuspool.light.svg (100%) rename {website_bkp => website_next}/assets/pools/ultimuspool.svg (100%) rename {website_bkp => website_next}/assets/pools/unknown.light.svg (100%) rename {website_bkp => website_next}/assets/pools/unknown.svg (100%) rename {website_bkp => website_next}/assets/pools/viabtc.svg (100%) rename {website_bkp => website_next}/assets/pools/wayicn.svg (100%) rename {website_bkp => website_next}/assets/pools/whitepool.light.svg (100%) rename {website_bkp => website_next}/assets/pools/whitepool.svg (100%) rename {website_bkp => website_next}/assets/pools/wiz.svg (100%) rename {website_bkp/assets/favicon => website_next/assets}/web-app-manifest-192x192.png (100%) rename {website_bkp/assets/favicon => website_next/assets}/web-app-manifest-512x512.png (100%) rename {website => website_next}/build/index.js (100%) rename {website => website_next}/build/style.css (100%) rename {website => website_next}/cube/index.js (100%) rename {website => website_next}/cube/style.css (100%) rename {website_bkp/scripts => website_next}/entry.js (100%) rename {website => website_next}/explore/index.js (100%) rename {website => website_next}/explore/style.css (100%) rename {website_bkp/assets/favicon => website_next}/favicon-96x96.png (100%) rename {website_bkp/assets/favicon => website_next}/favicon.ico (100%) rename {website_bkp/assets/favicon => website_next}/favicon.svg (100%) rename {website => website_next}/header/index.js (83%) rename {website => website_next}/header/style.css (72%) rename {website => website_next}/home/index.js (100%) rename {website => website_next}/home/style.css (100%) create mode 100644 website_next/index.html rename {website_bkp => website_next}/jsconfig.json (100%) rename {website => website_next}/learn/data.js (100%) rename {website => website_next}/learn/index.js (100%) rename {website => website_next}/learn/style.css (100%) rename {website_bkp => website_next}/llms-full.txt (100%) rename {website_bkp => website_next}/llms.txt (100%) rename {website => website_next}/main.js (100%) rename {website_bkp => website_next}/manifest.webmanifest (62%) rename {website_bkp => website_next}/robots.txt (100%) rename {website_bkp => website_next}/service-worker.js (100%) rename {website_bkp => website_next}/styles/fonts.css (72%) create mode 100644 website_next/styles/main.css rename {website_bkp => website_next}/styles/reset.css (100%) rename {website_bkp => website_next}/styles/variables.css (85%) rename {website_bkp => website_next}/tsconfig.json (100%) diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index e53fa81a3..38c53adaa 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -3534,7 +3534,7 @@ pub struct SeriesTree { pub investing: SeriesTree_Investing, pub market: SeriesTree_Market, pub pools: SeriesTree_Pools, - pub prices: SeriesTree_Prices, + pub price: SeriesTree_Price, pub supply: SeriesTree_Supply, pub cohorts: SeriesTree_Cohorts, } @@ -3556,7 +3556,7 @@ impl SeriesTree { investing: SeriesTree_Investing::new(client.clone(), format!("{base_path}_investing")), market: SeriesTree_Market::new(client.clone(), format!("{base_path}_market")), pools: SeriesTree_Pools::new(client.clone(), format!("{base_path}_pools")), - prices: SeriesTree_Prices::new(client.clone(), format!("{base_path}_prices")), + price: SeriesTree_Price::new(client.clone(), format!("{base_path}_price")), supply: SeriesTree_Supply::new(client.clone(), format!("{base_path}_supply")), cohorts: SeriesTree_Cohorts::new(client.clone(), format!("{base_path}_cohorts")), } @@ -7063,31 +7063,31 @@ impl SeriesTree_Pools_Minor { } /// Series tree node. -pub struct SeriesTree_Prices { - pub split: SeriesTree_Prices_Split, - pub ohlc: SeriesTree_Prices_Ohlc, - pub spot: SeriesTree_Prices_Spot, +pub struct SeriesTree_Price { + pub split: SeriesTree_Price_Split, + pub ohlc: SeriesTree_Price_Ohlc, + pub spot: SeriesTree_Price_Spot, } -impl SeriesTree_Prices { +impl SeriesTree_Price { pub fn new(client: Arc, base_path: String) -> Self { Self { - split: SeriesTree_Prices_Split::new(client.clone(), format!("{base_path}_split")), - ohlc: SeriesTree_Prices_Ohlc::new(client.clone(), format!("{base_path}_ohlc")), - spot: SeriesTree_Prices_Spot::new(client.clone(), format!("{base_path}_spot")), + split: SeriesTree_Price_Split::new(client.clone(), format!("{base_path}_split")), + ohlc: SeriesTree_Price_Ohlc::new(client.clone(), format!("{base_path}_ohlc")), + spot: SeriesTree_Price_Spot::new(client.clone(), format!("{base_path}_spot")), } } } /// Series tree node. -pub struct SeriesTree_Prices_Split { +pub struct SeriesTree_Price_Split { pub open: CentsSatsUsdPattern3, pub high: CentsSatsUsdPattern3, pub low: CentsSatsUsdPattern3, pub close: CentsSatsUsdPattern3, } -impl SeriesTree_Prices_Split { +impl SeriesTree_Price_Split { pub fn new(client: Arc, base_path: String) -> Self { Self { open: CentsSatsUsdPattern3::new(client.clone(), "price_open".to_string()), @@ -7099,13 +7099,13 @@ impl SeriesTree_Prices_Split { } /// Series tree node. -pub struct SeriesTree_Prices_Ohlc { +pub struct SeriesTree_Price_Ohlc { pub usd: SeriesPattern2, pub cents: SeriesPattern2, pub sats: SeriesPattern2, } -impl SeriesTree_Prices_Ohlc { +impl SeriesTree_Price_Ohlc { pub fn new(client: Arc, base_path: String) -> Self { Self { usd: SeriesPattern2::new(client.clone(), "price_ohlc".to_string()), @@ -7116,13 +7116,13 @@ impl SeriesTree_Prices_Ohlc { } /// Series tree node. -pub struct SeriesTree_Prices_Spot { +pub struct SeriesTree_Price_Spot { pub usd: SeriesPattern1, pub cents: SeriesPattern1, pub sats: SeriesPattern1, } -impl SeriesTree_Prices_Spot { +impl SeriesTree_Price_Spot { pub fn new(client: Arc, base_path: String) -> Self { Self { usd: SeriesPattern1::new(client.clone(), "price".to_string()), @@ -8953,7 +8953,7 @@ pub struct BrkClient { impl BrkClient { /// Client version. - pub const VERSION: &'static str = "v0.3.0"; + pub const VERSION: &'static str = "v0.3.1"; /// Create a new client with the given base URL. pub fn new(base_url: impl Into) -> Self { diff --git a/crates/brk_computer/src/cointime/compute.rs b/crates/brk_computer/src/cointime/compute.rs index ebcb69156..1a81731d1 100644 --- a/crates/brk_computer/src/cointime/compute.rs +++ b/crates/brk_computer/src/cointime/compute.rs @@ -3,14 +3,14 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::Vecs; -use crate::{blocks, distribution, mining, prices, supply}; +use crate::{blocks, distribution, mining, price, supply}; impl Vecs { #[allow(clippy::too_many_arguments)] pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, blocks: &blocks::Vecs, mining: &mining::Vecs, supply_vecs: &supply::Vecs, diff --git a/crates/brk_computer/src/cointime/prices/compute.rs b/crates/brk_computer/src/cointime/prices/compute.rs index ea5b82614..1762fc575 100644 --- a/crates/brk_computer/src/cointime/prices/compute.rs +++ b/crates/brk_computer/src/cointime/prices/compute.rs @@ -5,14 +5,14 @@ use vecdb::Exit; use super::super::{activity, cap, supply}; use super::Vecs; -use crate::{distribution, prices}; +use crate::{distribution, price}; impl Vecs { #[allow(clippy::too_many_arguments)] pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, distribution: &distribution::Vecs, activity: &activity::Vecs, supply: &supply::Vecs, diff --git a/crates/brk_computer/src/cointime/reserve_risk/compute.rs b/crates/brk_computer/src/cointime/reserve_risk/compute.rs index 18c87efdf..41bdf9151 100644 --- a/crates/brk_computer/src/cointime/reserve_risk/compute.rs +++ b/crates/brk_computer/src/cointime/reserve_risk/compute.rs @@ -4,14 +4,14 @@ use brk_types::StoredF64; use vecdb::Exit; use super::{super::value, Vecs}; -use crate::{blocks, internal::algo::ComputeRollingMedianFromStarts, prices}; +use crate::{blocks, internal::algo::ComputeRollingMedianFromStarts, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, value: &value::Vecs, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/cointime/supply/compute.rs b/crates/brk_computer/src/cointime/supply/compute.rs index 512102f9b..6a37486b8 100644 --- a/crates/brk_computer/src/cointime/supply/compute.rs +++ b/crates/brk_computer/src/cointime/supply/compute.rs @@ -4,13 +4,13 @@ use vecdb::Exit; use super::super::activity; use super::Vecs; -use crate::{distribution, prices}; +use crate::{distribution, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, distribution: &distribution::Vecs, activity: &activity::Vecs, exit: &Exit, diff --git a/crates/brk_computer/src/cointime/value/compute.rs b/crates/brk_computer/src/cointime/value/compute.rs index 18e105395..918b576f3 100644 --- a/crates/brk_computer/src/cointime/value/compute.rs +++ b/crates/brk_computer/src/cointime/value/compute.rs @@ -5,13 +5,13 @@ use vecdb::Exit; use super::super::activity; use super::Vecs; -use crate::{distribution, prices}; +use crate::{distribution, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, distribution: &distribution::Vecs, activity: &activity::Vecs, exit: &Exit, diff --git a/crates/brk_computer/src/distribution/addr/exposed/mod.rs b/crates/brk_computer/src/distribution/addr/exposed/mod.rs index 2bcd2b5e7..04e8a7f52 100644 --- a/crates/brk_computer/src/distribution/addr/exposed/mod.rs +++ b/crates/brk_computer/src/distribution/addr/exposed/mod.rs @@ -45,7 +45,7 @@ use super::{ count::AddrCountFundedTotalVecs, supply::{AddrSupplyShareVecs, AddrSupplyVecs}, }; -use crate::{indexes, prices}; +use crate::{indexes, price}; mod state; @@ -104,7 +104,7 @@ impl ExposedAddrVecs { pub(crate) fn compute_rest( &mut self, starting_lengths: &Lengths, - prices: &prices::Vecs, + prices: &price::Vecs, all_supply_sats: &impl ReadableVec, type_supply_sats: &ByAddrType<&impl ReadableVec>, exit: &Exit, diff --git a/crates/brk_computer/src/distribution/addr/reused/mod.rs b/crates/brk_computer/src/distribution/addr/reused/mod.rs index bd68e3b89..6513d786d 100644 --- a/crates/brk_computer/src/distribution/addr/reused/mod.rs +++ b/crates/brk_computer/src/distribution/addr/reused/mod.rs @@ -35,7 +35,7 @@ use super::{ use crate::{ indexes, inputs, internal::{WindowStartVec, Windows}, - outputs, prices, + outputs, price, }; mod state; @@ -112,7 +112,7 @@ impl ReusedAddrVecs { starting_lengths: &Lengths, outputs_by_type: &outputs::ByTypeVecs, inputs_by_type: &inputs::ByTypeVecs, - prices: &prices::Vecs, + prices: &price::Vecs, all_supply_sats: &impl ReadableVec, type_supply_sats: &ByAddrType<&impl ReadableVec>, exit: &Exit, diff --git a/crates/brk_computer/src/distribution/cohorts/addr/groups.rs b/crates/brk_computer/src/distribution/cohorts/addr/groups.rs index 60a3c6a48..791da2445 100644 --- a/crates/brk_computer/src/distribution/cohorts/addr/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/addr/groups.rs @@ -13,7 +13,7 @@ use crate::{ distribution::DynCohortVecs, indexes, internal::{WindowStartVec, Windows}, - prices, + price, }; use super::{super::traits::CohortVecs, vecs::AddrCohortVecs}; @@ -95,7 +95,7 @@ impl AddrCohorts { /// First phase of post-processing: compute index transforms. pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -108,7 +108,7 @@ impl AddrCohorts { /// Second phase of post-processing: compute relative metrics. pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/cohorts/addr/vecs.rs b/crates/brk_computer/src/distribution/cohorts/addr/vecs.rs index 07fc7cac5..3ef96a066 100644 --- a/crates/brk_computer/src/distribution/cohorts/addr/vecs.rs +++ b/crates/brk_computer/src/distribution/cohorts/addr/vecs.rs @@ -12,7 +12,7 @@ use crate::{ distribution::state::{AddrCohortState, MinimalRealizedState}, indexes, internal::{PerBlockWithDeltas, WindowStartVec, Windows}, - prices, + price, }; use crate::distribution::metrics::{ImportConfig, MinimalCohortMetrics}; @@ -174,7 +174,7 @@ impl DynCohortVecs for AddrCohortVecs { fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -229,7 +229,7 @@ impl CohortVecs for AddrCohortVecs { fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/cohorts/traits.rs b/crates/brk_computer/src/distribution/cohorts/traits.rs index 7906d02d6..707518b16 100644 --- a/crates/brk_computer/src/distribution/cohorts/traits.rs +++ b/crates/brk_computer/src/distribution/cohorts/traits.rs @@ -3,7 +3,7 @@ use brk_indexer::Lengths; use brk_types::{Cents, Height, Sats, StoredU64, Version}; use vecdb::{Exit, ReadableVec}; -use crate::prices; +use crate::price; /// Dynamic dispatch trait for cohort vectors. /// @@ -31,7 +31,7 @@ pub trait DynCohortVecs: Send + Sync { /// First phase of post-processing computations. fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()>; @@ -61,7 +61,7 @@ pub trait CohortVecs: DynCohortVecs { /// Second phase of post-processing computations. fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index a0b52ab24..927c37ce4 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -27,7 +27,7 @@ use crate::{ }, indexes, internal::{ValuePerBlockCumulativeRolling, WindowStartVec, Windows}, - prices, + price, }; use super::{fenwick::CostBasisFenwick, vecs::UTXOCohortVecs}; @@ -483,7 +483,7 @@ impl UTXOCohorts { /// First phase of post-processing: compute index transforms. pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -546,7 +546,7 @@ impl UTXOCohorts { pub(crate) fn compute_rest_part2( &mut self, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_market_cap: &impl ReadableVec, exit: &Exit, diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/core.rs b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/core.rs index 3ff8d5d3d..9189a7373 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/core.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/core.rs @@ -6,7 +6,7 @@ use vecdb::{Exit, ReadableVec}; use crate::{ distribution::{cohorts::traits::DynCohortVecs, metrics::CoreCohortMetrics}, - prices, + price, }; use super::UTXOCohortVecs; @@ -56,7 +56,7 @@ impl DynCohortVecs for UTXOCohortVecs { fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/minimal.rs b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/minimal.rs index 1f023aba9..d01a2c7cf 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/minimal.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/minimal.rs @@ -6,7 +6,7 @@ use vecdb::{Exit, ReadableVec}; use crate::{ distribution::{cohorts::traits::DynCohortVecs, metrics::MinimalCohortMetrics}, - prices, + price, }; use super::UTXOCohortVecs; @@ -49,7 +49,7 @@ impl DynCohortVecs for UTXOCohortVecs { fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/mod.rs b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/mod.rs index f454d62a3..cfedfc50b 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/mod.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/mod.rs @@ -55,7 +55,7 @@ use crate::{ metrics::{CohortMetricsBase, CohortMetricsState}, state::UTXOCohortState, }, - prices, + price, }; #[derive(Traversable)] @@ -186,7 +186,7 @@ impl DynCohortVecs for UTXOCohortVecs { fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/type.rs b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/type.rs index df32af77f..fecee7ce4 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/vecs/type.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/vecs/type.rs @@ -5,7 +5,7 @@ use brk_types::{Cents, Height, Version}; use vecdb::{Exit, ReadableVec}; use crate::{ - distribution::cohorts::traits::DynCohortVecs, distribution::metrics::TypeCohortMetrics, prices, + distribution::cohorts::traits::DynCohortVecs, distribution::metrics::TypeCohortMetrics, price, }; use super::UTXOCohortVecs; @@ -55,7 +55,7 @@ impl DynCohortVecs for UTXOCohortVecs { fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/activity/core.rs b/crates/brk_computer/src/distribution/metrics/activity/core.rs index c833e0507..90137884e 100644 --- a/crates/brk_computer/src/distribution/metrics/activity/core.rs +++ b/crates/brk_computer/src/distribution/metrics/activity/core.rs @@ -11,7 +11,7 @@ use crate::{ state::{CohortState, CostBasisOps, RealizedOps}, }, internal::{PerBlockCumulativeRolling, ValuePerBlockCumulativeRolling}, - prices, + price, }; use super::ActivityMinimal; @@ -98,7 +98,7 @@ impl ActivityCore { pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/activity/full.rs b/crates/brk_computer/src/distribution/metrics/activity/full.rs index e20d43e02..2d605faa6 100644 --- a/crates/brk_computer/src/distribution/metrics/activity/full.rs +++ b/crates/brk_computer/src/distribution/metrics/activity/full.rs @@ -12,7 +12,7 @@ use crate::{ metrics::ImportConfig, state::{CohortState, CostBasisOps, RealizedOps}, }, - prices, + price, }; use super::ActivityCore; @@ -89,7 +89,7 @@ impl ActivityFull { pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/activity/minimal.rs b/crates/brk_computer/src/distribution/metrics/activity/minimal.rs index 03fb86a92..9398a510d 100644 --- a/crates/brk_computer/src/distribution/metrics/activity/minimal.rs +++ b/crates/brk_computer/src/distribution/metrics/activity/minimal.rs @@ -10,7 +10,7 @@ use crate::{ state::{CohortState, CostBasisOps, RealizedOps}, }, internal::ValuePerBlockCumulativeRolling, - prices, + price, }; #[derive(Traversable)] @@ -63,7 +63,7 @@ impl ActivityMinimal { pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/activity/mod.rs b/crates/brk_computer/src/distribution/metrics/activity/mod.rs index 567347e7b..e250c2871 100644 --- a/crates/brk_computer/src/distribution/metrics/activity/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/activity/mod.rs @@ -13,7 +13,7 @@ use vecdb::Exit; use crate::{ distribution::state::{CohortState, CostBasisOps, RealizedOps}, - prices, + price, }; pub trait ActivityLike: Send + Sync { @@ -30,7 +30,7 @@ pub trait ActivityLike: Send + Sync { ) -> Result<()>; fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()>; @@ -62,7 +62,7 @@ impl ActivityLike for ActivityCore { } fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -96,7 +96,7 @@ impl ActivityLike for ActivityFull { } fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/cohort/all.rs b/crates/brk_computer/src/distribution/metrics/cohort/all.rs index cd36fcbbd..f07a886ff 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/all.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/all.rs @@ -11,7 +11,7 @@ use crate::{ ActivityFull, AdjustedSopr, CohortMetricsBase, CostBasis, ImportConfig, OutputsBase, RealizedFull, RelativeForAll, SupplyCore, UnrealizedFull, }, - prices, + price, }; /// All-cohort metrics: extended realized + adjusted (as composable add-on), @@ -100,7 +100,7 @@ impl AllCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_market_cap: &impl ReadableVec, under_1h_value_created: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/cohort/basic.rs b/crates/brk_computer/src/distribution/metrics/cohort/basic.rs index 948e3f430..a51b7e46b 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/basic.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/basic.rs @@ -10,7 +10,7 @@ use crate::{ ActivityCore, CohortMetricsBase, ImportConfig, OutputsBase, RealizedCore, SupplyCore, UnrealizedCore, }, - prices, + price, }; /// Basic cohort metrics: no extensions, used by age_range cohorts. @@ -61,7 +61,7 @@ impl BasicCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/cohort/core.rs b/crates/brk_computer/src/distribution/metrics/cohort/core.rs index e9ba51e35..cdc52e396 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/core.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/core.rs @@ -10,7 +10,7 @@ use crate::{ ActivityCore, CohortMetricsBase, ImportConfig, OutputsBase, RealizedCore, SupplyCore, UnrealizedCore, }, - prices, + price, }; #[derive(Traversable)] @@ -102,7 +102,7 @@ impl CoreCohortMetrics { pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -122,7 +122,7 @@ impl CoreCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/cohort/extended.rs b/crates/brk_computer/src/distribution/metrics/cohort/extended.rs index c74be21c1..d36c37547 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/extended.rs @@ -12,7 +12,7 @@ use crate::{ ActivityFull, CohortMetricsBase, CostBasis, ImportConfig, OutputsBase, RealizedFull, RelativeWithExtended, SupplyCore, UnrealizedFull, }, - prices, + price, }; /// Cohort metrics with extended realized + extended cost basis (no adjusted). @@ -90,7 +90,7 @@ impl ExtendedCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_market_cap: &impl ReadableVec, all_supply_sats: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs b/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs index 8f8724f38..5e4beb751 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs @@ -10,7 +10,7 @@ use crate::{ distribution::metrics::{ ActivityFull, AdjustedSopr, CohortMetricsBase, ImportConfig, RealizedFull, UnrealizedFull, }, - prices, + price, }; use super::ExtendedCohortMetrics; @@ -62,7 +62,7 @@ impl ExtendedAdjustedCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_market_cap: &impl ReadableVec, under_1h_value_created: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/cohort/minimal.rs b/crates/brk_computer/src/distribution/metrics/cohort/minimal.rs index f130bda20..eb52dd23c 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/minimal.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/minimal.rs @@ -9,7 +9,7 @@ use crate::{ distribution::metrics::{ ActivityMinimal, ImportConfig, OutputsBase, RealizedMinimal, SupplyBase, UnrealizedMinimal, }, - prices, + price, }; /// MinimalCohortMetrics: supply, outputs, realized cap/price/mvrv/profit/loss + value_created/destroyed. @@ -97,7 +97,7 @@ impl MinimalCohortMetrics { pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -111,7 +111,7 @@ impl MinimalCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/cohort/type.rs b/crates/brk_computer/src/distribution/metrics/cohort/type.rs index ed3177a6b..4ff2127bb 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/type.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/type.rs @@ -9,7 +9,7 @@ use crate::{ distribution::metrics::{ ActivityMinimal, ImportConfig, OutputsBase, RealizedMinimal, SupplyCore, UnrealizedBasic, }, - prices, + price, }; /// TypeCohortMetrics: supply(core), outputs(base), realized(minimal), unrealized(basic). @@ -59,7 +59,7 @@ impl TypeCohortMetrics { pub(crate) fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -73,7 +73,7 @@ impl TypeCohortMetrics { pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, all_supply_sats: &impl ReadableVec, all_utxo_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/mod.rs b/crates/brk_computer/src/distribution/metrics/mod.rs index 5dfa55f25..c04b17ddd 100644 --- a/crates/brk_computer/src/distribution/metrics/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/mod.rs @@ -149,7 +149,7 @@ use crate::{ CohortState, CoreRealizedState, CostBasisData, CostBasisOps, CostBasisRaw, MinimalRealizedState, RealizedOps, RealizedState, WithCapital, WithoutCapital, }, - prices, + price, }; pub trait CohortMetricsState { @@ -270,7 +270,7 @@ pub trait CohortMetricsBase: /// First phase of computed metrics (indexes from height). fn compute_rest_part1( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/profitability.rs b/crates/brk_computer/src/distribution/metrics/profitability.rs index becb92d69..b4a72a1b2 100644 --- a/crates/brk_computer/src/distribution/metrics/profitability.rs +++ b/crates/brk_computer/src/distribution/metrics/profitability.rs @@ -10,7 +10,7 @@ use crate::{ internal::{ PerBlock, RatioPerBlock, ValuePerBlock, ValuePerBlockWithDeltas, WindowStartVec, Windows, }, - prices, + price, }; #[derive(Traversable)] @@ -115,7 +115,7 @@ impl ProfitabilityBucket { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, is_profit: bool, exit: &Exit, @@ -176,7 +176,7 @@ impl ProfitabilityBucket { pub(crate) fn compute_from_ranges( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, is_profit: bool, sources: &[&ProfitabilityBucket], @@ -293,7 +293,7 @@ impl ProfitabilityMetrics { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/realized/core.rs b/crates/brk_computer/src/distribution/metrics/realized/core.rs index caae24e51..81455e513 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/core.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/core.rs @@ -16,7 +16,7 @@ use crate::{ FiatPerBlockCumulativeWithSumsAndDeltas, LazyPerBlock, NegCentsUnsignedToDollars, PerBlockCumulativeRolling, RatioCents64, RollingWindow24hPerBlock, Windows, }, - prices, + price, }; use crate::distribution::metrics::ImportConfig; @@ -166,7 +166,7 @@ impl RealizedCore { pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_supply: &impl ReadableVec, transfer_volume_sum_24h_cents: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/realized/full.rs b/crates/brk_computer/src/distribution/metrics/realized/full.rs index df6345f1c..76832a6b4 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/full.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/full.rs @@ -18,7 +18,7 @@ use crate::{ RatioPerBlockStdDevBands, RatioSma, RollingWindows, RollingWindowsFrom1w, ValuePerBlockCumulativeRolling, }, - prices, + price, }; use crate::distribution::metrics::ImportConfig; @@ -240,7 +240,7 @@ impl RealizedFull { pub(crate) fn compute_rest_part2( &mut self, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_supply: &impl ReadableVec, height_to_market_cap: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/realized/minimal.rs b/crates/brk_computer/src/distribution/metrics/realized/minimal.rs index 7980806fb..0f30140c1 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/minimal.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/minimal.rs @@ -13,7 +13,7 @@ use crate::{ FiatPerBlockCumulativeWithSums, FiatPerBlockWithDeltas, Identity, LazyPerBlock, PriceWithRatioPerBlock, }, - prices, + price, }; use crate::distribution::metrics::ImportConfig; @@ -104,7 +104,7 @@ impl RealizedMinimal { pub(crate) fn compute_rest_part2( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, height_to_supply: &impl ReadableVec, exit: &Exit, diff --git a/crates/brk_computer/src/distribution/metrics/supply/avg_amount.rs b/crates/brk_computer/src/distribution/metrics/supply/avg_amount.rs index bc33f6802..f4120e7b6 100644 --- a/crates/brk_computer/src/distribution/metrics/supply/avg_amount.rs +++ b/crates/brk_computer/src/distribution/metrics/supply/avg_amount.rs @@ -3,7 +3,7 @@ use brk_traversable::Traversable; use brk_types::{Height, Sats, StoredU64, Version}; use vecdb::{AnyStoredVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec}; -use crate::{indexes, internal::ValuePerBlock, prices}; +use crate::{indexes, internal::ValuePerBlock, price}; /// Average amount held per UTXO and per funded address. /// @@ -53,7 +53,7 @@ impl AvgAmountMetrics { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, supply_sats: &impl ReadableVec, utxo_count: &impl ReadableVec, funded_addr_count: &impl ReadableVec, diff --git a/crates/brk_computer/src/distribution/metrics/supply/base.rs b/crates/brk_computer/src/distribution/metrics/supply/base.rs index 7a1519b60..8b8a835ec 100644 --- a/crates/brk_computer/src/distribution/metrics/supply/base.rs +++ b/crates/brk_computer/src/distribution/metrics/supply/base.rs @@ -6,7 +6,7 @@ use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVe use crate::{ distribution::state::{CohortState, CostBasisOps, RealizedOps}, - prices, + price, }; use crate::internal::{ @@ -64,7 +64,7 @@ impl SupplyBase { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, max_from: Height, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/supply/core.rs b/crates/brk_computer/src/distribution/metrics/supply/core.rs index 1de602ce3..4ee576c2a 100644 --- a/crates/brk_computer/src/distribution/metrics/supply/core.rs +++ b/crates/brk_computer/src/distribution/metrics/supply/core.rs @@ -5,7 +5,7 @@ use brk_types::{Height, Version}; use derive_more::{Deref, DerefMut}; use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec}; -use crate::{distribution::state::UnrealizedState, prices}; +use crate::{distribution::state::UnrealizedState, price}; use crate::internal::{ HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyValuePerBlock, ValuePerBlock, @@ -72,7 +72,7 @@ impl SupplyCore { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, max_from: Height, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/unrealized/full.rs b/crates/brk_computer/src/distribution/metrics/unrealized/full.rs index a9af8bc71..3dc2ffc6e 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized/full.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized/full.rs @@ -7,7 +7,7 @@ use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, use crate::distribution::state::UnrealizedState; use crate::internal::{CentsSubtractToCentsSigned, FiatPerBlock}; -use crate::{distribution::metrics::ImportConfig, prices}; +use crate::{distribution::metrics::ImportConfig, price}; use super::UnrealizedCore; @@ -99,7 +99,7 @@ impl UnrealizedFull { pub(crate) fn compute_rest_all( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, supply_in_profit_sats: &(impl ReadableVec + Sync), supply_in_loss_sats: &(impl ReadableVec + Sync), diff --git a/crates/brk_computer/src/distribution/metrics/unrealized/mod.rs b/crates/brk_computer/src/distribution/metrics/unrealized/mod.rs index 073642b5f..38947d47b 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized/mod.rs @@ -13,7 +13,7 @@ use brk_indexer::Lengths; use brk_types::{Height, Sats}; use vecdb::{Exit, ReadableVec}; -use crate::{distribution::state::UnrealizedState, prices}; +use crate::{distribution::state::UnrealizedState, price}; pub trait UnrealizedLike: Send + Sync { fn as_core(&self) -> &UnrealizedCore; @@ -22,7 +22,7 @@ pub trait UnrealizedLike: Send + Sync { fn push_state(&mut self, state: &UnrealizedState); fn compute_rest( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, supply_in_profit_sats: &(impl ReadableVec + Sync), supply_in_loss_sats: &(impl ReadableVec + Sync), @@ -46,7 +46,7 @@ impl UnrealizedLike for UnrealizedCore { } fn compute_rest( &mut self, - _prices: &prices::Vecs, + _prices: &price::Vecs, starting_lengths: &Lengths, _supply_in_profit_sats: &(impl ReadableVec + Sync), _supply_in_loss_sats: &(impl ReadableVec + Sync), @@ -72,7 +72,7 @@ impl UnrealizedLike for UnrealizedFull { } fn compute_rest( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, supply_in_profit_sats: &(impl ReadableVec + Sync), supply_in_loss_sats: &(impl ReadableVec + Sync), diff --git a/crates/brk_computer/src/distribution/vecs.rs b/crates/brk_computer/src/distribution/vecs.rs index c87d158d9..9c948f74b 100644 --- a/crates/brk_computer/src/distribution/vecs.rs +++ b/crates/brk_computer/src/distribution/vecs.rs @@ -29,7 +29,7 @@ use crate::{ PerBlockCumulativeRolling, WindowStartVec, Windows, WithAddrTypes, db_utils::{finalize_db, open_db}, }, - outputs, prices, transactions, + outputs, price, transactions, }; use super::{ @@ -316,7 +316,7 @@ impl Vecs { outputs: &outputs::Vecs, transactions: &transactions::Vecs, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.db.sync_bg_tasks()?; diff --git a/crates/brk_computer/src/indicators/rarity_meter/mod.rs b/crates/brk_computer/src/indicators/rarity_meter/mod.rs index dfa2d412e..3d9568c9b 100644 --- a/crates/brk_computer/src/indicators/rarity_meter/mod.rs +++ b/crates/brk_computer/src/indicators/rarity_meter/mod.rs @@ -6,7 +6,7 @@ use brk_traversable::Traversable; use brk_types::Version; use vecdb::{Database, Exit, Rw, StorageMode}; -use crate::{distribution, indexes, prices}; +use crate::{distribution, indexes, price}; pub use inner::RarityMeterInner; @@ -37,7 +37,7 @@ impl RarityMeter { &mut self, indexer: &Indexer, distribution: &distribution::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { let realized = &distribution.utxo_cohorts.all.metrics.realized; diff --git a/crates/brk_computer/src/internal/per_block/ratio/price_extended.rs b/crates/brk_computer/src/internal/per_block/ratio/price_extended.rs index 358d827d8..18f2922a5 100644 --- a/crates/brk_computer/src/internal/per_block/ratio/price_extended.rs +++ b/crates/brk_computer/src/internal/per_block/ratio/price_extended.rs @@ -6,7 +6,7 @@ use derive_more::{Deref, DerefMut}; use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode}; use crate::internal::{LazyPerBlock, PerBlock, Price}; -use crate::{indexes, prices}; +use crate::{indexes, price}; use super::{RatioPerBlock, RatioPerBlockPercentiles}; @@ -63,7 +63,7 @@ impl PriceWithRatioPerBlock { /// Compute price via closure (in cents), then compute ratio. pub(crate) fn compute_all( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, mut compute_price: F, @@ -101,7 +101,7 @@ impl PriceWithRatioExtendedPerBlock { /// Compute ratio and percentiles from already-computed price cents. pub(crate) fn compute_rest( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, ) -> Result<()> { @@ -120,7 +120,7 @@ impl PriceWithRatioExtendedPerBlock { /// Compute price via closure (in cents), then compute ratio and percentiles. pub(crate) fn compute_all( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, starting_lengths: &Lengths, exit: &Exit, mut compute_price: F, diff --git a/crates/brk_computer/src/internal/per_block/value/base.rs b/crates/brk_computer/src/internal/per_block/value/base.rs index 5c0a70937..f296b7f83 100644 --- a/crates/brk_computer/src/internal/per_block/value/base.rs +++ b/crates/brk_computer/src/internal/per_block/value/base.rs @@ -10,7 +10,7 @@ use crate::{ CentsUnsignedToDollars, LazyPerBlock, NumericValue, PerBlock, SatsSignedToBitcoin, SatsToBitcoin, SatsToCents, }, - prices, + price, }; /// Trait that associates a sats type with its transform to Bitcoin. @@ -69,7 +69,7 @@ impl ValuePerBlock { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, max_from: Height, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/internal/per_block/value/block.rs b/crates/brk_computer/src/internal/per_block/value/block.rs index 8fa5669ba..f619c10fe 100644 --- a/crates/brk_computer/src/internal/per_block/value/block.rs +++ b/crates/brk_computer/src/internal/per_block/value/block.rs @@ -8,7 +8,7 @@ use vecdb::{ use crate::{ internal::{CentsUnsignedToDollars, SatsToBitcoin, SatsToCents}, - prices, + price, }; /// Raw per-block amount data: sats + cents (stored), btc + usd (lazy), no resolutions. @@ -44,7 +44,7 @@ impl ValueBlock { pub(crate) fn compute_cents( &mut self, max_from: Height, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.cents.compute_binary::( diff --git a/crates/brk_computer/src/internal/per_block/value/cumulative.rs b/crates/brk_computer/src/internal/per_block/value/cumulative.rs index 17c8eac4f..23c51cf00 100644 --- a/crates/brk_computer/src/internal/per_block/value/cumulative.rs +++ b/crates/brk_computer/src/internal/per_block/value/cumulative.rs @@ -6,7 +6,7 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode}; use crate::{ indexes, internal::{ValueBlock, ValuePerBlock}, - prices, + price, }; #[derive(Traversable)] @@ -39,7 +39,7 @@ impl ValuePerBlockCumulative { pub(crate) fn compute( &mut self, - prices: &prices::Vecs, + prices: &price::Vecs, max_from: Height, exit: &Exit, ) -> Result<()> { @@ -61,7 +61,7 @@ impl ValuePerBlockCumulative { pub(crate) fn compute_with( &mut self, max_from: Height, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, compute_sats: impl FnOnce(&mut EagerVec>) -> Result<()>, ) -> Result<()> { diff --git a/crates/brk_computer/src/internal/per_block/value/cumulative_rolling.rs b/crates/brk_computer/src/internal/per_block/value/cumulative_rolling.rs index 1bbfbc804..51d7fed15 100644 --- a/crates/brk_computer/src/internal/per_block/value/cumulative_rolling.rs +++ b/crates/brk_computer/src/internal/per_block/value/cumulative_rolling.rs @@ -10,7 +10,7 @@ use crate::{ LazyRollingAvgsAmountFromHeight, LazyRollingSumsAmountFromHeight, ValuePerBlockCumulative, WindowStartVec, Windows, }, - prices, + price, }; #[derive(Deref, DerefMut, Traversable)] @@ -63,7 +63,7 @@ impl ValuePerBlockCumulativeRolling { pub(crate) fn compute( &mut self, max_from: Height, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, compute_sats: impl FnOnce(&mut EagerVec>) -> Result<()>, ) -> Result<()> { @@ -74,7 +74,7 @@ impl ValuePerBlockCumulativeRolling { pub(crate) fn compute_rest( &mut self, max_from: Height, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.inner.compute(prices, max_from, exit) diff --git a/crates/brk_computer/src/internal/per_block/value/full.rs b/crates/brk_computer/src/internal/per_block/value/full.rs index ca4f7cd34..c92a0ad7a 100644 --- a/crates/brk_computer/src/internal/per_block/value/full.rs +++ b/crates/brk_computer/src/internal/per_block/value/full.rs @@ -10,7 +10,7 @@ use crate::{ RollingDistributionValuePerBlock, ValuePerBlockCumulativeRolling, WindowStartVec, WindowStarts, Windows, }, - prices, + price, }; #[derive(Deref, DerefMut, Traversable)] @@ -49,7 +49,7 @@ impl ValuePerBlockFull { &mut self, max_from: Height, windows: &WindowStarts<'_>, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, compute_sats: impl FnOnce(&mut EagerVec>) -> Result<()>, ) -> Result<()> { diff --git a/crates/brk_computer/src/internal/with_addr_types.rs b/crates/brk_computer/src/internal/with_addr_types.rs index f68427e5f..ecf4b3a9d 100644 --- a/crates/brk_computer/src/internal/with_addr_types.rs +++ b/crates/brk_computer/src/internal/with_addr_types.rs @@ -11,7 +11,7 @@ use rayon::prelude::*; use schemars::JsonSchema; use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, WritableVec}; -use crate::{indexes, prices}; +use crate::{indexes, price}; use super::{ BpsType, NumericValue, PerBlock, PerBlockCumulativeRolling, PercentPerBlock, ValuePerBlock, @@ -229,7 +229,7 @@ impl WithAddrTypes { pub(crate) fn compute_rest( &mut self, max_from: Height, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.all.compute(prices, max_from, exit)?; diff --git a/crates/brk_computer/src/investing/compute.rs b/crates/brk_computer/src/investing/compute.rs index 9a3d2332b..f07e83f35 100644 --- a/crates/brk_computer/src/investing/compute.rs +++ b/crates/brk_computer/src/investing/compute.rs @@ -4,7 +4,7 @@ use brk_types::{BasisPointsSigned32, Bitcoin, Cents, Date, Day1, Dollars, Sats}; use vecdb::{AnyVec, Exit, ReadableOptionVec, ReadableVec, VecIndex}; use super::{ByDcaPeriod, Vecs}; -use crate::{blocks, indexes, internal::RatioDiffCentsBps32, market, prices}; +use crate::{blocks, indexes, internal::RatioDiffCentsBps32, market, price}; const DCA_AMOUNT: Dollars = Dollars::mint(100.0); @@ -13,7 +13,7 @@ impl Vecs { &mut self, indexer: &Indexer, indexes: &indexes::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, blocks: &blocks::Vecs, lookback: &market::lookback::Vecs, exit: &Exit, diff --git a/crates/brk_computer/src/lib.rs b/crates/brk_computer/src/lib.rs index c7e51c2d8..7f31688d4 100644 --- a/crates/brk_computer/src/lib.rs +++ b/crates/brk_computer/src/lib.rs @@ -22,7 +22,7 @@ mod market; mod mining; mod outputs; mod pools; -pub mod prices; +pub mod price; mod supply; mod transactions; @@ -38,7 +38,7 @@ pub struct Computer { pub investing: Box>, pub market: Box>, pub pools: Box>, - pub prices: Box>, + pub price: Box>, #[traversable(flatten)] pub distribution: Box>, pub supply: Box>, @@ -66,14 +66,14 @@ impl Computer { )?)) })?; - let (constants, prices) = timed("Imported prices/constants", || -> Result<_> { + let (constants, price) = timed("Imported price/constants", || -> Result<_> { let constants = Box::new(constants::Vecs::new(VERSION, &indexes)); - let prices = Box::new(prices::Vecs::forced_import( + let price = Box::new(price::Vecs::forced_import( &computed_path, VERSION, &indexes, )?); - Ok((constants, prices)) + Ok((constants, price)) })?; let blocks = timed("Imported blocks", || -> Result<_> { @@ -223,7 +223,7 @@ impl Computer { cointime, indexes, inputs, - prices, + price, outputs, }; @@ -244,7 +244,7 @@ impl Computer { investing::DB_NAME, market::DB_NAME, pools::DB_NAME, - prices::DB_NAME, + price::DB_NAME, distribution::DB_NAME, supply::DB_NAME, inputs::DB_NAME, @@ -297,8 +297,8 @@ impl Computer { }) }, || { - timed("Computed prices", || { - self.prices.compute(indexer, &self.indexes, exit) + timed("Computed price", || { + self.price.compute(indexer, &self.indexes, exit) }) }, ); @@ -310,7 +310,7 @@ impl Computer { let market = scope.spawn(|| { timed("Computed market", || { self.market - .compute(indexer, &self.prices, &self.indexes, &self.blocks, exit) + .compute(indexer, &self.price, &self.indexes, &self.blocks, exit) }) }); @@ -321,7 +321,7 @@ impl Computer { &self.indexes, &self.blocks, &self.inputs, - &self.prices, + &self.price, exit, ) })?; @@ -331,7 +331,7 @@ impl Computer { &self.indexes, &self.blocks, &self.transactions, - &self.prices, + &self.price, exit, ) }) @@ -343,7 +343,7 @@ impl Computer { &self.indexes, &self.inputs, &self.blocks, - &self.prices, + &self.price, exit, ) })?; @@ -360,7 +360,7 @@ impl Computer { indexer, &self.indexes, &self.blocks, - &self.prices, + &self.price, &self.mining, exit, ) @@ -372,7 +372,7 @@ impl Computer { self.investing.compute( indexer, &self.indexes, - &self.prices, + &self.price, &self.blocks, &self.market.lookback, exit, @@ -388,7 +388,7 @@ impl Computer { &self.outputs, &self.transactions, &self.blocks, - &self.prices, + &self.price, exit, ) })?; @@ -421,7 +421,7 @@ impl Computer { &self.blocks, &self.mining, &self.transactions, - &self.prices, + &self.price, &self.distribution, exit, ) @@ -430,7 +430,7 @@ impl Computer { timed("Computed cointime", || { self.cointime.compute( indexer, - &self.prices, + &self.price, &self.blocks, &self.mining, &self.supply, @@ -445,7 +445,7 @@ impl Computer { self.indicators .rarity_meter - .compute(indexer, &self.distribution, &self.prices, exit)?; + .compute(indexer, &self.distribution, &self.price, exit)?; info!("Total compute time: {:?}", compute_start.elapsed()); Ok(()) @@ -498,7 +498,7 @@ impl_iter_named!( investing, market, pools, - prices, + price, distribution, supply, inputs, diff --git a/crates/brk_computer/src/market/ath/compute.rs b/crates/brk_computer/src/market/ath/compute.rs index 6a3a45aae..ce3d66c2d 100644 --- a/crates/brk_computer/src/market/ath/compute.rs +++ b/crates/brk_computer/src/market/ath/compute.rs @@ -4,13 +4,13 @@ use brk_types::{StoredF32, Timestamp}; use vecdb::{Exit, ReadableVec, VecIndex}; use super::Vecs; -use crate::{indexes, prices}; +use crate::{indexes, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, indexes: &indexes::Vecs, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/market/compute.rs b/crates/brk_computer/src/market/compute.rs index 3df1ffd84..f8fa98967 100644 --- a/crates/brk_computer/src/market/compute.rs +++ b/crates/brk_computer/src/market/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use brk_indexer::Indexer; use vecdb::Exit; -use crate::{blocks, indexes, prices}; +use crate::{blocks, indexes, price}; use super::Vecs; @@ -10,7 +10,7 @@ impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, indexes: &indexes::Vecs, blocks: &blocks::Vecs, exit: &Exit, diff --git a/crates/brk_computer/src/market/lookback/compute.rs b/crates/brk_computer/src/market/lookback/compute.rs index c356e8105..50bbe5875 100644 --- a/crates/brk_computer/src/market/lookback/compute.rs +++ b/crates/brk_computer/src/market/lookback/compute.rs @@ -3,14 +3,14 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::Vecs; -use crate::{blocks, prices}; +use crate::{blocks, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { let starting_height = indexer.safe_lengths().height; diff --git a/crates/brk_computer/src/market/moving_average/compute.rs b/crates/brk_computer/src/market/moving_average/compute.rs index 7f4c8c498..a062858e8 100644 --- a/crates/brk_computer/src/market/moving_average/compute.rs +++ b/crates/brk_computer/src/market/moving_average/compute.rs @@ -3,14 +3,14 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::Vecs; -use crate::{blocks, prices}; +use crate::{blocks, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { let starting_lengths = indexer.safe_lengths(); diff --git a/crates/brk_computer/src/market/range/compute.rs b/crates/brk_computer/src/market/range/compute.rs index 8fb436137..6f791e620 100644 --- a/crates/brk_computer/src/market/range/compute.rs +++ b/crates/brk_computer/src/market/range/compute.rs @@ -4,13 +4,13 @@ use brk_types::{BasisPoints16, StoredF32}; use vecdb::{Exit, ReadableVec, VecIndex}; use super::Vecs; -use crate::{blocks, prices}; +use crate::{blocks, price}; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, blocks: &blocks::Vecs, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/market/returns/compute.rs b/crates/brk_computer/src/market/returns/compute.rs index 6defdf674..086a840e0 100644 --- a/crates/brk_computer/src/market/returns/compute.rs +++ b/crates/brk_computer/src/market/returns/compute.rs @@ -5,14 +5,14 @@ use vecdb::Exit; use super::Vecs; use crate::{ - blocks, internal::RatioDiffDollarsBps32, investing::ByDcaPeriod, market::lookback, prices, + blocks, internal::RatioDiffDollarsBps32, investing::ByDcaPeriod, market::lookback, price, }; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, blocks: &blocks::Vecs, lookback: &lookback::Vecs, exit: &Exit, diff --git a/crates/brk_computer/src/market/technical/compute.rs b/crates/brk_computer/src/market/technical/compute.rs index 1d25e7456..a50178561 100644 --- a/crates/brk_computer/src/market/technical/compute.rs +++ b/crates/brk_computer/src/market/technical/compute.rs @@ -10,7 +10,7 @@ use super::{ use crate::{ blocks, internal::{RatioDollarsBp32, WindowsTo1m}, - prices, + price, }; impl Vecs { @@ -19,7 +19,7 @@ impl Vecs { &mut self, indexer: &Indexer, returns: &returns::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, blocks: &blocks::Vecs, moving_average: &moving_average::Vecs, exit: &Exit, diff --git a/crates/brk_computer/src/market/technical/macd.rs b/crates/brk_computer/src/market/technical/macd.rs index 522c8a2c8..379d50c78 100644 --- a/crates/brk_computer/src/market/technical/macd.rs +++ b/crates/brk_computer/src/market/technical/macd.rs @@ -3,14 +3,14 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::MacdChain; -use crate::{blocks, prices}; +use crate::{blocks, price}; #[allow(clippy::too_many_arguments)] pub(super) fn compute( chain: &mut MacdChain, indexer: &Indexer, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, fast_days: usize, slow_days: usize, signal_days: usize, diff --git a/crates/brk_computer/src/mining/compute.rs b/crates/brk_computer/src/mining/compute.rs index 8dd36d4f6..ed8cf647b 100644 --- a/crates/brk_computer/src/mining/compute.rs +++ b/crates/brk_computer/src/mining/compute.rs @@ -3,7 +3,7 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::Vecs; -use crate::{blocks, indexes, prices, transactions}; +use crate::{blocks, indexes, price, transactions}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -13,7 +13,7 @@ impl Vecs { indexes: &indexes::Vecs, blocks: &blocks::Vecs, transactions: &transactions::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.db.sync_bg_tasks()?; diff --git a/crates/brk_computer/src/mining/rewards/compute.rs b/crates/brk_computer/src/mining/rewards/compute.rs index 10cfc5623..1b7e88721 100644 --- a/crates/brk_computer/src/mining/rewards/compute.rs +++ b/crates/brk_computer/src/mining/rewards/compute.rs @@ -7,7 +7,7 @@ use super::Vecs; use crate::{ blocks, indexes, internal::{RatioDollarsBp32, RatioSatsBp16}, - prices, transactions, + price, transactions, }; impl Vecs { @@ -18,7 +18,7 @@ impl Vecs { indexes: &indexes::Vecs, lookback: &blocks::LookbackVecs, transactions: &transactions::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { let starting_height = indexer.safe_lengths().height; diff --git a/crates/brk_computer/src/outputs/compute.rs b/crates/brk_computer/src/outputs/compute.rs index 47d429a74..99d327eb5 100644 --- a/crates/brk_computer/src/outputs/compute.rs +++ b/crates/brk_computer/src/outputs/compute.rs @@ -3,7 +3,7 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::Vecs; -use crate::{blocks, indexes, inputs, prices}; +use crate::{blocks, indexes, inputs, price}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -13,7 +13,7 @@ impl Vecs { indexes: &indexes::Vecs, inputs: &inputs::Vecs, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.db.sync_bg_tasks()?; diff --git a/crates/brk_computer/src/outputs/value/compute.rs b/crates/brk_computer/src/outputs/value/compute.rs index d601b5ace..9fb9f8542 100644 --- a/crates/brk_computer/src/outputs/value/compute.rs +++ b/crates/brk_computer/src/outputs/value/compute.rs @@ -4,13 +4,13 @@ use brk_types::{Height, OutputType, Sats, TxOutIndex}; use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec}; use super::Vecs; -use crate::prices; +use crate::price; impl Vecs { pub(crate) fn compute( &mut self, indexer: &Indexer, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { let starting_lengths = indexer.safe_lengths(); diff --git a/crates/brk_computer/src/pools/major.rs b/crates/brk_computer/src/pools/major.rs index d50c53e2a..c9c478cf1 100644 --- a/crates/brk_computer/src/pools/major.rs +++ b/crates/brk_computer/src/pools/major.rs @@ -11,7 +11,7 @@ use crate::{ MaskSats, PercentRollingWindows, RatioU64Bp16, ValuePerBlockCumulativeRolling, WindowStartVec, Windows, }, - mining, prices, + mining, price, }; use super::minor; @@ -63,7 +63,7 @@ impl Vecs { indexer: &Indexer, pool: &impl ReadableVec, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, mining: &mining::Vecs, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/pools/mod.rs b/crates/brk_computer/src/pools/mod.rs index be86e8eca..54793f13e 100644 --- a/crates/brk_computer/src/pools/mod.rs +++ b/crates/brk_computer/src/pools/mod.rs @@ -22,7 +22,7 @@ use crate::{ WindowStartVec, Windows, db_utils::{finalize_db, open_db}, }, - mining, prices, + mining, price, }; pub const DB_NAME: &str = "pools"; @@ -90,7 +90,7 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, blocks: &blocks::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, mining: &mining::Vecs, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/prices/by_unit.rs b/crates/brk_computer/src/price/by_unit.rs similarity index 100% rename from crates/brk_computer/src/prices/by_unit.rs rename to crates/brk_computer/src/price/by_unit.rs diff --git a/crates/brk_computer/src/prices/compute.rs b/crates/brk_computer/src/price/compute.rs similarity index 91% rename from crates/brk_computer/src/prices/compute.rs rename to crates/brk_computer/src/price/compute.rs index 8c640d06e..f743a93e7 100644 --- a/crates/brk_computer/src/prices/compute.rs +++ b/crates/brk_computer/src/price/compute.rs @@ -3,8 +3,8 @@ use std::ops::Range; use brk_error::Result; use brk_indexer::{Indexer, Lengths}; use brk_oracle::{ - bin_to_cents, cents_to_bin, for_each_round_dollar_bin, Config, HistogramRaw, Oracle, - START_HEIGHT_FAST, START_HEIGHT_SLOW, + Config, Oracle, START_HEIGHT_FAST, START_HEIGHT_SLOW, bin_to_cents, cents_to_bin, + payment_histogram, }; use brk_types::{Cents, OutputType, Sats, TxIndex, TxOutIndex}; use tracing::info; @@ -87,16 +87,11 @@ impl Vecs { .truncate_if_needed_at(truncate_to)?; if self.spot.cents.height.len() < START_HEIGHT_SLOW { - for line in brk_oracle::PRICES - .lines() - .skip(self.spot.cents.height.len()) - { + for cents in brk_oracle::pre_oracle_prices_from(self.spot.cents.height.len()) { if self.spot.cents.height.len() >= START_HEIGHT_SLOW { break; } - let dollars: f64 = line.parse().unwrap_or(0.0); - let cents = (dollars * 100.0).round() as u64; - self.spot.cents.height.inner.push(Cents::new(cents)); + self.spot.cents.height.inner.push(cents); } } @@ -183,8 +178,7 @@ impl Vecs { } /// Feed a range of blocks from the indexer into an Oracle (skipping coinbase), - /// returning per-block ref_bin values. Outputs are grouped per transaction - /// because `for_each_round_dollar_bin` drops a whole tx on any OP_RETURN. + /// returning per-block ref_bin values. /// /// Pass `cap = None` from compute paths, when the indexer is quiescent and /// raw vec lengths are authoritative. Pass `cap = Some(&safe_lengths)` from @@ -293,21 +287,18 @@ impl Vecs { &mut output_types, ); - let mut hist = HistogramRaw::zeros(); - for tx in 0..tx_count { + let tx_outputs = (0..tx_count).map(|tx| { let lo = tx_starts[tx] - out_start; let hi = tx_starts .get(tx + 1) .map(|s| s - out_start) .unwrap_or(out_end - out_start); - let outputs = values[lo..hi] + values[lo..hi] .iter() .copied() - .zip(output_types[lo..hi].iter().copied()); - for_each_round_dollar_bin(range.start + idx, outputs, |bin| { - hist.increment(bin as usize) - }); - } + .zip(output_types[lo..hi].iter().copied()) + }); + let hist = payment_histogram(range.start + idx, tx_outputs); let ref_bin = oracle.process_histogram(&hist); on_block(range.start + idx, oracle, ref_bin); diff --git a/crates/brk_computer/src/prices/mod.rs b/crates/brk_computer/src/price/mod.rs similarity index 99% rename from crates/brk_computer/src/prices/mod.rs rename to crates/brk_computer/src/price/mod.rs index 9b0376fd8..b6dae9f78 100644 --- a/crates/brk_computer/src/prices/mod.rs +++ b/crates/brk_computer/src/price/mod.rs @@ -21,7 +21,7 @@ use crate::{ use by_unit::{OhlcByUnit, PriceByUnit, SplitByUnit, SplitCloseByUnit, SplitIndexesByUnit}; use ohlcs::{LazyOhlcVecs, OhlcVecs}; -pub const DB_NAME: &str = "prices"; +pub const DB_NAME: &str = "price"; #[derive(Traversable)] pub struct Vecs { diff --git a/crates/brk_computer/src/prices/ohlcs.rs b/crates/brk_computer/src/price/ohlcs.rs similarity index 100% rename from crates/brk_computer/src/prices/ohlcs.rs rename to crates/brk_computer/src/price/ohlcs.rs diff --git a/crates/brk_computer/src/supply/burned/compute.rs b/crates/brk_computer/src/supply/burned/compute.rs index b544ff142..855e969ad 100644 --- a/crates/brk_computer/src/supply/burned/compute.rs +++ b/crates/brk_computer/src/supply/burned/compute.rs @@ -4,7 +4,7 @@ use brk_types::Sats; use vecdb::{Exit, VecIndex}; use super::Vecs; -use crate::{mining, outputs, prices}; +use crate::{mining, outputs, price}; impl Vecs { pub(crate) fn compute( @@ -12,7 +12,7 @@ impl Vecs { indexer: &Indexer, outputs: &outputs::Vecs, mining: &mining::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { let starting_height = indexer.safe_lengths().height; diff --git a/crates/brk_computer/src/supply/compute.rs b/crates/brk_computer/src/supply/compute.rs index ca717a4c0..e5369df1a 100644 --- a/crates/brk_computer/src/supply/compute.rs +++ b/crates/brk_computer/src/supply/compute.rs @@ -7,7 +7,7 @@ use vecdb::Exit; const INITIAL_SUBSIDY: f64 = Sats::ONE_BTC_U64 as f64 * 50.0; use super::Vecs; -use crate::{blocks, distribution, mining, outputs, prices, transactions}; +use crate::{blocks, distribution, mining, outputs, price, transactions}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -18,7 +18,7 @@ impl Vecs { blocks: &blocks::Vecs, mining: &mining::Vecs, transactions: &transactions::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, distribution: &distribution::Vecs, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/transactions/compute.rs b/crates/brk_computer/src/transactions/compute.rs index 1656257fe..6f67a3dbf 100644 --- a/crates/brk_computer/src/transactions/compute.rs +++ b/crates/brk_computer/src/transactions/compute.rs @@ -3,7 +3,7 @@ use brk_indexer::Indexer; use vecdb::Exit; use super::Vecs; -use crate::{blocks, indexes, inputs, prices}; +use crate::{blocks, indexes, inputs, price}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -13,7 +13,7 @@ impl Vecs { indexes: &indexes::Vecs, blocks: &blocks::Vecs, inputs: &inputs::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, exit: &Exit, ) -> Result<()> { self.db.sync_bg_tasks()?; diff --git a/crates/brk_computer/src/transactions/volume/compute.rs b/crates/brk_computer/src/transactions/volume/compute.rs index 3b5d944dc..a54102d6e 100644 --- a/crates/brk_computer/src/transactions/volume/compute.rs +++ b/crates/brk_computer/src/transactions/volume/compute.rs @@ -5,7 +5,7 @@ use vecdb::Exit; use super::Vecs; use crate::transactions::{count, fees}; -use crate::{indexes, internal::Windows, prices}; +use crate::{indexes, internal::Windows, price}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -13,7 +13,7 @@ impl Vecs { &mut self, indexer: &Indexer, indexes: &indexes::Vecs, - prices: &prices::Vecs, + prices: &price::Vecs, count_vecs: &count::Vecs, fees_vecs: &fees::Vecs, exit: &Exit, diff --git a/crates/brk_mempool/src/stores/live_histograms.rs b/crates/brk_mempool/src/stores/live_histograms.rs index 0c24cf260..bebe32877 100644 --- a/crates/brk_mempool/src/stores/live_histograms.rs +++ b/crates/brk_mempool/src/stores/live_histograms.rs @@ -1,4 +1,4 @@ -use brk_oracle::{HistogramRaw, for_each_round_dollar_bin, sats_to_bin}; +use brk_oracle::{for_each_modern_round_dollar_bin, sats_to_bin, HistogramRaw}; use brk_types::Transaction; use crate::stores::tx_store::TxRecord; @@ -43,14 +43,9 @@ impl LiveHistograms { /// Round-dollar-eligible bins, applying the oracle payment filter. Calls /// `emit(bin)` per eligible output. Deterministic over a tx's outputs, /// which are never mutated after insert, so add and remove recompute it - /// identically rather than caching. Live mempool txs are post-tip, always - /// above the historical max-outputs cap window, so the cap never applies. + /// identically rather than caching. fn eligible_bins(tx: &Transaction, emit: impl FnMut(u16)) { - for_each_round_dollar_bin( - usize::MAX, - tx.output.iter().map(|o| (o.value, o.type_())), - emit, - ); + for_each_modern_round_dollar_bin(tx.output.iter().map(|o| (o.value, o.type_())), emit); } /// Raw bin index per output, dropping only values outside the bin domain diff --git a/crates/brk_oracle/README.md b/crates/brk_oracle/README.md index a8327c9a6..328515914 100644 --- a/crates/brk_oracle/README.md +++ b/crates/brk_oracle/README.md @@ -48,7 +48,7 @@ For each new block: ### 1. Filter outputs -Skip the coinbase transaction, and skip every output of a transaction carrying an `OP_RETURN`: that transaction is protocol machinery, not a dollar-denominated payment, so its payout amounts are not price signal. Below height 630,000, also skip every output of a transaction with more than 100 outputs: a large fan-out is a batch payout (exchange sweep, mixer), not a round-dollar payment, and the thin early signal needs it removed. Then exclude noisy outputs: script types dominated by protocol activity (P2TR by default), dust below 1,000 sats, and round BTC amounts (0.01, 0.1, 1.0 BTC, etc.) that create false spikes unrelated to dollar purchases. +Skip the coinbase transaction, and skip every output of a transaction carrying an `OP_RETURN`: that transaction is protocol machinery, not a dollar-denominated payment, so its payout amounts are not price signal. Below height 630,000, also skip every output of a transaction with more than 100 outputs: a large fan-out is a batch payout (exchange sweep, mixer), not a round-dollar payment, and the thin early signal needs it removed. At and above height 630,000, the transaction fan-out cap relaxes to 250 outputs so dense-chain payment activity remains visible while very large fan-outs cannot dominate one EMA slot. Then exclude noisy outputs: script types dominated by protocol activity (P2TR by default), dust below 1,000 sats, and round BTC amounts (0.01, 0.1, 1.0 BTC, etc.) that create false spikes unrelated to dollar purchases. ### 2. Build a log-scale histogram @@ -122,9 +122,9 @@ Parabolic interpolation between the best bin and its two neighbors refines the e The oracle consumes one pre-built histogram per block via `process_histogram(&hist)`, a `[u32; 2400]` bin-count array, and returns the updated reference bin. -The caller filters as it builds the histogram, applying the [step 1](#1-filter-outputs) rules. Two helpers are exported for this: `eligible_bin(sats, output_type)` returns an output's bin index, or `None` if filtered, and `for_each_round_dollar_bin` wraps it with the per-transaction drops (coinbase, OP_RETURN, the >100-output cap below height 630,000) for callers holding a whole transaction's outputs. +The caller filters as it builds the histogram, applying the [step 1](#1-filter-outputs) rules. `payment_histogram` builds a fresh block histogram from non-coinbase transaction outputs. Incremental callers use `for_each_round_dollar_bin(height, ...)`; live or otherwise guaranteed-modern callers use `for_each_modern_round_dollar_bin(...)`, which applies the modern fan-out cap without requiring a height. `eligible_bin(sats, output_type)` returns an individual output's bin index, or `None` if filtered. The transaction-level rules include the OP_RETURN drop, the >100 transaction-output fan-out cap below height 630,000, and the >250 cap from height 630,000 onward. -The initial seed must be close to the real price at the starting height. The crate includes a `PRICES` constant with exchange prices for heights 0..340,000. Its last entry, height 339,999 (one below `START_HEIGHT_SLOW`), seeds the oracle's first on-chain computation at height 340,000. +The initial seed must be close to the real price at the starting height. The crate includes typed pre-oracle helpers for exchange prices at heights 0..340,000. `Oracle::from_seed()` uses the last baked price, height 339,999 (one below `START_HEIGHT_SLOW`), and the slow cold-start config to seed the oracle's first on-chain computation at height 340,000. ## Configuration @@ -161,7 +161,7 @@ Between heights 340,000 and 508,000 the oracle runs a slower cold-start configur ## Accuracy -Tested over 596,251 blocks (heights 340,000 to 950,800, as of May 2026) against exchange OHLC data. Error is measured per block as distance from the oracle estimate to the exchange high/low range at that height. If the oracle falls within the range, the error is zero. +Tested over 596,251 exchange-covered blocks after running the oracle from height 340,000 through height 952,314. Error is measured per block as distance from the oracle estimate to the exchange high/low range at that height. If the oracle falls within the range, the error is zero. ### Per-block @@ -173,9 +173,9 @@ Tested over 596,251 blocks (heights 340,000 to 950,800, as of May 2026) against | 99.9th percentile | 15.6% | | RMSE | 0.97% | | Max error | 33.8% | -| Bias | +0.05 bins (essentially zero) | -| Blocks > 5% error | 3,235 (0.543%) | -| Blocks > 10% error | 1,324 | +| Bias | +0.06 bins (essentially zero) | +| Blocks > 5% error | 3,233 (0.542%) | +| Blocks > 10% error | 1,323 | | Blocks > 20% error | 154 | ### Daily candles @@ -185,7 +185,7 @@ Oracle daily OHLC built from per-block prices vs exchange daily OHLC: | | Median | RMSE | Max | |-------|--------|------|-----| | Open | 0.24% | 1.07% | 29.1% | -| High | 0.58% | 1.48% | 27.3% | +| High | 0.58% | 1.47% | 27.3% | | Low | 0.53% | 1.95% | 55.1% | | Close | 0.27% | 1.18% | 29.2% | @@ -199,10 +199,10 @@ Oracle daily OHLC built from per-block prices vs exchange daily OHLC: | 2018 | 54,531 | 0.18% | 1.31% | 31.6% | 411 | 207 | 62 | $3,129–$17,178 | | 2019 | 54,272 | 0.16% | 0.59% | 17.4% | 100 | 16 | 0 | $3,338–$13,868 | | 2020 | 53,102 | 0.10% | 0.42% | 11.6% | 61 | 3 | 0 | $3,858–$29,322 | -| 2021 | 52,733 | 0.07% | 0.47% | 14.4% | 43 | 10 | 0 | $27,678–$69,000 | +| 2021 | 52,733 | 0.07% | 0.47% | 14.4% | 42 | 9 | 0 | $27,678–$69,000 | | 2022 | 53,230 | 0.07% | 0.32% | 6.8% | 10 | 0 | 0 | $15,460–$48,240 | | 2023 | 54,032 | 0.10% | 0.25% | 6.6% | 5 | 0 | 0 | $16,490–$44,700 | -| 2024 | 53,367 | 0.10% | 0.28% | 7.1% | 8 | 0 | 0 | $38,555–$108,298 | +| 2024 | 53,367 | 0.10% | 0.28% | 6.7% | 7 | 0 | 0 | $38,555–$108,298 | | 2025 | 53,113 | 0.11% | 0.25% | 5.8% | 4 | 0 | 0 | $74,409–$126,198 | | 2026 | 5,910 | 0.10% | 0.27% | 3.2% | 0 | 0 | 0 | $60,000–$97,900 | @@ -217,6 +217,14 @@ Post-hoc smoothing, for example correcting any block whose price deviates more t ## Changelog +### v4 + +Changes from v3: + +- **Modern fan-out cap**: below height 630,000 the oracle keeps the strict >100-output transaction drop introduced in v3. At and above 630,000 the cap now relaxes to 250 outputs instead of being fully lifted. This preserves dense-chain payment signal while preventing very large modern fan-outs from dominating a single EMA slot and creating a transient false round-dollar ladder. + +`VERSION` is bumped to 4 so downstream consumers invalidate prices computed by an earlier algorithm. + ### v3 Changes from v2: diff --git a/crates/brk_oracle/examples/determinism.rs b/crates/brk_oracle/examples/determinism.rs index 6e6961384..0a1eeb1ec 100644 --- a/crates/brk_oracle/examples/determinism.rs +++ b/crates/brk_oracle/examples/determinism.rs @@ -4,9 +4,8 @@ //! values matching a continuously-running oracle from the restart height //! onward. //! -//! Mirrors the production filter exactly (per-tx OP_RETURN drop + per-output -//! `eligible_bin`), so it exercises the same code path -//! `brk_computer::prices::compute::feed_blocks` uses at runtime. +//! Mirrors the production transaction filter exactly, so it exercises the same code path +//! `brk_computer::price::compute::feed_blocks` uses at runtime. //! //! Run with: cargo run -p brk_oracle --example determinism --release @@ -14,22 +13,12 @@ use std::path::PathBuf; use brk_indexer::Indexer; use brk_oracle::{ - Config, HistogramRaw, Oracle, PRICES, START_HEIGHT_FAST, bin_to_cents, cents_to_bin, - for_each_round_dollar_bin, + Config, HistogramRaw, Oracle, START_HEIGHT_FAST, START_HEIGHT_SLOW, bin_to_cents, cents_to_bin, + payment_histogram, }; use brk_types::{OutputType, Sats, TxIndex, TxOutIndex}; use vecdb::{AnyVec, ReadableVec, VecIndex}; -fn seed_bin_for_start_height() -> f64 { - let price: f64 = PRICES - .lines() - .nth(START_HEIGHT_FAST - 1) - .expect("prices.txt too short for START_HEIGHT_FAST") - .parse() - .expect("Failed to parse seed price"); - cents_to_bin(price * 100.0) -} - struct Block { height: usize, values: Vec, @@ -40,21 +29,19 @@ struct Block { } fn build_histogram(block: &Block) -> HistogramRaw { - let mut hist = HistogramRaw::zeros(); - for tx in 0..block.tx_starts.len() { + let tx_outputs = (0..block.tx_starts.len()).map(|tx| { let lo = block.tx_starts[tx] - block.out_start; let hi = block .tx_starts .get(tx + 1) .map(|s| s - block.out_start) .unwrap_or(block.out_end - block.out_start); - let outputs = block.values[lo..hi] + block.values[lo..hi] .iter() .copied() - .zip(block.output_types[lo..hi].iter().copied()); - for_each_round_dollar_bin(block.height, outputs, |bin| hist.increment(bin as usize)); - } - hist + .zip(block.output_types[lo..hi].iter().copied()) + }); + payment_histogram(block.height, tx_outputs) } fn main() { @@ -68,14 +55,15 @@ fn main() { let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer"); let total_heights = indexer.vecs.blocks.timestamp.len(); - let config = Config::default(); - let window_size = config.window_size; + let fast_config = Config::default(); + let window_size = fast_config.window_size; let restart_offset = 1000; let end_offset = restart_offset + window_size * 4; let end_height = (START_HEIGHT_FAST + end_offset).min(total_heights); let restart_at = START_HEIGHT_FAST + restart_offset; let warmup_start = restart_at - window_size; + let load_start = START_HEIGHT_SLOW; assert!( end_height > restart_at, @@ -84,8 +72,8 @@ fn main() { ); println!( - "Loading {} blocks ({START_HEIGHT_FAST}..{end_height})...", - end_height - START_HEIGHT_FAST + "Loading {} blocks ({load_start}..{end_height})...", + end_height - load_start ); let total_txs = indexer.vecs.transactions.txid.len(); let total_outputs = indexer.vecs.outputs.value.len(); @@ -93,8 +81,8 @@ fn main() { let out_first: Vec = indexer.vecs.outputs.first_txout_index.collect(); let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor(); - let mut blocks: Vec = Vec::with_capacity(end_height - START_HEIGHT_FAST); - for h in START_HEIGHT_FAST..end_height { + let mut blocks: Vec = Vec::with_capacity(end_height - load_start); + for h in load_start..end_height { let ft = first_tx_index[h]; let next_ft = first_tx_index .get(h + 1) @@ -136,31 +124,36 @@ fn main() { }); } - let mut continuous = Oracle::new(seed_bin_for_start_height(), config.clone()); + let mut continuous = Oracle::from_seed(); let continuous_bins: Vec = blocks .iter() - .map(|b| continuous.process_histogram(&build_histogram(b))) + .map(|b| { + if b.height == START_HEIGHT_FAST { + continuous.reconfigure(fast_config); + } + continuous.process_histogram(&build_histogram(b)) + }) .collect(); println!( "Continuous oracle: {} blocks processed", continuous_bins.len() ); - let prev_bin = continuous_bins[restart_at - START_HEIGHT_FAST - 1]; + let prev_bin = continuous_bins[restart_at - load_start - 1]; let seed_bin = cents_to_bin(bin_to_cents(prev_bin) as f64); println!( "Restart at {restart_at}: prev_bin={prev_bin:.4} -> cents -> seed_bin={seed_bin:.4} (delta {:.6})", seed_bin - prev_bin ); - let warmup_slice = &blocks[warmup_start - START_HEIGHT_FAST..restart_at - START_HEIGHT_FAST]; - let mut restored = Oracle::from_checkpoint(seed_bin, config.clone(), |o| { + let warmup_slice = &blocks[warmup_start - load_start..restart_at - load_start]; + let mut restored = Oracle::from_checkpoint(seed_bin, fast_config, |o| { for b in warmup_slice { o.process_histogram(&build_histogram(b)); } }); - let restored_bins: Vec = blocks[restart_at - START_HEIGHT_FAST..] + let restored_bins: Vec = blocks[restart_at - load_start..] .iter() .map(|b| restored.process_histogram(&build_histogram(b))) .collect(); @@ -168,7 +161,7 @@ fn main() { let mut mismatches: Vec<(usize, f64, f64)> = Vec::new(); for (i, &r) in restored_bins.iter().enumerate() { - let c = continuous_bins[restart_at - START_HEIGHT_FAST + i]; + let c = continuous_bins[restart_at - load_start + i]; if r != c { mismatches.push((restart_at + i, c, r)); } diff --git a/crates/brk_oracle/examples/experiment.rs b/crates/brk_oracle/examples/experiment.rs new file mode 100644 index 000000000..4a1150830 --- /dev/null +++ b/crates/brk_oracle/examples/experiment.rs @@ -0,0 +1,690 @@ +//! Compare oracle filter/EMA variants against the historical OHLC set. +//! +//! This is a diagnostic harness, not production code. It mirrors the production +//! state machine closely enough to compare candidate changes in one pass over +//! the indexed chain while recording the recent bad-lock heights. +//! +//! Run: +//! cargo run -p brk_oracle --example experiment --release + +use std::{cmp::Ordering, env, path::PathBuf}; + +use brk_indexer::Indexer; +use brk_oracle::{ + bin_to_cents, cents_to_bin, eligible_bin, seed_bin as oracle_seed_bin, Config, BINS_PER_DECADE, + NUM_BINS, START_HEIGHT_FAST, START_HEIGHT_SLOW, +}; +use brk_types::{OutputType, Sats, TxIndex, TxOutIndex}; +use vecdb::{AnyVec, ReadableVec, VecIndex}; + +const GENESIS_DAY: u32 = 14252; +const BINS_5PCT: f64 = 4.24; +const BINS_10PCT: f64 = 8.28; +const BINS_20PCT: f64 = 15.84; +const STENCIL_OFFSETS: [i32; 19] = [ + -400, -340, -305, -260, -200, -165, -140, -120, -105, -60, 0, 35, 60, 95, 140, 200, 260, 340, + 400, +]; +const N_ARMS: usize = STENCIL_OFFSETS.len(); +const TARGET_HEIGHTS: &[usize] = &[952_286, 952_287, 952_288, 952_289, 952_290]; + +fn bins_to_pct(bins: f64) -> f64 { + (10.0_f64.powf(bins / BINS_PER_DECADE as f64) - 1.0) * 100.0 +} + +fn timestamp_to_year(ts: u32) -> u16 { + let years_since_1970 = ts as f64 / 31_557_600.0; + (1970.0 + years_since_1970) as u16 +} + +#[derive(Clone)] +struct ShapeAnchor { + weight: f64, + profile: [f64; N_ARMS], +} + +impl ShapeAnchor { + fn new(weight: f64) -> Self { + Self { + weight, + profile: [1.0 / N_ARMS as f64; N_ARMS], + } + } + + fn score(&self, state: &OracleState, center: i64) -> f64 { + if self.weight == 0.0 { + return 0.0; + } + self.weight + * normalized_arms_at(state, center) + .map(|arms| { + 1.0 - (0..N_ARMS) + .map(|i| (arms[i] - self.profile[i]).abs()) + .sum::() + }) + .unwrap_or(0.0) + } + + fn update(&mut self, state: &OracleState, pick: i64) { + const BETA: f64 = 0.004; + if self.weight == 0.0 { + return; + } + if let Some(arms) = normalized_arms_at(state, pick) { + for (p, arm) in self.profile.iter_mut().zip(arms) { + *p = (1.0 - BETA) * *p + BETA * arm; + } + } + } +} + +#[derive(Clone)] +struct OracleState { + config: Config, + ring: Vec>, + nonzero: Vec>, + weights: Vec, + cursor: usize, + filled: usize, + ref_bin: f64, + warmup: bool, + shape: ShapeAnchor, +} + +impl OracleState { + fn new(ref_bin: f64, config: Config) -> Self { + let weights = weights(config.window_size, config.alpha); + Self { + ring: vec![vec![0.0; NUM_BINS]; config.window_size], + nonzero: vec![Vec::new(); config.window_size], + weights, + cursor: 0, + filled: 0, + ref_bin, + warmup: false, + shape: ShapeAnchor::new(config.shape_weight), + config, + } + } + + fn reconfigure(&mut self, config: Config) { + let kept = self.recent(config.window_size); + let mut next = Self::new(self.ref_bin, config); + next.warmup = true; + for hist in kept { + next.push_existing(hist); + } + next.warmup = false; + *self = next; + } + + fn recent(&self, n: usize) -> Vec> { + (0..self.filled.min(n)) + .rev() + .map(|age| self.ring[self.index_at_age(age)].clone()) + .collect() + } + + fn index_at_age(&self, age: usize) -> usize { + (self.cursor + self.ring.len() - 1 - age) % self.ring.len() + } + + fn start_block(&mut self) { + for bin in self.nonzero[self.cursor].drain(..) { + self.ring[self.cursor][bin] = 0.0; + } + } + + fn add(&mut self, bin: usize, weight: f64) { + let slot = &mut self.ring[self.cursor]; + if slot[bin] == 0.0 { + self.nonzero[self.cursor].push(bin); + } + slot[bin] += weight; + } + + fn push_existing(&mut self, hist: Vec) { + self.start_block(); + for (bin, value) in hist + .into_iter() + .enumerate() + .filter(|(_, value)| *value != 0.0) + { + self.add(bin, value); + } + self.finish_block(); + } + + fn finish_block(&mut self) { + self.cursor = (self.cursor + 1) % self.ring.len(); + self.filled = (self.filled + 1).min(self.ring.len()); + if self.warmup { + return; + } + self.ref_bin = find_best_bin(self); + let mut shape = self.shape.clone(); + shape.update(self, self.ref_bin.round() as i64); + self.shape = shape; + } + + fn value_at(&self, bin: i64) -> f64 { + if bin < 0 || bin as usize >= NUM_BINS { + return 0.0; + } + let bin = bin as usize; + (0..self.filled) + .map(|age| self.weights[age] * self.ring[self.index_at_age(age)][bin]) + .sum() + } +} + +fn weights(window_size: usize, alpha: f64) -> Vec { + let decay = 1.0 - alpha; + (0..window_size) + .map(|i| alpha * decay.powi(i as i32)) + .collect() +} + +fn normalized_arms_at(state: &OracleState, center: i64) -> Option<[f64; N_ARMS]> { + let mut arms = STENCIL_OFFSETS.map(|offset| state.value_at(center + offset as i64)); + let sum: f64 = arms.iter().sum(); + if sum <= 0.0 { + return None; + } + for arm in &mut arms { + *arm /= sum; + } + Some(arms) +} + +fn find_best_bin(state: &OracleState) -> f64 { + let center = state.ref_bin.round() as usize; + let search_start = center.saturating_sub(state.config.search_below); + let search_end = (center + state.config.search_above + 1).min(NUM_BINS); + if search_start >= search_end { + return state.ref_bin; + } + + let mut arm_peaks = [0.0f64; N_ARMS]; + for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() { + for bin in search_start..search_end { + arm_peaks[i] = arm_peaks[i].max(state.value_at(bin as i64 + offset as i64)); + } + } + + let score = |bin: usize| -> f64 { + let mut total = 0.0; + for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() { + if arm_peaks[i] > 0.0 { + total += state.value_at(bin as i64 + offset as i64) / arm_peaks[i]; + } + } + total + state.shape.score(state, bin as i64) + }; + + let mut best_bin = search_start; + let mut best_score = score(search_start); + for bin in (search_start + 1)..search_end { + let candidate = score(bin); + if candidate > best_score { + best_score = candidate; + best_bin = bin; + } + } + + let score_center = best_score; + let score_left = if best_bin > search_start { + score(best_bin - 1) + } else { + score_center + }; + let score_right = if best_bin + 1 < search_end { + score(best_bin + 1) + } else { + score_center + }; + let denom = score_left - 2.0 * score_center + score_right; + let sub_bin = if denom.abs() > 1e-10 { + (0.5 * (score_left - score_right) / denom).clamp(-0.5, 0.5) + } else { + 0.0 + }; + best_bin as f64 + sub_bin +} + +#[derive(Clone)] +struct VariantCfg { + name: String, + fast_alpha: f64, + fast_window: usize, + max_outputs: Option, + max_outputs_until: usize, + max_outputs_after: Option, +} + +struct Variant { + cfg: VariantCfg, + state: OracleState, + overall: YearStats, + years: Vec, + bias: f64, + target_prices: Vec<(usize, f64)>, +} + +fn cap_label(cap: Option) -> String { + cap.map(|cap| cap.to_string()) + .unwrap_or_else(|| "none".to_string()) +} + +fn target_price(target_prices: &[(usize, f64)], height: usize) -> Option { + target_prices + .iter() + .find(|(h, _)| *h == height) + .map(|(_, price)| *price) +} + +fn fixes_bad_lock(target_prices: &[(usize, f64)]) -> bool { + target_price(target_prices, 952_287).is_some_and(|price| price > 62_000.0) + && target_price(target_prices, 952_288).is_some_and(|price| price > 62_000.0) +} + +impl Variant { + fn new(cfg: VariantCfg, seed_bin: f64) -> Self { + Self { + cfg, + state: OracleState::new(seed_bin, Config::slow()), + overall: YearStats::new(0), + years: Vec::new(), + bias: 0.0, + target_prices: Vec::new(), + } + } + + fn fast_config(&self) -> Config { + Config { + alpha: self.cfg.fast_alpha, + window_size: self.cfg.fast_window, + ..Config::default() + } + } + + fn maybe_reconfigure(&mut self, height: usize) { + if height == START_HEIGHT_FAST { + self.state.reconfigure(self.fast_config()); + } + } + + fn should_drop_tx(&self, height: usize, output_count: usize) -> bool { + if height < self.cfg.max_outputs_until { + self.cfg.max_outputs.is_some_and(|max| output_count > max) + } else { + self.cfg + .max_outputs_after + .is_some_and(|max| output_count > max) + } + } + + fn add_tx(&mut self, bins: &[u16], height: usize, output_count: usize) { + if bins.is_empty() || self.should_drop_tx(height, output_count) { + return; + } + for &bin in bins { + self.state.add(bin as usize, 1.0); + } + } + + fn finish_block(&mut self, height: usize) { + self.state.finish_block(); + if TARGET_HEIGHTS.contains(&height) { + self.target_prices + .push((height, bin_to_cents(self.state.ref_bin) as f64 / 100.0)); + } + } + + fn update_stats( + &mut self, + height: usize, + height_bands: &[(f64, f64)], + height_ohlc: &[[f64; 4]], + height_years: &[u16], + ) { + if height >= height_bands.len() { + return; + } + let (high_bin, low_bin) = height_bands[height]; + if high_bin <= 0.0 || low_bin <= 0.0 { + return; + } + let err = if self.state.ref_bin < high_bin { + self.state.ref_bin - high_bin + } else if self.state.ref_bin > low_bin { + self.state.ref_bin - low_bin + } else { + 0.0 + }; + let exchange_high = height_ohlc[height][1]; + let exchange_low = height_ohlc[height][2]; + self.overall.update(err, exchange_high, exchange_low); + self.bias += err; + + let year = height_years[height]; + if self.years.last().is_none_or(|stats| stats.year != year) { + self.years.push(YearStats::new(year)); + } + self.years + .last_mut() + .unwrap() + .update(err, exchange_high, exchange_low); + } +} + +struct YearStats { + year: u16, + total_sq_err: f64, + max_err: f64, + total_blocks: u64, + gt_5pct: u64, + gt_10pct: u64, + gt_20pct: u64, + errors: Vec, +} + +impl YearStats { + fn new(year: u16) -> Self { + Self { + year, + total_sq_err: 0.0, + max_err: 0.0, + total_blocks: 0, + gt_5pct: 0, + gt_10pct: 0, + gt_20pct: 0, + errors: Vec::new(), + } + } + + fn update(&mut self, err: f64, _exchange_high: f64, _exchange_low: f64) { + let abs_err = err.abs(); + self.total_sq_err += err * err; + self.total_blocks += 1; + self.errors.push(bins_to_pct(abs_err)); + self.max_err = self.max_err.max(abs_err); + if abs_err > BINS_5PCT { + self.gt_5pct += 1; + } + if abs_err > BINS_10PCT { + self.gt_10pct += 1; + } + if abs_err > BINS_20PCT { + self.gt_20pct += 1; + } + } + + fn rmse_pct(&self) -> f64 { + if self.total_blocks == 0 { + return 0.0; + } + bins_to_pct((self.total_sq_err / self.total_blocks as f64).sqrt()) + } + + fn max_pct(&self) -> f64 { + bins_to_pct(self.max_err) + } + + fn percentile(&self, p: f64) -> f64 { + if self.errors.is_empty() { + return 0.0; + } + let mut errors = self.errors.clone(); + errors.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); + let idx = ((p / 100.0) * (errors.len() - 1) as f64).round() as usize; + errors[idx.min(errors.len() - 1)] + } +} + +fn main() { + let data_dir = std::env::var("BRK_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".brk")); + let end_override = std::env::var("ORACLE_END") + .ok() + .and_then(|s| s.parse::().ok()); + let stats_start = std::env::var("ORACLE_STATS_START") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(START_HEIGHT_SLOW) + .max(START_HEIGHT_SLOW); + + let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer"); + let total_heights = indexer.vecs.blocks.timestamp.len(); + let end = end_override.unwrap_or(total_heights).min(total_heights); + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + + let height_ohlc: Vec<[f64; 4]> = serde_json::from_str( + &std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json")) + .expect("read height_price_ohlc.json"), + ) + .expect("parse height OHLC"); + let height_bands: Vec<(f64, f64)> = height_ohlc + .iter() + .map(|ohlc| { + let high = ohlc[1]; + let low = ohlc[2]; + if high > 0.0 && low > 0.0 { + (cents_to_bin(high * 100.0), cents_to_bin(low * 100.0)) + } else { + (0.0, 0.0) + } + }) + .collect(); + + let timestamps: Vec = indexer.vecs.blocks.timestamp.collect(); + let height_years: Vec = timestamps + .iter() + .map(|ts| timestamp_to_year(**ts)) + .collect(); + let _height_day1s: Vec = timestamps + .iter() + .map(|ts| (**ts / 86_400).saturating_sub(GENESIS_DAY) as usize) + .collect(); + + let seed_bin = oracle_seed_bin(); + + let current_alpha = 2.0 / 7.0; + let current_window = 12; + let mut cfgs = Vec::::new(); + let mut add_cfg = |name: String, + max_outputs: Option, + max_outputs_until: usize, + max_outputs_after: Option| { + cfgs.push(VariantCfg { + name, + fast_alpha: current_alpha, + fast_window: current_window, + max_outputs, + max_outputs_until, + max_outputs_after, + }); + }; + + for post in [200, 250] { + add_cfg( + format!("pre100_post{post}"), + Some(100), + brk_oracle::MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, + Some(post), + ); + } + + cfgs.dedup_by(|a, b| a.name == b.name); + if let Ok(only) = env::var("BRK_ORACLE_EXPERIMENT_ONLY") { + let names = only + .split(',') + .map(str::trim) + .filter(|name| !name.is_empty()) + .collect::>(); + cfgs.retain(|cfg| names.iter().any(|name| *name == cfg.name)); + } + let mut variants: Vec = cfgs + .into_iter() + .map(|cfg| Variant::new(cfg, seed_bin)) + .collect(); + + let total_txs = indexer.vecs.transactions.txid.len(); + let total_outputs = indexer.vecs.outputs.value.len(); + let first_tx_index: Vec = indexer.vecs.transactions.first_tx_index.collect(); + let out_first: Vec = indexer.vecs.outputs.first_txout_index.collect(); + let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor(); + let mut tx_starts: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + let mut output_types: Vec = Vec::new(); + let mut bins: Vec = Vec::new(); + + eprintln!( + "running {} variants over heights {START_HEIGHT_SLOW}..{end}; stats from {stats_start}", + variants.len() + ); + + for h in START_HEIGHT_SLOW..end { + if h % 25_000 == 0 { + eprintln!("height {h}"); + } + for variant in &mut variants { + variant.maybe_reconfigure(h); + variant.state.start_block(); + } + + let ft = first_tx_index[h]; + let next_ft = first_tx_index + .get(h + 1) + .copied() + .unwrap_or(TxIndex::from(total_txs)); + let block_first_tx = ft.to_usize() + 1; + let tx_count = next_ft.to_usize() - block_first_tx; + let out_end = out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize(); + + txout_cursor.advance(block_first_tx - txout_cursor.position()); + tx_starts.clear(); + for _ in 0..tx_count { + tx_starts.push(txout_cursor.next().unwrap().to_usize()); + } + let out_start = tx_starts.first().copied().unwrap_or(out_end); + + indexer + .vecs + .outputs + .value + .collect_range_into_at(out_start, out_end, &mut values); + indexer.vecs.outputs.output_type.collect_range_into_at( + out_start, + out_end, + &mut output_types, + ); + + for tx in 0..tx_count { + let lo = tx_starts[tx] - out_start; + let hi = tx_starts + .get(tx + 1) + .map(|s| s - out_start) + .unwrap_or(out_end - out_start); + if output_types[lo..hi].contains(&OutputType::OpReturn) { + continue; + } + bins.clear(); + for i in lo..hi { + if let Some(bin) = eligible_bin(values[i], output_types[i]) { + bins.push(bin); + } + } + for variant in &mut variants { + variant.add_tx(&bins, h, hi - lo); + } + } + + for variant in &mut variants { + variant.finish_block(h); + if h >= stats_start { + variant.update_stats(h, &height_bands, &height_ohlc, &height_years); + } + } + } + + variants.sort_by(|a, b| { + fixes_bad_lock(&b.target_prices) + .cmp(&fixes_bad_lock(&a.target_prices)) + .then_with(|| { + a.overall + .rmse_pct() + .partial_cmp(&b.overall.rmse_pct()) + .unwrap_or(Ordering::Equal) + }) + .then_with(|| a.overall.gt_5pct.cmp(&b.overall.gt_5pct)) + }); + + println!( + "variant\tpre_cap\tpost_cap\tfixed\tmedian\tp95\tp99\tp999\trmse\tmax\tbias_bins\tgt5\tgt10\tgt20\tp952287\tp952288\ttarget_prices\trmse_by_year\tgt5_by_year" + ); + for variant in &variants { + let overall = &variant.overall; + let bias = if overall.total_blocks > 0 { + variant.bias / overall.total_blocks as f64 + } else { + 0.0 + }; + let rmse_by_year = (2015..=2026) + .map(|year| { + let rmse = variant + .years + .iter() + .find(|stats| stats.year == year) + .map(YearStats::rmse_pct) + .unwrap_or(0.0); + format!("{year}:{rmse:.3}") + }) + .collect::>() + .join(","); + let gt5_by_year = (2015..=2026) + .map(|year| { + let gt5 = variant + .years + .iter() + .find(|stats| stats.year == year) + .map(|stats| stats.gt_5pct) + .unwrap_or(0); + format!("{year}:{gt5}") + }) + .collect::>() + .join(","); + println!( + "{}\t{}\t{}\t{}\t{:.3}\t{:.3}\t{:.3}\t{:.3}\t{:.3}\t{:.3}\t{:.3}\t{}\t{}\t{}\t{:.2}\t{:.2}\t{}\t{}\t{}", + variant.cfg.name, + cap_label(variant.cfg.max_outputs), + cap_label(variant.cfg.max_outputs_after), + fixes_bad_lock(&variant.target_prices), + overall.percentile(50.0), + overall.percentile(95.0), + overall.percentile(99.0), + overall.percentile(99.9), + overall.rmse_pct(), + overall.max_pct(), + bias, + overall.gt_5pct, + overall.gt_10pct, + overall.gt_20pct, + target_price(&variant.target_prices, 952_287).unwrap_or(0.0), + target_price(&variant.target_prices, 952_288).unwrap_or(0.0), + variant + .target_prices + .iter() + .map(|(height, price)| format!("{height}:{price:.2}")) + .collect::>() + .join(","), + rmse_by_year, + gt5_by_year + ); + } +} diff --git a/crates/brk_oracle/examples/report.rs b/crates/brk_oracle/examples/report.rs index f48a0ad51..3a75003b5 100644 --- a/crates/brk_oracle/examples/report.rs +++ b/crates/brk_oracle/examples/report.rs @@ -6,8 +6,8 @@ use std::path::PathBuf; use brk_indexer::Indexer; use brk_oracle::{ - Config, HistogramRaw, Oracle, PRICES, START_HEIGHT_FAST, bin_to_cents, cents_to_bin, - eligible_bin, + Config, Oracle, START_HEIGHT_FAST, START_HEIGHT_SLOW, bin_to_cents, cents_to_bin, + payment_histogram, }; use brk_types::{OutputType, Sats, TxIndex, TxOutIndex}; use vecdb::{AnyVec, ReadableVec, VecIndex}; @@ -172,15 +172,7 @@ fn main() { .map(|ts| (**ts / 86400).saturating_sub(GENESIS_DAY) as usize) .collect(); - let start_price: f64 = PRICES - .lines() - .nth(START_HEIGHT_FAST - 1) - .expect("prices.txt too short") - .parse() - .expect("Failed to parse seed price"); - - let config = Config::default(); - let mut oracle = Oracle::new(cents_to_bin(start_price * 100.0), config); + let mut oracle = Oracle::from_seed(); let total_txs = indexer.vecs.transactions.txid.len(); let total_outputs = indexer.vecs.outputs.value.len(); @@ -201,7 +193,11 @@ fn main() { let mut oracle_candles: Vec = Vec::new(); let mut current_di: Option = None; - for h in START_HEIGHT_FAST..total_heights { + for h in START_HEIGHT_SLOW..total_heights { + if h == START_HEIGHT_FAST { + oracle.reconfigure(Config::default()); + } + let ft = first_tx_index[h]; let next_ft = first_tx_index .get(h + 1) @@ -235,23 +231,18 @@ fn main() { .output_type .collect_range_at(out_start, out_end); - // Drop every output of a tx carrying an OP_RETURN (protocol machinery). - let mut hist = HistogramRaw::zeros(); - for tx in 0..tx_count { + let tx_outputs = (0..tx_count).map(|tx| { let lo = tx_starts[tx] - out_start; let hi = tx_starts .get(tx + 1) .map(|s| s - out_start) .unwrap_or(out_end - out_start); - if output_types[lo..hi].contains(&OutputType::OpReturn) { - continue; - } - for i in lo..hi { - if let Some(bin) = eligible_bin(values[i], output_types[i]) { - hist.increment(bin as usize); - } - } - } + values[lo..hi] + .iter() + .copied() + .zip(output_types[lo..hi].iter().copied()) + }); + let hist = payment_histogram(h, tx_outputs); let ref_bin = oracle.process_histogram(&hist); let oracle_price = bin_to_cents(ref_bin) as f64 / 100.0; @@ -373,10 +364,12 @@ fn main() { println!(" brk_oracle accuracy report"); println!(" ══════════════════════════"); println!(); - println!(" Config: w12, alpha=2/7, search -9/+11, noisy/dust/round-btc filtered"); println!( - " Test range: height {} .. {} ({} blocks)", - START_HEIGHT_FAST, + " Config: slow w40 alpha=0.10 until {START_HEIGHT_FAST}, then w12 alpha=2/7; shared payment filter" + ); + println!( + " Test range: height {} .. {} ({} exchange-covered blocks)", + START_HEIGHT_SLOW, total_heights - 1, overall.total_blocks ); diff --git a/crates/brk_oracle/examples/report_from.rs b/crates/brk_oracle/examples/report_from.rs index bd229c4e7..7d01bb85e 100644 --- a/crates/brk_oracle/examples/report_from.rs +++ b/crates/brk_oracle/examples/report_from.rs @@ -1,13 +1,16 @@ -//! Generate detailed oracle accuracy report for README / documentation. +//! Experimental oracle accuracy report from an arbitrary start height with many +//! scoring/filter knobs. //! -//! Run with: cargo run -p brk_oracle --example report --release +//! Use `report.rs` for the canonical README/documentation report. +//! +//! Run with: cargo run -p brk_oracle --example report_from --release use std::path::PathBuf; use brk_indexer::Indexer; use brk_oracle::{ - Config, HistogramEma, HistogramRaw, NUM_BINS, PRICES, START_HEIGHT_FAST, bin_to_cents, - cents_to_bin, eligible_bin, + Config, HistogramEma, HistogramRaw, NUM_BINS, START_HEIGHT_FAST, bin_to_cents, cents_to_bin, + eligible_bin, pre_oracle_price_cents, }; use brk_types::{OutputType, Sats, TxIndex, TxOutIndex}; use vecdb::{AnyVec, ReadableVec, VecIndex}; @@ -579,16 +582,14 @@ fn main() { .map(|ts| (**ts / 86400).saturating_sub(GENESIS_DAY) as usize) .collect(); - // Seed price at height `start - 1`. The baked prices.txt only covers up to - // 508k (the cold-start seed); past it we warm-start from the exchange close - // so any later start height gets a primed ref_bin without the cold-start - // alias zone. start <= 508k stays bit-identical to the old baseline. - let start_price: f64 = PRICES - .lines() - .nth(start - 1) - .and_then(|l| l.parse().ok()) + // Seed price at height `start - 1`. The baked prices.txt only covers the + // pre-oracle seed range; past it this experimental harness warm-starts from + // exchange OHLC so arbitrary later starts get a primed ref_bin. + let seed_height = start.saturating_sub(1); + let start_price: f64 = pre_oracle_price_cents(seed_height) + .map(|cents| cents.inner() as f64 / 100.0) .unwrap_or_else(|| { - let o = height_ohlc.get(start - 1).copied().unwrap_or([0.0; 4]); + let o = height_ohlc.get(seed_height).copied().unwrap_or([0.0; 4]); if o[3] > 0.0 { o[3] } else { @@ -1168,7 +1169,10 @@ fn main() { println!(" brk_oracle accuracy report"); println!(" ══════════════════════════"); println!(); - println!(" Config: w12, alpha=2/7, search -9/+11, noisy/dust/round-btc filtered"); + println!( + " Config: w{}, alpha={:.5}, search -{}/+{}, experimental knobs", + window_size, config.alpha, config.search_below, config.search_above + ); println!( " Test range: height {} .. {} ({} blocks), seed ${:.2}", start, diff --git a/crates/brk_oracle/src/config.rs b/crates/brk_oracle/src/config.rs index 9cd5705f7..9813c0d69 100644 --- a/crates/brk_oracle/src/config.rs +++ b/crates/brk_oracle/src/config.rs @@ -1,7 +1,8 @@ use std::ops::Range; /// First height the oracle computes on-chain, with the slow cold-start EMA -/// ([`slow`](Config::slow)). Below it, prices come from [`PRICES`](crate::PRICES). +/// ([`slow`](Config::slow)). Below it, prices come from +/// [`pre_oracle_prices_from`](crate::pre_oracle_prices_from). pub const START_HEIGHT_SLOW: usize = 340_000; /// Height where the oracle switches slow -> fast EMA ([`default`](Config::default)). @@ -10,7 +11,7 @@ pub const START_HEIGHT_SLOW: usize = 340_000; /// slow. pub const START_HEIGHT_FAST: usize = 508_000; -#[derive(Clone)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Config { /// EMA decay: 2/(N+1) where N is span in blocks. 2/7 = 6-block span. pub alpha: f64, @@ -100,4 +101,10 @@ mod tests { Config::segments_for_range(START_HEIGHT_FAST..(START_HEIGHT_FAST + 2)).collect(); assert_eq!(fast, vec![START_HEIGHT_FAST..(START_HEIGHT_FAST + 2)]); } + + #[test] + fn for_height_selects_regime() { + assert_eq!(Config::for_height(START_HEIGHT_FAST - 1), Config::slow()); + assert_eq!(Config::for_height(START_HEIGHT_FAST), Config::default()); + } } diff --git a/crates/brk_oracle/src/filter.rs b/crates/brk_oracle/src/filter.rs index 771a45071..0d2e42cd6 100644 --- a/crates/brk_oracle/src/filter.rs +++ b/crates/brk_oracle/src/filter.rs @@ -1,6 +1,6 @@ use brk_types::{OutputType, Sats}; -use crate::scale::sats_to_bin; +use crate::scale::{sats_to_bin, HistogramRaw}; /// Dust floor: outputs below this many sats are too small to be payments. const MIN_SATS: u64 = 1000; @@ -21,16 +21,27 @@ const EXCLUDED_MASK: u16 = { mask }; -/// A transaction with more than this many outputs is a batch payout (exchange -/// sweep, mixer fan-out), not a round-dollar payment, so it is dropped below -/// [`MAX_OUTPUTS_UNTIL_HEIGHT`]. -pub const MAX_OUTPUTS: usize = 100; +/// Pre-modern transaction-output fan-out cap. Above this, the transaction is a +/// batch payout (exchange sweep, mixer fan-out), not a round-dollar payment. +pub const PRE_MODERN_TX_OUTPUT_FANOUT_CAP: usize = 100; -/// Height below which the [`MAX_OUTPUTS`] cap applies. The thin 2018-2020 -/// signal needs batch payouts removed to stay locked onto the round-dollar -/// pattern. Above this height on-chain volume is dense enough that the cap -/// removes more genuine signal than noise, so it is lifted. -pub const MAX_OUTPUTS_UNTIL_HEIGHT: usize = 630_000; +/// Modern-chain transaction-output fan-out cap. Dense post-630k blocks can +/// carry more genuine payment outputs, but very large fan-outs can still +/// dominate one EMA slot and create a false round-dollar ladder. +pub const MODERN_TX_OUTPUT_FANOUT_CAP: usize = 250; + +/// Height where [`PRE_MODERN_TX_OUTPUT_FANOUT_CAP`] relaxes to +/// [`MODERN_TX_OUTPUT_FANOUT_CAP`]. +pub const MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT: usize = 630_000; + +#[inline(always)] +fn tx_output_fanout_cap(height: usize) -> usize { + if height < MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT { + PRE_MODERN_TX_OUTPUT_FANOUT_CAP + } else { + MODERN_TX_OUTPUT_FANOUT_CAP + } +} /// Bin index for `(sats, output_type)`, or `None` for an excluded type (P2TR), /// dust, a round-BTC value, or an out-of-range bin. The per-output half of the @@ -51,17 +62,19 @@ pub fn eligible_bin(sats: Sats, output_type: OutputType) -> Option { /// bins identically. Calls `emit(bin)` for each eligible output, in order. /// /// A whole transaction is dropped when it carries any OP_RETURN output (data -/// carriers, not payments) or, below [`MAX_OUTPUTS_UNTIL_HEIGHT`], when it has -/// more than [`MAX_OUTPUTS`] outputs (batch payouts). `height` is the block these -/// outputs belong to. The mempool, always past the cap window, passes -/// `usize::MAX`. +/// carriers, not payments) or when it has more than the height-specific fan-out +/// cap: [`PRE_MODERN_TX_OUTPUT_FANOUT_CAP`] below +/// [`MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT`], +/// [`MODERN_TX_OUTPUT_FANOUT_CAP`] at and above it. `height` is the block these +/// outputs belong to. Live or otherwise guaranteed-modern callers should use +/// [`for_each_modern_round_dollar_bin`] instead. #[inline] pub fn for_each_round_dollar_bin( height: usize, outputs: impl ExactSizeIterator + Clone, mut emit: impl FnMut(u16), ) { - if height < MAX_OUTPUTS_UNTIL_HEIGHT && outputs.len() > MAX_OUTPUTS { + if outputs.len() > tx_output_fanout_cap(height) { return; } if outputs.clone().any(|(_, ty)| ty == OutputType::OpReturn) { @@ -73,3 +86,133 @@ pub fn for_each_round_dollar_bin( } } } + +/// Heightless form of [`for_each_round_dollar_bin`] for live or otherwise +/// guaranteed-modern transaction streams. Applies +/// [`MODERN_TX_OUTPUT_FANOUT_CAP`]. +#[inline] +pub fn for_each_modern_round_dollar_bin( + outputs: impl ExactSizeIterator + Clone, + emit: impl FnMut(u16), +) { + for_each_round_dollar_bin(MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, outputs, emit); +} + +/// Build a fresh eligible round-dollar payment histogram for one block's +/// non-coinbase transaction outputs. +#[inline] +pub fn payment_histogram( + height: usize, + txs: impl IntoIterator, +) -> HistogramRaw +where + Outputs: ExactSizeIterator + Clone, +{ + let mut hist = HistogramRaw::zeros(); + for outputs in txs { + for_each_round_dollar_bin(height, outputs, |bin| hist.increment(bin as usize)); + } + hist +} + +#[cfg(test)] +mod tests { + use super::*; + + fn payment_outputs(len: usize) -> impl ExactSizeIterator + Clone { + std::iter::repeat_n((Sats::new(12_345), OutputType::P2WPKH), len) + } + + fn emitted_count(height: usize, len: usize) -> usize { + let mut count = 0; + for_each_round_dollar_bin(height, payment_outputs(len), |_| count += 1); + count + } + + #[test] + fn early_fanout_cap_is_strict() { + assert_eq!( + emitted_count( + MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT - 1, + PRE_MODERN_TX_OUTPUT_FANOUT_CAP, + ), + PRE_MODERN_TX_OUTPUT_FANOUT_CAP + ); + assert_eq!( + emitted_count( + MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT - 1, + PRE_MODERN_TX_OUTPUT_FANOUT_CAP + 1, + ), + 0 + ); + } + + #[test] + fn modern_fanout_cap_is_relaxed_but_not_lifted() { + assert_eq!( + emitted_count( + MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, + MODERN_TX_OUTPUT_FANOUT_CAP, + ), + MODERN_TX_OUTPUT_FANOUT_CAP + ); + assert_eq!( + emitted_count( + MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, + MODERN_TX_OUTPUT_FANOUT_CAP + 1, + ), + 0 + ); + } + + fn emitted_count_modern(len: usize) -> usize { + let mut count = 0; + for_each_modern_round_dollar_bin(payment_outputs(len), |_| count += 1); + count + } + + #[test] + fn modern_helper_uses_modern_fanout_cap() { + assert_eq!( + emitted_count_modern(MODERN_TX_OUTPUT_FANOUT_CAP), + MODERN_TX_OUTPUT_FANOUT_CAP + ); + assert_eq!(emitted_count_modern(MODERN_TX_OUTPUT_FANOUT_CAP + 1), 0); + } + + #[test] + fn payment_histogram_drops_op_return_transaction() { + let sats = Sats::new(12_345); + let txs = vec![ + vec![(sats, OutputType::P2WPKH), (sats, OutputType::P2PKH)], + vec![ + (Sats::new(54_321), OutputType::OpReturn), + (sats, OutputType::P2WPKH), + ], + ]; + let hist = payment_histogram( + MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, + txs.into_iter().map(|tx| tx.into_iter()), + ); + + let bin = eligible_bin(sats, OutputType::P2WPKH).unwrap() as usize; + assert_eq!(hist[bin], 2); + } + + #[test] + fn builds_fresh_payment_histogram() { + let sats = Sats::new(12_345); + let txs = vec![vec![ + (sats, OutputType::P2WPKH), + (Sats::new(100_000_000), OutputType::P2WPKH), + ]]; + + let hist = payment_histogram( + MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, + txs.into_iter().map(|tx| tx.into_iter()), + ); + + let bin = eligible_bin(sats, OutputType::P2WPKH).unwrap() as usize; + assert_eq!(hist[bin], 1); + } +} diff --git a/crates/brk_oracle/src/lib.rs b/crates/brk_oracle/src/lib.rs index 13e86b253..1b31ed04f 100644 --- a/crates/brk_oracle/src/lib.rs +++ b/crates/brk_oracle/src/lib.rs @@ -6,42 +6,44 @@ //! Behavior changes by height along two independent axes, each in its own module: //! //! - EMA regime (`config`): below [`START_HEIGHT_SLOW`] prices come from the baked -//! [`PRICES`]. From there to [`START_HEIGHT_FAST`] a slow cold-start EMA runs with -//! a shape-anchoring restoring force. At [`START_HEIGHT_FAST`] it switches to a -//! fast EMA that tracks mature-market volatility. -//! - Output filter (`filter`): below [`MAX_OUTPUTS_UNTIL_HEIGHT`] batch-payout -//! transactions are dropped from the histogram. Above it the cap is lifted. +//! pre-oracle tape. From there to [`START_HEIGHT_FAST`] a slow cold-start EMA +//! runs with a shape-anchoring restoring force. At [`START_HEIGHT_FAST`] it +//! switches to a fast EMA that tracks mature-market volatility. +//! - Output filter (`filter`): below [`MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT`] +//! batch-payout transactions are capped strictly. Above it the cap relaxes but +//! still drops very large fan-outs. //! //! The two boundaries differ on purpose. The EMA must hand off to fast before the -//! 2020 crash, while the output cap helps the thin pre-2020 mix for longer. +//! 2020 crash, while the output cap helps the thin pre-2020 mix for longer and +//! still prevents modern fan-out clusters from dominating one EMA slot. use brk_types::{Cents, Dollars}; mod config; mod filter; mod scale; -mod shape; +mod seed; mod stencil; mod window; pub use config::{Config, START_HEIGHT_FAST, START_HEIGHT_SLOW}; -pub use filter::{MAX_OUTPUTS, MAX_OUTPUTS_UNTIL_HEIGHT, eligible_bin, for_each_round_dollar_bin}; -pub use scale::{ - BINS_PER_DECADE, HistogramEma, HistogramEmaCompact, HistogramRaw, NUM_BINS, bin_to_cents, - cents_to_bin, sats_to_bin, +pub use filter::{ + eligible_bin, for_each_modern_round_dollar_bin, for_each_round_dollar_bin, payment_histogram, + MODERN_TX_OUTPUT_FANOUT_CAP, MODERN_TX_OUTPUT_FANOUT_CAP_START_HEIGHT, + PRE_MODERN_TX_OUTPUT_FANOUT_CAP, }; +pub use scale::{ + bin_to_cents, cents_to_bin, sats_to_bin, HistogramEma, HistogramEmaCompact, HistogramRaw, + BINS_PER_DECADE, NUM_BINS, +}; +pub use seed::{pre_oracle_price_cents, pre_oracle_prices_from, seed_bin, seed_price_cents}; -use shape::ShapeAnchor; -use stencil::find_best_bin; +use stencil::Stencil; use window::EmaWindow; /// Oracle algorithm version. Bump on any change that alters computed prices /// so downstream consumers can invalidate cached results. -pub const VERSION: u32 = 3; - -/// Pre-oracle dollar prices, one per line, heights 0..340_000. The last entry -/// seeds the oracle's first on-chain computation at [`START_HEIGHT_SLOW`]. -pub const PRICES: &str = include_str!("prices.txt"); +pub const VERSION: u32 = 4; #[derive(Clone)] pub struct Oracle { @@ -49,9 +51,7 @@ pub struct Oracle { ref_bin: f64, config: Config, warmup: bool, - /// Shape-anchoring restoring force, inert outside the slow cold-start - /// regime (zero weight). See [`ShapeAnchor`](shape::ShapeAnchor). - shape: ShapeAnchor, + stencil: Stencil, } impl Oracle { @@ -60,11 +60,17 @@ impl Oracle { window: EmaWindow::new(config.window_size, config.alpha), ref_bin: start_bin, warmup: false, - shape: ShapeAnchor::new(config.shape_weight), + stencil: Stencil::new(config.shape_weight), config, } } + /// Create an oracle ready to process height [`START_HEIGHT_SLOW`], seeded from + /// the baked pre-oracle price tape and using the slow cold-start config. + pub fn from_seed() -> Self { + Self::new(seed_bin(), Config::slow()) + } + /// Create an oracle restored from a known price. `fill` should call /// `process_histogram` for the warmup blocks. During warmup the ring /// fills without recomputing EMA or searching, then we recompute once @@ -84,14 +90,12 @@ impl Oracle { if !self.warmup { self.window.recompute(); - self.ref_bin = find_best_bin( + self.ref_bin = self.stencil.pick( self.window.ema(), self.ref_bin, self.config.search_below, self.config.search_above, - &self.shape, ); - self.shape.update(self.window.ema(), self.ref_bin.round() as i64); } self.ref_bin } @@ -139,6 +143,21 @@ mod tests { assert_eq!(oracle.price_cents(), bin_to_cents(1600.0).into()); } + #[test] + fn from_seed_matches_manual_seed() { + let mut seeded = Oracle::from_seed(); + let mut manual = Oracle::new(seed_bin(), Config::slow()); + let mut hist = HistogramRaw::zeros(); + hist.increment(1200); + + assert_eq!(seeded.ref_bin(), manual.ref_bin()); + assert_eq!( + seeded.process_histogram(&hist), + manual.process_histogram(&hist) + ); + assert!(seeded.ema().iter().eq(manual.ema().iter())); + } + // reconfigure must leave the oracle in the same state as a fresh warm-up // over the most recent window of raw histograms. The continuous build and // the incremental resume rely on this agreeing at the slow -> fast seam. @@ -158,7 +177,7 @@ mod tests { hists.iter().for_each(|h| { switched.process_histogram(h); }); - switched.reconfigure(fast.clone()); + switched.reconfigure(fast); let keep = fast.window_size; let fresh = Oracle::from_checkpoint(switched.ref_bin(), fast, |o| { @@ -186,7 +205,7 @@ mod tests { let query_start = config.window_size + 5; let query_end = query_start + 20; let seed = 1600.0; - let mut sequential = Oracle::from_checkpoint(seed, config.clone(), |o| { + let mut sequential = Oracle::from_checkpoint(seed, config, |o| { hists[query_start + 1 - config.window_size..query_start + 1] .iter() .for_each(|h| { @@ -199,7 +218,7 @@ mod tests { sequential.process_histogram(&hists[height]); } - let fresh = Oracle::from_checkpoint(seed, config.clone(), |o| { + let fresh = Oracle::from_checkpoint(seed, config, |o| { hists[height + 1 - config.window_size..height + 1] .iter() .for_each(|h| { diff --git a/crates/brk_oracle/src/seed.rs b/crates/brk_oracle/src/seed.rs new file mode 100644 index 000000000..bb2fa3f56 --- /dev/null +++ b/crates/brk_oracle/src/seed.rs @@ -0,0 +1,60 @@ +use brk_types::Cents; + +use crate::{config::START_HEIGHT_SLOW, scale::cents_to_bin}; + +/// Pre-oracle dollar prices, one per line, heights 0..START_HEIGHT_SLOW. +const PRICES: &str = include_str!("prices.txt"); + +/// Baked pre-oracle price at `height`, or `None` once on-chain oracle prices +/// start. +pub fn pre_oracle_price_cents(height: usize) -> Option { + if height >= START_HEIGHT_SLOW { + return None; + } + PRICES.lines().nth(height).map(parse_price_cents) +} + +/// Baked pre-oracle prices starting at `start_height`, as a one-pass iterator. +pub fn pre_oracle_prices_from(start_height: usize) -> impl Iterator { + PRICES + .lines() + .take(START_HEIGHT_SLOW) + .skip(start_height.min(START_HEIGHT_SLOW)) + .map(parse_price_cents) +} + +/// Baked exchange price for the block immediately before on-chain oracle prices +/// start. +pub fn seed_price_cents() -> Cents { + pre_oracle_price_cents(START_HEIGHT_SLOW - 1) + .expect("prices.txt must cover height START_HEIGHT_SLOW - 1") +} + +/// Initial reference bin for processing height START_HEIGHT_SLOW. +pub fn seed_bin() -> f64 { + cents_to_bin(seed_price_cents().inner() as f64) +} + +fn parse_price_cents(line: &str) -> Cents { + let dollars: f64 = line.parse().expect("invalid baked oracle price"); + Cents::new((dollars * 100.0).round() as u64) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn prices_txt_covers_pre_oracle_range() { + assert!(PRICES.lines().count() >= START_HEIGHT_SLOW); + assert_eq!(pre_oracle_prices_from(0).count(), START_HEIGHT_SLOW); + seed_price_cents(); + } + + #[test] + fn pre_oracle_prices_stop_at_onchain_start() { + assert!(pre_oracle_price_cents(START_HEIGHT_SLOW - 1).is_some()); + assert!(pre_oracle_price_cents(START_HEIGHT_SLOW).is_none()); + assert_eq!(pre_oracle_prices_from(START_HEIGHT_SLOW).count(), 0); + } +} diff --git a/crates/brk_oracle/src/shape.rs b/crates/brk_oracle/src/shape.rs deleted file mode 100644 index e80a58c75..000000000 --- a/crates/brk_oracle/src/shape.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::{ - scale::HistogramEma, - stencil::{N_ARMS, normalized_arms_at}, -}; - -/// EMA rate for the adaptive shape template (~250-block time constant), slow -/// enough that a transient octave slide can't corrupt the profile before the -/// pick recovers. -const SHAPE_BETA: f64 = 0.004; - -/// Adaptive shape-anchoring restoring force for the slow cold-start regime. -/// -/// Holds a round-USD shape template (`profile`), re-estimated each block from the -/// arm vector at the pick, and adds a per-candidate score pulling the search -/// toward the octave whose payment shape looks real. This lets the slow EMA -/// resist round-USD octave aliasing in the thin pre-2018 output mix. -/// -/// A zero `weight` makes it inert ([`score`](Self::score) returns 0, -/// [`update`](Self::update) is a no-op), so the fast regime carries it for free -/// without call sites special-casing the disabled path. -#[derive(Clone)] -pub(crate) struct ShapeAnchor { - weight: f64, - /// Seeded flat (every arm equal). The slow EMA learns the real payment shape - /// within a few hundred blocks, so no hand-tuned starting guess is needed. - profile: [f64; N_ARMS], -} - -impl ShapeAnchor { - pub(crate) fn new(weight: f64) -> Self { - Self { - weight, - profile: [1.0 / N_ARMS as f64; N_ARMS], - } - } - - /// Restoring-force contribution to a candidate bin's score: `weight` times the - /// shape match against the learned profile. 0 when inert or the bin is empty. - pub(crate) fn score(&self, ema: &HistogramEma, bin: i64) -> f64 { - if self.weight == 0.0 { - return 0.0; - } - self.weight * self.shape_match(ema, bin) - } - - /// Blend the L1-normalized arm shape at `pick` into the profile (slow EMA, - /// [`SHAPE_BETA`]). No-op when inert or the pick is empty. - pub(crate) fn update(&mut self, ema: &HistogramEma, pick: i64) { - if self.weight == 0.0 { - return; - } - if let Some(arms) = normalized_arms_at(ema, pick) { - (0..N_ARMS).for_each(|i| { - self.profile[i] = (1.0 - SHAPE_BETA) * self.profile[i] + SHAPE_BETA * arms[i]; - }); - } - } - - /// Shape match `1 - L1distance` between the candidate's L1-normalized arm - /// vector and the profile. 1.0 is an identical shape and it falls as mass - /// shifts off the round-USD ladder. 0 for an empty (no-mass) center. - fn shape_match(&self, ema: &HistogramEma, center: i64) -> f64 { - match normalized_arms_at(ema, center) { - Some(arms) => { - 1.0 - (0..N_ARMS) - .map(|i| (arms[i] - self.profile[i]).abs()) - .sum::() - } - None => 0.0, - } - } -} diff --git a/crates/brk_oracle/src/stencil.rs b/crates/brk_oracle/src/stencil.rs index 70e193081..514301e5d 100644 --- a/crates/brk_oracle/src/stencil.rs +++ b/crates/brk_oracle/src/stencil.rs @@ -1,7 +1,6 @@ -use crate::{ - scale::{HistogramEma, NUM_BINS}, - shape::ShapeAnchor, -}; +use std::ops::Range; + +use crate::scale::{HistogramEma, NUM_BINS}; /// Bin offsets for 19 round-USD amounts relative to the $100 reference (offset 0). /// Each offset = log10(amount / 100) * BINS_PER_DECADE. @@ -28,7 +27,13 @@ const STENCIL_OFFSETS: [i32; 19] = [ ]; /// Number of round-USD stencil arms. -pub(crate) const N_ARMS: usize = STENCIL_OFFSETS.len(); +const N_ARMS: usize = STENCIL_OFFSETS.len(); +type Arms = [f64; N_ARMS]; + +/// EMA rate for the adaptive shape template (~250-block time constant), slow +/// enough that a transient octave slide can't corrupt the profile before the +/// pick recovers. +const SHAPE_BETA: f64 = 0.004; /// EMA mass at `idx`, or 0.0 when the index falls outside the histogram. #[inline(always)] @@ -41,12 +46,12 @@ fn bin_value(ema: &HistogramEma, idx: i64) -> f64 { } /// Raw EMA mass on each of the 19 stencil arms at `center`. -fn arms_at(ema: &HistogramEma, center: i64) -> [f64; N_ARMS] { +fn arms_at(ema: &HistogramEma, center: i64) -> Arms { STENCIL_OFFSETS.map(|offset| bin_value(ema, center + offset as i64)) } /// [`arms_at`] L1-normalized to sum 1, or `None` when the center carries no mass. -pub(crate) fn normalized_arms_at(ema: &HistogramEma, center: i64) -> Option<[f64; N_ARMS]> { +fn normalized_arms_at(ema: &HistogramEma, center: i64) -> Option { let mut arms = arms_at(ema, center); let sum: f64 = arms.iter().sum(); if sum <= 0.0 { @@ -58,72 +63,200 @@ pub(crate) fn normalized_arms_at(ema: &HistogramEma, center: i64) -> Option<[f64 Some(arms) } +/// Round-dollar stencil picker. +/// +/// Input: current EMA histogram, previous reference bin, and search bounds. +/// Output: next reference bin. Internal state is only the adaptive shape profile +/// used by the slow cold-start regime. +#[derive(Clone)] +pub(super) struct Stencil { + shape: ShapeAnchor, +} + +impl Stencil { + pub(super) fn new(shape_weight: f64) -> Self { + Self { + shape: ShapeAnchor::new(shape_weight), + } + } + + pub(super) fn pick( + &mut self, + ema: &HistogramEma, + prev_bin: f64, + search_below: usize, + search_above: usize, + ) -> f64 { + let ref_bin = find_best_bin(ema, prev_bin, search_below, search_above, &self.shape); + self.shape.update(ema, ref_bin.round() as i64); + ref_bin + } +} + +/// Adaptive shape-anchoring restoring force for the slow cold-start regime. +/// +/// Holds a round-USD shape template (`profile`), re-estimated each block from the +/// arm vector at the pick, and adds a per-candidate score pulling the search +/// toward the octave whose payment shape looks real. This lets the slow EMA +/// resist round-USD octave aliasing in the thin pre-2018 output mix. +/// +/// A zero `weight` makes it inert ([`score`](Self::score) returns 0, +/// [`update`](Self::update) is a no-op), so the fast regime carries it for free +/// without call sites special-casing the disabled path. +#[derive(Clone)] +struct ShapeAnchor { + weight: f64, + /// Seeded flat (every arm equal). The slow EMA learns the real payment shape + /// within a few hundred blocks, so no hand-tuned starting guess is needed. + profile: Arms, +} + +impl ShapeAnchor { + fn new(weight: f64) -> Self { + Self { + weight, + profile: [1.0 / N_ARMS as f64; N_ARMS], + } + } + + /// Restoring-force contribution to a candidate bin's score: `weight` times the + /// shape match against the learned profile. 0 when inert or the bin is empty. + fn score(&self, ema: &HistogramEma, bin: i64) -> f64 { + if self.weight == 0.0 { + return 0.0; + } + self.weight * self.shape_match(ema, bin) + } + + /// Blend the L1-normalized arm shape at `pick` into the profile (slow EMA, + /// [`SHAPE_BETA`]). No-op when inert or the pick is empty. + fn update(&mut self, ema: &HistogramEma, pick: i64) { + if self.weight == 0.0 { + return; + } + if let Some(arms) = normalized_arms_at(ema, pick) { + (0..N_ARMS).for_each(|i| { + self.profile[i] = (1.0 - SHAPE_BETA) * self.profile[i] + SHAPE_BETA * arms[i]; + }); + } + } + + /// Shape match `1 - L1distance` between the candidate's L1-normalized arm + /// vector and the profile. 1.0 is an identical shape and it falls as mass + /// shifts off the round-USD ladder. 0 for an empty (no-mass) center. + fn shape_match(&self, ema: &HistogramEma, center: i64) -> f64 { + match normalized_arms_at(ema, center) { + Some(arms) => { + 1.0 - (0..N_ARMS) + .map(|i| (arms[i] - self.profile[i]).abs()) + .sum::() + } + None => 0.0, + } + } +} + +struct CandidateScorer<'a> { + ema: &'a HistogramEma, + shape: &'a ShapeAnchor, + range: Range, + arm_peaks: Arms, +} + +impl<'a> CandidateScorer<'a> { + fn new(ema: &'a HistogramEma, shape: &'a ShapeAnchor, range: Range) -> Self { + Self { + ema, + shape, + arm_peaks: arm_peaks(ema, range.clone()), + range, + } + } + + fn score(&self, bin: usize) -> f64 { + let mut total = 0.0; + for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() { + if self.arm_peaks[i] > 0.0 { + total += bin_value(self.ema, bin as i64 + offset as i64) / self.arm_peaks[i]; + } + } + total + self.shape.score(self.ema, bin as i64) + } + + fn best_bin(&self) -> (usize, f64) { + let mut bins = self.range.clone(); + let mut best_bin = bins.next().expect("candidate range must not be empty"); + let mut best_score = self.score(best_bin); + + for bin in bins { + let candidate = self.score(bin); + if candidate > best_score { + best_score = candidate; + best_bin = bin; + } + } + + (best_bin, best_score) + } + + /// Parabolic sub-bin interpolation for fractional precision. + fn interpolated_bin(&self, best_bin: usize, best_score: f64) -> f64 { + let score_center = best_score; + let score_left = if best_bin > self.range.start { + self.score(best_bin - 1) + } else { + score_center + }; + let score_right = if best_bin + 1 < self.range.end { + self.score(best_bin + 1) + } else { + score_center + }; + let denom = score_left - 2.0 * score_center + score_right; + let sub_bin = if denom.abs() > 1e-10 { + (0.5 * (score_left - score_right) / denom).clamp(-0.5, 0.5) + } else { + 0.0 + }; + + best_bin as f64 + sub_bin + } +} + +fn search_range(prev_bin: f64, search_below: usize, search_above: usize) -> Option> { + let center = prev_bin.round() as usize; + let search_start = center.saturating_sub(search_below); + let search_end = (center + search_above + 1).min(NUM_BINS); + + (search_start < search_end).then_some(search_start..search_end) +} + +fn arm_peaks(ema: &HistogramEma, range: Range) -> Arms { + let mut peaks = [0.0f64; N_ARMS]; + for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() { + for bin in range.clone() { + peaks[i] = peaks[i].max(bin_value(ema, bin as i64 + offset as i64)); + } + } + peaks +} + /// Scores each candidate bin in the search window by summing normalized stencil /// matches across the EMA histogram, then refines with parabolic interpolation. /// Each candidate also picks up `shape`'s shape-anchoring restoring force, which /// is inert (adds 0) outside the slow cold-start regime. -pub(crate) fn find_best_bin( +fn find_best_bin( ema: &HistogramEma, prev_bin: f64, search_below: usize, search_above: usize, shape: &ShapeAnchor, ) -> f64 { - let center = prev_bin.round() as usize; - let search_start = center.saturating_sub(search_below); - let search_end = (center + search_above + 1).min(NUM_BINS); - - if search_start >= search_end { + let Some(range) = search_range(prev_bin, search_below, search_above) else { return prev_bin; - } - - // Per-offset peak within the search window (for normalization). - let mut arm_peaks = [0.0f64; N_ARMS]; - for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() { - for bin in search_start..search_end { - arm_peaks[i] = arm_peaks[i].max(bin_value(ema, bin as i64 + offset as i64)); - } - } - - let score = |bin: usize| -> f64 { - let mut total = 0.0; - for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() { - if arm_peaks[i] > 0.0 { - total += bin_value(ema, bin as i64 + offset as i64) / arm_peaks[i]; - } - } - total += shape.score(ema, bin as i64); - total }; - let mut best_bin = search_start; - let mut best_score = score(search_start); - for bin in (search_start + 1)..search_end { - let candidate = score(bin); - if candidate > best_score { - best_score = candidate; - best_bin = bin; - } - } - - // Parabolic sub-bin interpolation for fractional precision. - let score_center = best_score; - let score_left = if best_bin > search_start { - score(best_bin - 1) - } else { - score_center - }; - let score_right = if best_bin + 1 < search_end { - score(best_bin + 1) - } else { - score_center - }; - let denom = score_left - 2.0 * score_center + score_right; - let sub_bin = if denom.abs() > 1e-10 { - (0.5 * (score_left - score_right) / denom).clamp(-0.5, 0.5) - } else { - 0.0 - }; - - best_bin as f64 + sub_bin + let scorer = CandidateScorer::new(ema, shape, range); + let (best_bin, best_score) = scorer.best_bin(); + scorer.interpolated_bin(best_bin, best_score) } diff --git a/crates/brk_query/src/impl/block/info.rs b/crates/brk_query/src/impl/block/info.rs index 0c8985a08..ef5d335f9 100644 --- a/crates/brk_query/src/impl/block/info.rs +++ b/crates/brk_query/src/impl/block/info.rs @@ -271,7 +271,7 @@ impl Query { .block .sats .collect_range_at(begin, end); - let prices = computer.prices.spot.usd.height.collect_range_at(begin, end); + let prices = computer.price.spot.usd.height.collect_range_at(begin, end); let output_volumes = computer .mining .rewards diff --git a/crates/brk_query/src/impl/mining/block_fees.rs b/crates/brk_query/src/impl/mining/block_fees.rs index 94fa3c577..f28355c5a 100644 --- a/crates/brk_query/src/impl/mining/block_fees.rs +++ b/crates/brk_query/src/impl/mining/block_fees.rs @@ -13,7 +13,7 @@ impl Query { pub fn block_fees(&self, time_period: TimePeriod) -> Result> { let bw = BlockWindow::new(self, time_period)?; let fees: Vec = bw.read(&self.computer().mining.rewards.fees.block.sats)?; - let prices: Vec = bw.read(&self.computer().prices.spot.cents.height)?; + let prices: Vec = bw.read(&self.computer().price.spot.cents.height)?; Ok(bw .buckets diff --git a/crates/brk_query/src/impl/mining/block_rewards.rs b/crates/brk_query/src/impl/mining/block_rewards.rs index 1da3526e8..0ddca78a6 100644 --- a/crates/brk_query/src/impl/mining/block_rewards.rs +++ b/crates/brk_query/src/impl/mining/block_rewards.rs @@ -13,7 +13,7 @@ impl Query { pub fn block_rewards(&self, time_period: TimePeriod) -> Result> { let bw = BlockWindow::new(self, time_period)?; let rewards: Vec = bw.read(&self.computer().mining.rewards.coinbase.block.sats)?; - let prices: Vec = bw.read(&self.computer().prices.spot.cents.height)?; + let prices: Vec = bw.read(&self.computer().price.spot.cents.height)?; Ok(bw .buckets diff --git a/crates/brk_query/src/impl/oracle.rs b/crates/brk_query/src/impl/oracle.rs index 2bfdba28b..de8aa215d 100644 --- a/crates/brk_query/src/impl/oracle.rs +++ b/crates/brk_query/src/impl/oracle.rs @@ -1,10 +1,10 @@ use std::{ops::Range, sync::Arc}; -use brk_computer::prices::Vecs as PricesVecs; +use brk_computer::price::Vecs as PricesVecs; use brk_error::{Error, Result}; use brk_indexer::Lengths; use brk_oracle::{ - cents_to_bin, sats_to_bin, Config, HistogramEma, HistogramEmaCompact, HistogramRaw, Oracle, + Config, HistogramEma, HistogramEmaCompact, HistogramRaw, Oracle, cents_to_bin, sats_to_bin, }; use brk_types::{Day1, Dollars, TxOutIndex}; use vecdb::{AnyVec, ReadableVec, VecIndex}; @@ -127,7 +127,7 @@ impl Query { let last = self .computer() - .prices + .price .spot .cents .height @@ -169,7 +169,7 @@ impl Query { fn seed_bin_at(&self, height: usize) -> Result { let cents = self .computer() - .prices + .price .spot .cents .height @@ -180,7 +180,7 @@ impl Query { fn histogram_bound(&self, safe: &Lengths) -> usize { self.computer() - .prices + .price .spot .cents .height diff --git a/crates/brk_query/src/impl/price.rs b/crates/brk_query/src/impl/price.rs index d4bd2f5e7..829b0759b 100644 --- a/crates/brk_query/src/impl/price.rs +++ b/crates/brk_query/src/impl/price.rs @@ -23,7 +23,7 @@ impl Query { return Ok(vec![]); } let h4 = Hour4::from_timestamp(target); - let cents = self.computer().prices.spot.cents.hour4.collect_one(h4); + let cents = self.computer().price.spot.cents.hour4.collect_one(h4); Ok(vec![HistoricalPriceEntry { time: h4.to_timestamp(), usd: Dollars::from(cents.flatten().unwrap_or_default()), @@ -33,7 +33,7 @@ impl Query { fn all_prices(&self) -> Result> { let computer = self.computer(); Ok(computer - .prices + .price .spot .cents .hour4 diff --git a/crates/brk_query/src/impl/urpd.rs b/crates/brk_query/src/impl/urpd.rs index c49da1d80..b5f9d4282 100644 --- a/crates/brk_query/src/impl/urpd.rs +++ b/crates/brk_query/src/impl/urpd.rs @@ -81,7 +81,7 @@ impl Query { let day1 = Day1::try_from(date)?; let close = self .computer() - .prices + .price .split .close .cents diff --git a/crates/brk_server/src/api/series_legacy.rs b/crates/brk_server/src/api/series_legacy.rs index 4ef3166b3..33548fbc4 100644 --- a/crates/brk_server/src/api/series_legacy.rs +++ b/crates/brk_server/src/api/series_legacy.rs @@ -102,7 +102,7 @@ fn cost_basis_formatted( let day1 = Day1::try_from(date)?; let spot_cents = q .computer() - .prices + .price .split .close .cents diff --git a/crates/brk_website/examples/website.rs b/crates/brk_website/examples/website.rs index 82a6da4ef..4c1d4661c 100644 --- a/crates/brk_website/examples/website.rs +++ b/crates/brk_website/examples/website.rs @@ -1,4 +1,4 @@ -use std::time::Duration; +use std::{path::PathBuf, time::Duration}; use axum::{ ServiceExt, @@ -22,7 +22,8 @@ async fn main() -> std::io::Result<()> { // Use the embedded website (default in release mode) // Or use Website::Filesystem(path) to serve from a custom path - let website = Website::Default; + // let website = Website::Default; + let website = Website::Filesystem(PathBuf::from("./website_next")); if !website.is_enabled() { eprintln!("Website is disabled"); @@ -78,7 +79,7 @@ async fn main() -> std::io::Result<()> { )) .layer(CorsLayer::permissive()); - let port = 3110; + let port = 3111; let listener = TcpListener::bind(format!("0.0.0.0:{port}")).await?; info!("website server listening on port {port}"); diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 93d9c27bc..d2ef2edd3 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -5193,7 +5193,7 @@ function createTransferPattern(client, acc) { * @property {SeriesTree_Investing} investing * @property {SeriesTree_Market} market * @property {SeriesTree_Pools} pools - * @property {SeriesTree_Prices} prices + * @property {SeriesTree_Price} price * @property {SeriesTree_Supply} supply * @property {SeriesTree_Cohorts} cohorts */ @@ -6725,14 +6725,14 @@ function createTransferPattern(client, acc) { */ /** - * @typedef {Object} SeriesTree_Prices - * @property {SeriesTree_Prices_Split} split - * @property {SeriesTree_Prices_Ohlc} ohlc - * @property {SeriesTree_Prices_Spot} spot + * @typedef {Object} SeriesTree_Price + * @property {SeriesTree_Price_Split} split + * @property {SeriesTree_Price_Ohlc} ohlc + * @property {SeriesTree_Price_Spot} spot */ /** - * @typedef {Object} SeriesTree_Prices_Split + * @typedef {Object} SeriesTree_Price_Split * @property {CentsSatsUsdPattern3} open * @property {CentsSatsUsdPattern3} high * @property {CentsSatsUsdPattern3} low @@ -6740,14 +6740,14 @@ function createTransferPattern(client, acc) { */ /** - * @typedef {Object} SeriesTree_Prices_Ohlc + * @typedef {Object} SeriesTree_Price_Ohlc * @property {SeriesPattern2} usd * @property {SeriesPattern2} cents * @property {SeriesPattern2} sats */ /** - * @typedef {Object} SeriesTree_Prices_Spot + * @typedef {Object} SeriesTree_Price_Spot * @property {SeriesPattern1} usd * @property {SeriesPattern1} cents * @property {SeriesPattern1} sats @@ -9863,7 +9863,7 @@ class BrkClient extends BrkClientBase { noderunners: createBlocksDominancePattern(this, 'noderunners'), }, }, - prices: { + price: { split: { open: createCentsSatsUsdPattern3(this, 'price_open'), high: createCentsSatsUsdPattern3(this, 'price_high'), diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 7034efc09..f2077897a 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -5788,7 +5788,7 @@ class SeriesTree_Pools: self.major: SeriesTree_Pools_Major = SeriesTree_Pools_Major(client) self.minor: SeriesTree_Pools_Minor = SeriesTree_Pools_Minor(client) -class SeriesTree_Prices_Split: +class SeriesTree_Price_Split: """Series tree node.""" def __init__(self, client: BrkClient, base_path: str = ''): @@ -5797,7 +5797,7 @@ class SeriesTree_Prices_Split: self.low: CentsSatsUsdPattern3 = CentsSatsUsdPattern3(client, 'price_low') self.close: CentsSatsUsdPattern3 = CentsSatsUsdPattern3(client, 'price_close') -class SeriesTree_Prices_Ohlc: +class SeriesTree_Price_Ohlc: """Series tree node.""" def __init__(self, client: BrkClient, base_path: str = ''): @@ -5805,7 +5805,7 @@ class SeriesTree_Prices_Ohlc: self.cents: SeriesPattern2[OHLCCents] = SeriesPattern2(client, 'price_ohlc_cents') self.sats: SeriesPattern2[OHLCSats] = SeriesPattern2(client, 'price_ohlc_sats') -class SeriesTree_Prices_Spot: +class SeriesTree_Price_Spot: """Series tree node.""" def __init__(self, client: BrkClient, base_path: str = ''): @@ -5813,13 +5813,13 @@ class SeriesTree_Prices_Spot: self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, 'price_cents') self.sats: SeriesPattern1[Sats] = SeriesPattern1(client, 'price_sats') -class SeriesTree_Prices: +class SeriesTree_Price: """Series tree node.""" def __init__(self, client: BrkClient, base_path: str = ''): - self.split: SeriesTree_Prices_Split = SeriesTree_Prices_Split(client) - self.ohlc: SeriesTree_Prices_Ohlc = SeriesTree_Prices_Ohlc(client) - self.spot: SeriesTree_Prices_Spot = SeriesTree_Prices_Spot(client) + self.split: SeriesTree_Price_Split = SeriesTree_Price_Split(client) + self.ohlc: SeriesTree_Price_Ohlc = SeriesTree_Price_Ohlc(client) + self.spot: SeriesTree_Price_Spot = SeriesTree_Price_Spot(client) class SeriesTree_Supply_Velocity: """Series tree node.""" @@ -6717,7 +6717,7 @@ class SeriesTree: self.investing: SeriesTree_Investing = SeriesTree_Investing(client) self.market: SeriesTree_Market = SeriesTree_Market(client) self.pools: SeriesTree_Pools = SeriesTree_Pools(client) - self.prices: SeriesTree_Prices = SeriesTree_Prices(client) + self.price: SeriesTree_Price = SeriesTree_Price(client) self.supply: SeriesTree_Supply = SeriesTree_Supply(client) self.cohorts: SeriesTree_Cohorts = SeriesTree_Cohorts(client) diff --git a/website/AGENTS.md b/website/AGENTS.md index 4873a8318..49f27bc96 100644 --- a/website/AGENTS.md +++ b/website/AGENTS.md @@ -1,7 +1,3 @@ -# Rule - -before editing a file, always explain why that code, why it's the most optimal one and wait for my feedback - # Types To check types run: @@ -25,4 +21,3 @@ ALWAYS - reads like english - very easy to understand - very easy to maintain -- avoid defensive checks when the code itself guarantees correctness diff --git a/website/apple-touch-icon.png b/website/assets/favicon/apple-touch-icon.png similarity index 100% rename from website/apple-touch-icon.png rename to website/assets/favicon/apple-touch-icon.png diff --git a/website/favicon-96x96.png b/website/assets/favicon/favicon-96x96.png similarity index 100% rename from website/favicon-96x96.png rename to website/assets/favicon/favicon-96x96.png diff --git a/website/favicon.ico b/website/assets/favicon/favicon.ico similarity index 100% rename from website/favicon.ico rename to website/assets/favicon/favicon.ico diff --git a/website/favicon.svg b/website/assets/favicon/favicon.svg similarity index 100% rename from website/favicon.svg rename to website/assets/favicon/favicon.svg diff --git a/website_bkp/assets/favicon/site.webmanifest b/website/assets/favicon/site.webmanifest similarity index 100% rename from website_bkp/assets/favicon/site.webmanifest rename to website/assets/favicon/site.webmanifest diff --git a/website/assets/web-app-manifest-192x192.png b/website/assets/favicon/web-app-manifest-192x192.png similarity index 100% rename from website/assets/web-app-manifest-192x192.png rename to website/assets/favicon/web-app-manifest-192x192.png diff --git a/website/assets/web-app-manifest-512x512.png b/website/assets/favicon/web-app-manifest-512x512.png similarity index 100% rename from website/assets/web-app-manifest-512x512.png rename to website/assets/favicon/web-app-manifest-512x512.png diff --git a/website_bkp/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 b/website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 similarity index 100% rename from website_bkp/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 rename to website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 diff --git a/website/index.html b/website/index.html index 61b84f9df..8a6b9ce4e 100644 --- a/website/index.html +++ b/website/index.html @@ -1,12 +1,9 @@ - + bitview - + - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + - + + + + + + + + - + +
+ + + +
+
+ +
+
+ + + + + + + + + +
+
+ + diff --git a/website/manifest.webmanifest b/website/manifest.webmanifest index a51e2790c..e4b2ee912 100644 --- a/website/manifest.webmanifest +++ b/website/manifest.webmanifest @@ -1,8 +1,12 @@ { "name": "bitview", "short_name": "bitview", - "description": "Explore Bitcoin data from blocks to patterns.", - "categories": ["bitcoin", "on-chain", "data"], + "description": "Bitcoin transparency, amplified", + "categories": [ + "bitcoin", + "on-chain", + "data" + ], "start_url": "/", "scope": "/", "display": "standalone", @@ -12,25 +16,25 @@ "lang": "en", "icons": [ { - "src": "/assets/web-app-manifest-192x192.png", + "src": "/assets/favicon/web-app-manifest-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/web-app-manifest-192x192.png", + "src": "/assets/favicon/web-app-manifest-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/web-app-manifest-512x512.png", + "src": "/assets/favicon/web-app-manifest-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/web-app-manifest-512x512.png", + "src": "/assets/favicon/web-app-manifest-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/website_bkp/scripts/_types.js b/website/scripts/_types.js similarity index 100% rename from website_bkp/scripts/_types.js rename to website/scripts/_types.js diff --git a/website/entry.js b/website/scripts/entry.js similarity index 100% rename from website/entry.js rename to website/scripts/entry.js diff --git a/website_bkp/scripts/explorer/address.js b/website/scripts/explorer/address.js similarity index 100% rename from website_bkp/scripts/explorer/address.js rename to website/scripts/explorer/address.js diff --git a/website_bkp/scripts/explorer/block.js b/website/scripts/explorer/block.js similarity index 100% rename from website_bkp/scripts/explorer/block.js rename to website/scripts/explorer/block.js diff --git a/website_bkp/scripts/explorer/chain.js b/website/scripts/explorer/chain.js similarity index 100% rename from website_bkp/scripts/explorer/chain.js rename to website/scripts/explorer/chain.js diff --git a/website_bkp/scripts/explorer/cube.js b/website/scripts/explorer/cube.js similarity index 100% rename from website_bkp/scripts/explorer/cube.js rename to website/scripts/explorer/cube.js diff --git a/website_bkp/scripts/explorer/index.js b/website/scripts/explorer/index.js similarity index 100% rename from website_bkp/scripts/explorer/index.js rename to website/scripts/explorer/index.js diff --git a/website_bkp/scripts/explorer/mempool.js b/website/scripts/explorer/mempool.js similarity index 100% rename from website_bkp/scripts/explorer/mempool.js rename to website/scripts/explorer/mempool.js diff --git a/website_bkp/scripts/explorer/render.js b/website/scripts/explorer/render.js similarity index 100% rename from website_bkp/scripts/explorer/render.js rename to website/scripts/explorer/render.js diff --git a/website_bkp/scripts/explorer/tx.js b/website/scripts/explorer/tx.js similarity index 100% rename from website_bkp/scripts/explorer/tx.js rename to website/scripts/explorer/tx.js diff --git a/website_bkp/scripts/main.js b/website/scripts/main.js similarity index 100% rename from website_bkp/scripts/main.js rename to website/scripts/main.js diff --git a/website_bkp/scripts/modules/.gitignore b/website/scripts/modules/.gitignore similarity index 100% rename from website_bkp/scripts/modules/.gitignore rename to website/scripts/modules/.gitignore diff --git a/website_bkp/scripts/modules/brk-client/.gitignore b/website/scripts/modules/brk-client/.gitignore similarity index 100% rename from website_bkp/scripts/modules/brk-client/.gitignore rename to website/scripts/modules/brk-client/.gitignore diff --git a/website_bkp/scripts/modules/brk-client/index.js b/website/scripts/modules/brk-client/index.js similarity index 100% rename from website_bkp/scripts/modules/brk-client/index.js rename to website/scripts/modules/brk-client/index.js diff --git a/website_bkp/scripts/modules/brk-client/jsconfig.json b/website/scripts/modules/brk-client/jsconfig.json similarity index 100% rename from website_bkp/scripts/modules/brk-client/jsconfig.json rename to website/scripts/modules/brk-client/jsconfig.json diff --git a/website_bkp/scripts/modules/brk-client/package.json b/website/scripts/modules/brk-client/package.json similarity index 100% rename from website_bkp/scripts/modules/brk-client/package.json rename to website/scripts/modules/brk-client/package.json diff --git a/website_bkp/scripts/modules/brk-client/tests/basic.js b/website/scripts/modules/brk-client/tests/basic.js similarity index 100% rename from website_bkp/scripts/modules/brk-client/tests/basic.js rename to website/scripts/modules/brk-client/tests/basic.js diff --git a/website_bkp/scripts/modules/brk-client/tests/consistency.js b/website/scripts/modules/brk-client/tests/consistency.js similarity index 100% rename from website_bkp/scripts/modules/brk-client/tests/consistency.js rename to website/scripts/modules/brk-client/tests/consistency.js diff --git a/website_bkp/scripts/modules/brk-client/tests/metric_data.js b/website/scripts/modules/brk-client/tests/metric_data.js similarity index 100% rename from website_bkp/scripts/modules/brk-client/tests/metric_data.js rename to website/scripts/modules/brk-client/tests/metric_data.js diff --git a/website_bkp/scripts/modules/brk-client/tests/tree.js b/website/scripts/modules/brk-client/tests/tree.js similarity index 100% rename from website_bkp/scripts/modules/brk-client/tests/tree.js rename to website/scripts/modules/brk-client/tests/tree.js diff --git a/website_bkp/scripts/modules/brk-client/tsconfig.json b/website/scripts/modules/brk-client/tsconfig.json similarity index 100% rename from website_bkp/scripts/modules/brk-client/tsconfig.json rename to website/scripts/modules/brk-client/tsconfig.json diff --git a/website_bkp/scripts/modules/lean-qr/.gitignore b/website/scripts/modules/lean-qr/.gitignore similarity index 100% rename from website_bkp/scripts/modules/lean-qr/.gitignore rename to website/scripts/modules/lean-qr/.gitignore diff --git a/website_bkp/scripts/modules/lean-qr/2.7.1/index.d.ts b/website/scripts/modules/lean-qr/2.7.1/index.d.ts similarity index 100% rename from website_bkp/scripts/modules/lean-qr/2.7.1/index.d.ts rename to website/scripts/modules/lean-qr/2.7.1/index.d.ts diff --git a/website_bkp/scripts/modules/lean-qr/2.7.1/index.mjs b/website/scripts/modules/lean-qr/2.7.1/index.mjs similarity index 100% rename from website_bkp/scripts/modules/lean-qr/2.7.1/index.mjs rename to website/scripts/modules/lean-qr/2.7.1/index.mjs diff --git a/website_bkp/scripts/modules/lightweight-charts/.gitignore b/website/scripts/modules/lightweight-charts/.gitignore similarity index 100% rename from website_bkp/scripts/modules/lightweight-charts/.gitignore rename to website/scripts/modules/lightweight-charts/.gitignore diff --git a/website_bkp/scripts/modules/lightweight-charts/5.2.0/dist/lightweight-charts.standalone.production.mjs b/website/scripts/modules/lightweight-charts/5.2.0/dist/lightweight-charts.standalone.production.mjs similarity index 100% rename from website_bkp/scripts/modules/lightweight-charts/5.2.0/dist/lightweight-charts.standalone.production.mjs rename to website/scripts/modules/lightweight-charts/5.2.0/dist/lightweight-charts.standalone.production.mjs diff --git a/website_bkp/scripts/modules/lightweight-charts/5.2.0/dist/typings.d.ts b/website/scripts/modules/lightweight-charts/5.2.0/dist/typings.d.ts similarity index 100% rename from website_bkp/scripts/modules/lightweight-charts/5.2.0/dist/typings.d.ts rename to website/scripts/modules/lightweight-charts/5.2.0/dist/typings.d.ts diff --git a/website_bkp/scripts/modules/quickmatch-js/0.5.0/src/index.js b/website/scripts/modules/quickmatch-js/0.5.0/src/index.js similarity index 100% rename from website_bkp/scripts/modules/quickmatch-js/0.5.0/src/index.js rename to website/scripts/modules/quickmatch-js/0.5.0/src/index.js diff --git a/website_bkp/scripts/modules/tsconfig.json b/website/scripts/modules/tsconfig.json similarity index 100% rename from website_bkp/scripts/modules/tsconfig.json rename to website/scripts/modules/tsconfig.json diff --git a/website_bkp/scripts/modules/unpkg.sh b/website/scripts/modules/unpkg.sh similarity index 100% rename from website_bkp/scripts/modules/unpkg.sh rename to website/scripts/modules/unpkg.sh diff --git a/website_bkp/scripts/options/cointime.js b/website/scripts/options/cointime.js similarity index 100% rename from website_bkp/scripts/options/cointime.js rename to website/scripts/options/cointime.js diff --git a/website_bkp/scripts/options/constants.js b/website/scripts/options/constants.js similarity index 100% rename from website_bkp/scripts/options/constants.js rename to website/scripts/options/constants.js diff --git a/website_bkp/scripts/options/distribution/activity.js b/website/scripts/options/distribution/activity.js similarity index 100% rename from website_bkp/scripts/options/distribution/activity.js rename to website/scripts/options/distribution/activity.js diff --git a/website_bkp/scripts/options/distribution/cost-basis.js b/website/scripts/options/distribution/cost-basis.js similarity index 100% rename from website_bkp/scripts/options/distribution/cost-basis.js rename to website/scripts/options/distribution/cost-basis.js diff --git a/website_bkp/scripts/options/distribution/data.js b/website/scripts/options/distribution/data.js similarity index 100% rename from website_bkp/scripts/options/distribution/data.js rename to website/scripts/options/distribution/data.js diff --git a/website_bkp/scripts/options/distribution/holdings.js b/website/scripts/options/distribution/holdings.js similarity index 100% rename from website_bkp/scripts/options/distribution/holdings.js rename to website/scripts/options/distribution/holdings.js diff --git a/website_bkp/scripts/options/distribution/index.js b/website/scripts/options/distribution/index.js similarity index 100% rename from website_bkp/scripts/options/distribution/index.js rename to website/scripts/options/distribution/index.js diff --git a/website_bkp/scripts/options/distribution/prices.js b/website/scripts/options/distribution/prices.js similarity index 100% rename from website_bkp/scripts/options/distribution/prices.js rename to website/scripts/options/distribution/prices.js diff --git a/website_bkp/scripts/options/distribution/profitability.js b/website/scripts/options/distribution/profitability.js similarity index 100% rename from website_bkp/scripts/options/distribution/profitability.js rename to website/scripts/options/distribution/profitability.js diff --git a/website_bkp/scripts/options/distribution/valuation.js b/website/scripts/options/distribution/valuation.js similarity index 100% rename from website_bkp/scripts/options/distribution/valuation.js rename to website/scripts/options/distribution/valuation.js diff --git a/website_bkp/scripts/options/full.js b/website/scripts/options/full.js similarity index 100% rename from website_bkp/scripts/options/full.js rename to website/scripts/options/full.js diff --git a/website_bkp/scripts/options/investing.js b/website/scripts/options/investing.js similarity index 100% rename from website_bkp/scripts/options/investing.js rename to website/scripts/options/investing.js diff --git a/website_bkp/scripts/options/market.js b/website/scripts/options/market.js similarity index 100% rename from website_bkp/scripts/options/market.js rename to website/scripts/options/market.js diff --git a/website_bkp/scripts/options/mining.js b/website/scripts/options/mining.js similarity index 100% rename from website_bkp/scripts/options/mining.js rename to website/scripts/options/mining.js diff --git a/website_bkp/scripts/options/network.js b/website/scripts/options/network.js similarity index 100% rename from website_bkp/scripts/options/network.js rename to website/scripts/options/network.js diff --git a/website_bkp/scripts/options/partial.js b/website/scripts/options/partial.js similarity index 100% rename from website_bkp/scripts/options/partial.js rename to website/scripts/options/partial.js diff --git a/website_bkp/scripts/options/series.js b/website/scripts/options/series.js similarity index 100% rename from website_bkp/scripts/options/series.js rename to website/scripts/options/series.js diff --git a/website_bkp/scripts/options/shared.js b/website/scripts/options/shared.js similarity index 100% rename from website_bkp/scripts/options/shared.js rename to website/scripts/options/shared.js diff --git a/website_bkp/scripts/options/types.js b/website/scripts/options/types.js similarity index 100% rename from website_bkp/scripts/options/types.js rename to website/scripts/options/types.js diff --git a/website_bkp/scripts/options/unused.js b/website/scripts/options/unused.js similarity index 100% rename from website_bkp/scripts/options/unused.js rename to website/scripts/options/unused.js diff --git a/website_bkp/scripts/panes/chart.js b/website/scripts/panes/chart.js similarity index 100% rename from website_bkp/scripts/panes/chart.js rename to website/scripts/panes/chart.js diff --git a/website_bkp/scripts/panes/search.js b/website/scripts/panes/search.js similarity index 100% rename from website_bkp/scripts/panes/search.js rename to website/scripts/panes/search.js diff --git a/website_bkp/scripts/panes/share.js b/website/scripts/panes/share.js similarity index 100% rename from website_bkp/scripts/panes/share.js rename to website/scripts/panes/share.js diff --git a/website_bkp/scripts/utils/array.js b/website/scripts/utils/array.js similarity index 100% rename from website_bkp/scripts/utils/array.js rename to website/scripts/utils/array.js diff --git a/website_bkp/scripts/utils/chart/capture.js b/website/scripts/utils/chart/capture.js similarity index 100% rename from website_bkp/scripts/utils/chart/capture.js rename to website/scripts/utils/chart/capture.js diff --git a/website_bkp/scripts/utils/chart/index.js b/website/scripts/utils/chart/index.js similarity index 100% rename from website_bkp/scripts/utils/chart/index.js rename to website/scripts/utils/chart/index.js diff --git a/website_bkp/scripts/utils/chart/legend.js b/website/scripts/utils/chart/legend.js similarity index 100% rename from website_bkp/scripts/utils/chart/legend.js rename to website/scripts/utils/chart/legend.js diff --git a/website_bkp/scripts/utils/client.js b/website/scripts/utils/client.js similarity index 100% rename from website_bkp/scripts/utils/client.js rename to website/scripts/utils/client.js diff --git a/website_bkp/scripts/utils/colors.js b/website/scripts/utils/colors.js similarity index 100% rename from website_bkp/scripts/utils/colors.js rename to website/scripts/utils/colors.js diff --git a/website_bkp/scripts/utils/dom.js b/website/scripts/utils/dom.js similarity index 100% rename from website_bkp/scripts/utils/dom.js rename to website/scripts/utils/dom.js diff --git a/website_bkp/scripts/utils/elements.js b/website/scripts/utils/elements.js similarity index 100% rename from website_bkp/scripts/utils/elements.js rename to website/scripts/utils/elements.js diff --git a/website_bkp/scripts/utils/env.js b/website/scripts/utils/env.js similarity index 100% rename from website_bkp/scripts/utils/env.js rename to website/scripts/utils/env.js diff --git a/website_bkp/scripts/utils/format.js b/website/scripts/utils/format.js similarity index 100% rename from website_bkp/scripts/utils/format.js rename to website/scripts/utils/format.js diff --git a/website_bkp/scripts/utils/persisted.js b/website/scripts/utils/persisted.js similarity index 100% rename from website_bkp/scripts/utils/persisted.js rename to website/scripts/utils/persisted.js diff --git a/website_bkp/scripts/utils/price.js b/website/scripts/utils/price.js similarity index 100% rename from website_bkp/scripts/utils/price.js rename to website/scripts/utils/price.js diff --git a/website_bkp/scripts/utils/serde.js b/website/scripts/utils/serde.js similarity index 100% rename from website_bkp/scripts/utils/serde.js rename to website/scripts/utils/serde.js diff --git a/website_bkp/scripts/utils/storage.js b/website/scripts/utils/storage.js similarity index 100% rename from website_bkp/scripts/utils/storage.js rename to website/scripts/utils/storage.js diff --git a/website_bkp/scripts/utils/theme.js b/website/scripts/utils/theme.js similarity index 100% rename from website_bkp/scripts/utils/theme.js rename to website/scripts/utils/theme.js diff --git a/website_bkp/scripts/utils/time.js b/website/scripts/utils/time.js similarity index 100% rename from website_bkp/scripts/utils/time.js rename to website/scripts/utils/time.js diff --git a/website_bkp/scripts/utils/timing.js b/website/scripts/utils/timing.js similarity index 100% rename from website_bkp/scripts/utils/timing.js rename to website/scripts/utils/timing.js diff --git a/website_bkp/scripts/utils/units.js b/website/scripts/utils/units.js similarity index 100% rename from website_bkp/scripts/utils/units.js rename to website/scripts/utils/units.js diff --git a/website_bkp/scripts/utils/url.js b/website/scripts/utils/url.js similarity index 100% rename from website_bkp/scripts/utils/url.js rename to website/scripts/utils/url.js diff --git a/website_bkp/src/explorer/chain/cube/index.js b/website/src/explorer/chain/cube/index.js similarity index 100% rename from website_bkp/src/explorer/chain/cube/index.js rename to website/src/explorer/chain/cube/index.js diff --git a/website_bkp/src/explorer/chain/cube/style.css b/website/src/explorer/chain/cube/style.css similarity index 100% rename from website_bkp/src/explorer/chain/cube/style.css rename to website/src/explorer/chain/cube/style.css diff --git a/website_bkp/src/explorer/chain/index.js b/website/src/explorer/chain/index.js similarity index 100% rename from website_bkp/src/explorer/chain/index.js rename to website/src/explorer/chain/index.js diff --git a/website_bkp/src/explorer/chain/style.css b/website/src/explorer/chain/style.css similarity index 100% rename from website_bkp/src/explorer/chain/style.css rename to website/src/explorer/chain/style.css diff --git a/website_bkp/src/heatmap/controls/dates.js b/website/src/heatmap/controls/dates.js similarity index 100% rename from website_bkp/src/heatmap/controls/dates.js rename to website/src/heatmap/controls/dates.js diff --git a/website_bkp/src/heatmap/controls/index.js b/website/src/heatmap/controls/index.js similarity index 100% rename from website_bkp/src/heatmap/controls/index.js rename to website/src/heatmap/controls/index.js diff --git a/website_bkp/src/heatmap/controls/shared.js b/website/src/heatmap/controls/shared.js similarity index 100% rename from website_bkp/src/heatmap/controls/shared.js rename to website/src/heatmap/controls/shared.js diff --git a/website_bkp/src/heatmap/controls/y.js b/website/src/heatmap/controls/y.js similarity index 100% rename from website_bkp/src/heatmap/controls/y.js rename to website/src/heatmap/controls/y.js diff --git a/website_bkp/src/heatmap/format.js b/website/src/heatmap/format.js similarity index 100% rename from website_bkp/src/heatmap/format.js rename to website/src/heatmap/format.js diff --git a/website_bkp/src/heatmap/grid.js b/website/src/heatmap/grid.js similarity index 100% rename from website_bkp/src/heatmap/grid.js rename to website/src/heatmap/grid.js diff --git a/website_bkp/src/heatmap/index.js b/website/src/heatmap/index.js similarity index 100% rename from website_bkp/src/heatmap/index.js rename to website/src/heatmap/index.js diff --git a/website_bkp/src/heatmap/loader.js b/website/src/heatmap/loader.js similarity index 100% rename from website_bkp/src/heatmap/loader.js rename to website/src/heatmap/loader.js diff --git a/website_bkp/src/heatmap/lut.js b/website/src/heatmap/lut.js similarity index 100% rename from website_bkp/src/heatmap/lut.js rename to website/src/heatmap/lut.js diff --git a/website_bkp/src/heatmap/oracle.js b/website/src/heatmap/oracle.js similarity index 100% rename from website_bkp/src/heatmap/oracle.js rename to website/src/heatmap/oracle.js diff --git a/website_bkp/src/heatmap/renderer.js b/website/src/heatmap/renderer.js similarity index 100% rename from website_bkp/src/heatmap/renderer.js rename to website/src/heatmap/renderer.js diff --git a/website_bkp/src/heatmap/style.css b/website/src/heatmap/style.css similarity index 100% rename from website_bkp/src/heatmap/style.css rename to website/src/heatmap/style.css diff --git a/website_bkp/src/heatmap/time.js b/website/src/heatmap/time.js similarity index 100% rename from website_bkp/src/heatmap/time.js rename to website/src/heatmap/time.js diff --git a/website_bkp/src/heatmap/tooltip/index.js b/website/src/heatmap/tooltip/index.js similarity index 100% rename from website_bkp/src/heatmap/tooltip/index.js rename to website/src/heatmap/tooltip/index.js diff --git a/website_bkp/src/heatmap/tooltip/view.js b/website/src/heatmap/tooltip/view.js similarity index 100% rename from website_bkp/src/heatmap/tooltip/view.js rename to website/src/heatmap/tooltip/view.js diff --git a/website_bkp/src/heatmap/types.js b/website/src/heatmap/types.js similarity index 100% rename from website_bkp/src/heatmap/types.js rename to website/src/heatmap/types.js diff --git a/website_bkp/src/heatmap/urpd.js b/website/src/heatmap/urpd.js similarity index 100% rename from website_bkp/src/heatmap/urpd.js rename to website/src/heatmap/urpd.js diff --git a/website_bkp/styles/chart.css b/website/styles/chart.css similarity index 100% rename from website_bkp/styles/chart.css rename to website/styles/chart.css diff --git a/website_bkp/styles/components.css b/website/styles/components.css similarity index 100% rename from website_bkp/styles/components.css rename to website/styles/components.css diff --git a/website_bkp/styles/elements.css b/website/styles/elements.css similarity index 100% rename from website_bkp/styles/elements.css rename to website/styles/elements.css diff --git a/website/styles/fonts.css b/website/styles/fonts.css index a2989d984..63a1cd5d5 100644 --- a/website/styles/fonts.css +++ b/website/styles/fonts.css @@ -15,7 +15,6 @@ font-display: block; } -/* Preloaded in index.html — keep URL in sync. */ @font-face { font-family: Instrument; src: url("/assets/fonts/InstrumentSerif-Regular.woff2") format("woff2"); @@ -30,23 +29,12 @@ font-display: block; } -:root { - --font-mono: - "Lilex", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - "Liberation Mono", "Courier New", monospace; - --font-serif: - Instrument, Charter, "Bitstream Charter", "Sitka Text", Cambria, serif; -} - html { font-family: var(--font-mono); } -h1, -h2, -h3 { +h1 { font-family: var(--font-serif); - font-weight: 400; } code { diff --git a/website/styles/main.css b/website/styles/main.css index 856b971f0..b6bb4a713 100644 --- a/website/styles/main.css +++ b/website/styles/main.css @@ -1,33 +1,162 @@ -[hidden] { - display: none !important; -} +main { + grid-row: 1; + grid-column: 1; + position: relative; + display: flex; + min-height: 0; -html, -body { - background: var(--black); -} - -body { - > main { - position: fixed; - inset: 0; - overflow: auto; - color: white; - opacity: 0; + &::before, + &::after { + content: ""; + position: absolute; + left: 0; + right: 0; + z-index: 10; pointer-events: none; - scroll-behavior: smooth; - transition: opacity 150ms ease; } - > main[data-active] { - opacity: 1; + &::before { + top: 0; + height: var(--main-padding); + background-image: linear-gradient( + to top, + transparent, + var(--background-color) + ); + } + + &::after { + bottom: 0; + height: var(--main-padding); + background-image: linear-gradient( + to bottom, + transparent, + var(--background-color) + ); + } + + html[data-layout="full"] & { + width: 100%; + } + + html[data-layout="split"] & { + overflow-x: hidden; + contain: inline-size; + } + + > nav, + > search { + flex: 1; + overflow-x: hidden; + overflow-y: auto; + padding: var(--main-padding); + height: 100%; + display: flex; + flex-direction: column; + padding-bottom: 12rem; + } +} + +#resize-bar { + display: none; + grid-column: 1; + grid-row: 1 / -1; + justify-self: end; + width: 8px; + margin: 0 -4px; + z-index: 50; + position: relative; + cursor: col-resize; + touch-action: none; + + &::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 50%; + width: 2px; + translate: -50% 0; + background: transparent; + transition: background 0.15s; + } + + &:hover { + background: var(--border-color); + + &::after { + background: var(--color); + } + } + + html[data-resize] &::after { + background: var(--color); + } + + html[data-layout="split"] & { + display: block; + } +} + +footer { + grid-row: 2; + grid-column: 1 / -1; + position: relative; + z-index: 2; + min-width: 0; + overflow: hidden; + text-transform: uppercase; + padding-bottom: var(--main-padding); + + html[data-layout="split"] & { + grid-column: 1; + } + + &::before, + &::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + width: var(--main-padding); + z-index: 1; + pointer-events: none; + } + + &::before { + left: 0; + background-image: linear-gradient( + to left, + transparent, + var(--background-color) + ); + } + + &::after { + right: 0; + background-image: linear-gradient( + to right, + transparent, + var(--background-color) + ); + } + + > fieldset { + display: flex; + gap: 1.125rem; + overflow-x: auto; + min-width: 0; + margin: -0.5rem 0; + padding: 0.5rem var(--main-padding); pointer-events: auto; - } -} -@media (prefers-reduced-motion: reduce) { - body > main { - scroll-behavior: auto; - transition: none; + > label, + > button { + flex-shrink: 0; + } + + > button { + color: var(--off-color); + } } } diff --git a/website_bkp/styles/nav.css b/website/styles/nav.css similarity index 100% rename from website_bkp/styles/nav.css rename to website/styles/nav.css diff --git a/website_bkp/styles/panes/chart.css b/website/styles/panes/chart.css similarity index 100% rename from website_bkp/styles/panes/chart.css rename to website/styles/panes/chart.css diff --git a/website_bkp/styles/panes/explorer.css b/website/styles/panes/explorer.css similarity index 100% rename from website_bkp/styles/panes/explorer.css rename to website/styles/panes/explorer.css diff --git a/website_bkp/styles/search.css b/website/styles/search.css similarity index 100% rename from website_bkp/styles/search.css rename to website/styles/search.css diff --git a/website/styles/variables.css b/website/styles/variables.css index 6132d5bda..a41fc41cd 100644 --- a/website/styles/variables.css +++ b/website/styles/variables.css @@ -33,6 +33,12 @@ --inv-border-color: light-dark(var(--dark-gray), var(--light-gray)); --off-border-color: light-dark(var(--dark-white), var(--light-black)); + --font-mono: + "Lilex", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; + --font-serif: + Instrument, Charter, "Bitstream Charter", "Sitka Text", Cambria, serif; + --font-size-xs: 0.75rem; --line-height-xs: calc(1 / 0.75); --font-size-sm: 0.875rem; @@ -45,6 +51,9 @@ --line-height-xl: calc(1.75 / 1.25); --main-padding: 2rem; + /*@media (max-width: 767px) { + --main-padding: 1.5rem; + }*/ --negative-main-padding: calc(-1 * var(--main-padding)); --font-weight-base: 400; --max-main-width: 70dvw; diff --git a/website_bkp/index.html b/website_bkp/index.html deleted file mode 100644 index 8a6b9ce4e..000000000 --- a/website_bkp/index.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - bitview - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
-
- -
-
- - - - - - - - - -
-
- - - diff --git a/website_bkp/styles/main.css b/website_bkp/styles/main.css deleted file mode 100644 index b6bb4a713..000000000 --- a/website_bkp/styles/main.css +++ /dev/null @@ -1,162 +0,0 @@ -main { - grid-row: 1; - grid-column: 1; - position: relative; - display: flex; - min-height: 0; - - &::before, - &::after { - content: ""; - position: absolute; - left: 0; - right: 0; - z-index: 10; - pointer-events: none; - } - - &::before { - top: 0; - height: var(--main-padding); - background-image: linear-gradient( - to top, - transparent, - var(--background-color) - ); - } - - &::after { - bottom: 0; - height: var(--main-padding); - background-image: linear-gradient( - to bottom, - transparent, - var(--background-color) - ); - } - - html[data-layout="full"] & { - width: 100%; - } - - html[data-layout="split"] & { - overflow-x: hidden; - contain: inline-size; - } - - > nav, - > search { - flex: 1; - overflow-x: hidden; - overflow-y: auto; - padding: var(--main-padding); - height: 100%; - display: flex; - flex-direction: column; - padding-bottom: 12rem; - } -} - -#resize-bar { - display: none; - grid-column: 1; - grid-row: 1 / -1; - justify-self: end; - width: 8px; - margin: 0 -4px; - z-index: 50; - position: relative; - cursor: col-resize; - touch-action: none; - - &::after { - content: ""; - position: absolute; - top: 0; - bottom: 0; - left: 50%; - width: 2px; - translate: -50% 0; - background: transparent; - transition: background 0.15s; - } - - &:hover { - background: var(--border-color); - - &::after { - background: var(--color); - } - } - - html[data-resize] &::after { - background: var(--color); - } - - html[data-layout="split"] & { - display: block; - } -} - -footer { - grid-row: 2; - grid-column: 1 / -1; - position: relative; - z-index: 2; - min-width: 0; - overflow: hidden; - text-transform: uppercase; - padding-bottom: var(--main-padding); - - html[data-layout="split"] & { - grid-column: 1; - } - - &::before, - &::after { - content: ""; - position: absolute; - top: 0; - bottom: 0; - width: var(--main-padding); - z-index: 1; - pointer-events: none; - } - - &::before { - left: 0; - background-image: linear-gradient( - to left, - transparent, - var(--background-color) - ); - } - - &::after { - right: 0; - background-image: linear-gradient( - to right, - transparent, - var(--background-color) - ); - } - - > fieldset { - display: flex; - gap: 1.125rem; - overflow-x: auto; - min-width: 0; - margin: -0.5rem 0; - padding: 0.5rem var(--main-padding); - pointer-events: auto; - - > label, - > button { - flex-shrink: 0; - } - - > button { - color: var(--off-color); - } - } -} diff --git a/website_bkp/.gitignore b/website_next/.gitignore similarity index 100% rename from website_bkp/.gitignore rename to website_next/.gitignore diff --git a/website_bkp/.well-known/ai-plugin.json b/website_next/.well-known/ai-plugin.json similarity index 100% rename from website_bkp/.well-known/ai-plugin.json rename to website_next/.well-known/ai-plugin.json diff --git a/website_bkp/AGENTS.md b/website_next/AGENTS.md similarity index 64% rename from website_bkp/AGENTS.md rename to website_next/AGENTS.md index 49f27bc96..4873a8318 100644 --- a/website_bkp/AGENTS.md +++ b/website_next/AGENTS.md @@ -1,3 +1,7 @@ +# Rule + +before editing a file, always explain why that code, why it's the most optimal one and wait for my feedback + # Types To check types run: @@ -21,3 +25,4 @@ ALWAYS - reads like english - very easy to understand - very easy to maintain +- avoid defensive checks when the code itself guarantees correctness diff --git a/website_bkp/assets/favicon/apple-touch-icon.png b/website_next/apple-touch-icon.png similarity index 100% rename from website_bkp/assets/favicon/apple-touch-icon.png rename to website_next/apple-touch-icon.png diff --git a/website_bkp/assets/fonts/InstrumentSerif-Italic.woff2 b/website_next/assets/fonts/InstrumentSerif-Italic.woff2 similarity index 100% rename from website_bkp/assets/fonts/InstrumentSerif-Italic.woff2 rename to website_next/assets/fonts/InstrumentSerif-Italic.woff2 diff --git a/website_bkp/assets/fonts/InstrumentSerif-Regular.woff2 b/website_next/assets/fonts/InstrumentSerif-Regular.woff2 similarity index 100% rename from website_bkp/assets/fonts/InstrumentSerif-Regular.woff2 rename to website_next/assets/fonts/InstrumentSerif-Regular.woff2 diff --git a/website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 b/website_next/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 similarity index 100% rename from website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 rename to website_next/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 diff --git a/website_bkp/assets/fonts/Lilex[wght]-v2_620.woff2 b/website_next/assets/fonts/Lilex[wght]-v2_620.woff2 similarity index 100% rename from website_bkp/assets/fonts/Lilex[wght]-v2_620.woff2 rename to website_next/assets/fonts/Lilex[wght]-v2_620.woff2 diff --git a/website_bkp/assets/logo/.gitignore b/website_next/assets/logo/.gitignore similarity index 100% rename from website_bkp/assets/logo/.gitignore rename to website_next/assets/logo/.gitignore diff --git a/website_bkp/assets/logo/demo-svg.html b/website_next/assets/logo/demo-svg.html similarity index 100% rename from website_bkp/assets/logo/demo-svg.html rename to website_next/assets/logo/demo-svg.html diff --git a/website_bkp/assets/logo/demo.html b/website_next/assets/logo/demo.html similarity index 100% rename from website_bkp/assets/logo/demo.html rename to website_next/assets/logo/demo.html diff --git a/website_bkp/assets/logo/logo-dark.svg b/website_next/assets/logo/logo-dark.svg similarity index 100% rename from website_bkp/assets/logo/logo-dark.svg rename to website_next/assets/logo/logo-dark.svg diff --git a/website_bkp/assets/logo/logo-light.svg b/website_next/assets/logo/logo-light.svg similarity index 100% rename from website_bkp/assets/logo/logo-light.svg rename to website_next/assets/logo/logo-light.svg diff --git a/website_bkp/assets/logo/logo-orange.svg b/website_next/assets/logo/logo-orange.svg similarity index 100% rename from website_bkp/assets/logo/logo-orange.svg rename to website_next/assets/logo/logo-orange.svg diff --git a/website_bkp/assets/logo/logo.svg b/website_next/assets/logo/logo.svg similarity index 100% rename from website_bkp/assets/logo/logo.svg rename to website_next/assets/logo/logo.svg diff --git a/website_bkp/assets/pools.sh b/website_next/assets/pools.sh similarity index 100% rename from website_bkp/assets/pools.sh rename to website_next/assets/pools.sh diff --git a/website_bkp/assets/pools/1thash.svg b/website_next/assets/pools/1thash.svg similarity index 100% rename from website_bkp/assets/pools/1thash.svg rename to website_next/assets/pools/1thash.svg diff --git a/website_bkp/assets/pools/antpool.svg b/website_next/assets/pools/antpool.svg similarity index 100% rename from website_bkp/assets/pools/antpool.svg rename to website_next/assets/pools/antpool.svg diff --git a/website_bkp/assets/pools/arkpool.svg b/website_next/assets/pools/arkpool.svg similarity index 100% rename from website_bkp/assets/pools/arkpool.svg rename to website_next/assets/pools/arkpool.svg diff --git a/website_bkp/assets/pools/binancepool.svg b/website_next/assets/pools/binancepool.svg similarity index 100% rename from website_bkp/assets/pools/binancepool.svg rename to website_next/assets/pools/binancepool.svg diff --git a/website_bkp/assets/pools/bitcoincom.svg b/website_next/assets/pools/bitcoincom.svg similarity index 100% rename from website_bkp/assets/pools/bitcoincom.svg rename to website_next/assets/pools/bitcoincom.svg diff --git a/website_bkp/assets/pools/bitfufupool.svg b/website_next/assets/pools/bitfufupool.svg similarity index 100% rename from website_bkp/assets/pools/bitfufupool.svg rename to website_next/assets/pools/bitfufupool.svg diff --git a/website_bkp/assets/pools/bitfury.svg b/website_next/assets/pools/bitfury.svg similarity index 100% rename from website_bkp/assets/pools/bitfury.svg rename to website_next/assets/pools/bitfury.svg diff --git a/website_bkp/assets/pools/braiinspool.svg b/website_next/assets/pools/braiinspool.svg similarity index 100% rename from website_bkp/assets/pools/braiinspool.svg rename to website_next/assets/pools/braiinspool.svg diff --git a/website_bkp/assets/pools/braiinssolo.svg b/website_next/assets/pools/braiinssolo.svg similarity index 100% rename from website_bkp/assets/pools/braiinssolo.svg rename to website_next/assets/pools/braiinssolo.svg diff --git a/website_bkp/assets/pools/btccom.svg b/website_next/assets/pools/btccom.svg similarity index 100% rename from website_bkp/assets/pools/btccom.svg rename to website_next/assets/pools/btccom.svg diff --git a/website_bkp/assets/pools/btclab.svg b/website_next/assets/pools/btclab.svg similarity index 100% rename from website_bkp/assets/pools/btclab.svg rename to website_next/assets/pools/btclab.svg diff --git a/website_bkp/assets/pools/btctop.svg b/website_next/assets/pools/btctop.svg similarity index 100% rename from website_bkp/assets/pools/btctop.svg rename to website_next/assets/pools/btctop.svg diff --git a/website_bkp/assets/pools/default.light.svg b/website_next/assets/pools/default.light.svg similarity index 100% rename from website_bkp/assets/pools/default.light.svg rename to website_next/assets/pools/default.light.svg diff --git a/website_bkp/assets/pools/default.svg b/website_next/assets/pools/default.svg similarity index 100% rename from website_bkp/assets/pools/default.svg rename to website_next/assets/pools/default.svg diff --git a/website_bkp/assets/pools/emcdpool.svg b/website_next/assets/pools/emcdpool.svg similarity index 100% rename from website_bkp/assets/pools/emcdpool.svg rename to website_next/assets/pools/emcdpool.svg diff --git a/website_bkp/assets/pools/est3lar.svg b/website_next/assets/pools/est3lar.svg similarity index 100% rename from website_bkp/assets/pools/est3lar.svg rename to website_next/assets/pools/est3lar.svg diff --git a/website_bkp/assets/pools/f2pool.svg b/website_next/assets/pools/f2pool.svg similarity index 100% rename from website_bkp/assets/pools/f2pool.svg rename to website_next/assets/pools/f2pool.svg diff --git a/website_bkp/assets/pools/foundryusa.light.svg b/website_next/assets/pools/foundryusa.light.svg similarity index 100% rename from website_bkp/assets/pools/foundryusa.light.svg rename to website_next/assets/pools/foundryusa.light.svg diff --git a/website_bkp/assets/pools/foundryusa.svg b/website_next/assets/pools/foundryusa.svg similarity index 100% rename from website_bkp/assets/pools/foundryusa.svg rename to website_next/assets/pools/foundryusa.svg diff --git a/website_bkp/assets/pools/gdpool.svg b/website_next/assets/pools/gdpool.svg similarity index 100% rename from website_bkp/assets/pools/gdpool.svg rename to website_next/assets/pools/gdpool.svg diff --git a/website_bkp/assets/pools/huobipool.svg b/website_next/assets/pools/huobipool.svg similarity index 100% rename from website_bkp/assets/pools/huobipool.svg rename to website_next/assets/pools/huobipool.svg diff --git a/website_bkp/assets/pools/innopolistech.svg b/website_next/assets/pools/innopolistech.svg similarity index 100% rename from website_bkp/assets/pools/innopolistech.svg rename to website_next/assets/pools/innopolistech.svg diff --git a/website_bkp/assets/pools/kucoinpool.svg b/website_next/assets/pools/kucoinpool.svg similarity index 100% rename from website_bkp/assets/pools/kucoinpool.svg rename to website_next/assets/pools/kucoinpool.svg diff --git a/website_bkp/assets/pools/luxor.svg b/website_next/assets/pools/luxor.svg similarity index 100% rename from website_bkp/assets/pools/luxor.svg rename to website_next/assets/pools/luxor.svg diff --git a/website_bkp/assets/pools/marapool.svg b/website_next/assets/pools/marapool.svg similarity index 100% rename from website_bkp/assets/pools/marapool.svg rename to website_next/assets/pools/marapool.svg diff --git a/website_bkp/assets/pools/maxipool.svg b/website_next/assets/pools/maxipool.svg similarity index 100% rename from website_bkp/assets/pools/maxipool.svg rename to website_next/assets/pools/maxipool.svg diff --git a/website_bkp/assets/pools/minerium.svg b/website_next/assets/pools/minerium.svg similarity index 100% rename from website_bkp/assets/pools/minerium.svg rename to website_next/assets/pools/minerium.svg diff --git a/website_bkp/assets/pools/miningsquared.svg b/website_next/assets/pools/miningsquared.svg similarity index 100% rename from website_bkp/assets/pools/miningsquared.svg rename to website_next/assets/pools/miningsquared.svg diff --git a/website_bkp/assets/pools/mononaut.svg b/website_next/assets/pools/mononaut.svg similarity index 100% rename from website_bkp/assets/pools/mononaut.svg rename to website_next/assets/pools/mononaut.svg diff --git a/website_bkp/assets/pools/neopool.svg b/website_next/assets/pools/neopool.svg similarity index 100% rename from website_bkp/assets/pools/neopool.svg rename to website_next/assets/pools/neopool.svg diff --git a/website_bkp/assets/pools/nicehash.svg b/website_next/assets/pools/nicehash.svg similarity index 100% rename from website_bkp/assets/pools/nicehash.svg rename to website_next/assets/pools/nicehash.svg diff --git a/website_bkp/assets/pools/ocean.svg b/website_next/assets/pools/ocean.svg similarity index 100% rename from website_bkp/assets/pools/ocean.svg rename to website_next/assets/pools/ocean.svg diff --git a/website_bkp/assets/pools/okexpool.svg b/website_next/assets/pools/okexpool.svg similarity index 100% rename from website_bkp/assets/pools/okexpool.svg rename to website_next/assets/pools/okexpool.svg diff --git a/website_bkp/assets/pools/okkong.svg b/website_next/assets/pools/okkong.svg similarity index 100% rename from website_bkp/assets/pools/okkong.svg rename to website_next/assets/pools/okkong.svg diff --git a/website_bkp/assets/pools/parasite.svg b/website_next/assets/pools/parasite.svg similarity index 100% rename from website_bkp/assets/pools/parasite.svg rename to website_next/assets/pools/parasite.svg diff --git a/website_bkp/assets/pools/pegapool.svg b/website_next/assets/pools/pegapool.svg similarity index 100% rename from website_bkp/assets/pools/pegapool.svg rename to website_next/assets/pools/pegapool.svg diff --git a/website_bkp/assets/pools/phoenix.svg b/website_next/assets/pools/phoenix.svg similarity index 100% rename from website_bkp/assets/pools/phoenix.svg rename to website_next/assets/pools/phoenix.svg diff --git a/website_bkp/assets/pools/poolin.svg b/website_next/assets/pools/poolin.svg similarity index 100% rename from website_bkp/assets/pools/poolin.svg rename to website_next/assets/pools/poolin.svg diff --git a/website_bkp/assets/pools/publicpool.svg b/website_next/assets/pools/publicpool.svg similarity index 100% rename from website_bkp/assets/pools/publicpool.svg rename to website_next/assets/pools/publicpool.svg diff --git a/website_bkp/assets/pools/rawpool.svg b/website_next/assets/pools/rawpool.svg similarity index 100% rename from website_bkp/assets/pools/rawpool.svg rename to website_next/assets/pools/rawpool.svg diff --git a/website_bkp/assets/pools/sbicrypto.svg b/website_next/assets/pools/sbicrypto.svg similarity index 100% rename from website_bkp/assets/pools/sbicrypto.svg rename to website_next/assets/pools/sbicrypto.svg diff --git a/website_bkp/assets/pools/secpool.svg b/website_next/assets/pools/secpool.svg similarity index 100% rename from website_bkp/assets/pools/secpool.svg rename to website_next/assets/pools/secpool.svg diff --git a/website_bkp/assets/pools/sigmapoolcom.svg b/website_next/assets/pools/sigmapoolcom.svg similarity index 100% rename from website_bkp/assets/pools/sigmapoolcom.svg rename to website_next/assets/pools/sigmapoolcom.svg diff --git a/website_bkp/assets/pools/slushpool.svg b/website_next/assets/pools/slushpool.svg similarity index 100% rename from website_bkp/assets/pools/slushpool.svg rename to website_next/assets/pools/slushpool.svg diff --git a/website_bkp/assets/pools/solopoolcom.svg b/website_next/assets/pools/solopoolcom.svg similarity index 100% rename from website_bkp/assets/pools/solopoolcom.svg rename to website_next/assets/pools/solopoolcom.svg diff --git a/website_bkp/assets/pools/spiderpool.svg b/website_next/assets/pools/spiderpool.svg similarity index 100% rename from website_bkp/assets/pools/spiderpool.svg rename to website_next/assets/pools/spiderpool.svg diff --git a/website_bkp/assets/pools/terrapool.svg b/website_next/assets/pools/terrapool.svg similarity index 100% rename from website_bkp/assets/pools/terrapool.svg rename to website_next/assets/pools/terrapool.svg diff --git a/website_bkp/assets/pools/titan.svg b/website_next/assets/pools/titan.svg similarity index 100% rename from website_bkp/assets/pools/titan.svg rename to website_next/assets/pools/titan.svg diff --git a/website_bkp/assets/pools/ultimuspool.light.svg b/website_next/assets/pools/ultimuspool.light.svg similarity index 100% rename from website_bkp/assets/pools/ultimuspool.light.svg rename to website_next/assets/pools/ultimuspool.light.svg diff --git a/website_bkp/assets/pools/ultimuspool.svg b/website_next/assets/pools/ultimuspool.svg similarity index 100% rename from website_bkp/assets/pools/ultimuspool.svg rename to website_next/assets/pools/ultimuspool.svg diff --git a/website_bkp/assets/pools/unknown.light.svg b/website_next/assets/pools/unknown.light.svg similarity index 100% rename from website_bkp/assets/pools/unknown.light.svg rename to website_next/assets/pools/unknown.light.svg diff --git a/website_bkp/assets/pools/unknown.svg b/website_next/assets/pools/unknown.svg similarity index 100% rename from website_bkp/assets/pools/unknown.svg rename to website_next/assets/pools/unknown.svg diff --git a/website_bkp/assets/pools/viabtc.svg b/website_next/assets/pools/viabtc.svg similarity index 100% rename from website_bkp/assets/pools/viabtc.svg rename to website_next/assets/pools/viabtc.svg diff --git a/website_bkp/assets/pools/wayicn.svg b/website_next/assets/pools/wayicn.svg similarity index 100% rename from website_bkp/assets/pools/wayicn.svg rename to website_next/assets/pools/wayicn.svg diff --git a/website_bkp/assets/pools/whitepool.light.svg b/website_next/assets/pools/whitepool.light.svg similarity index 100% rename from website_bkp/assets/pools/whitepool.light.svg rename to website_next/assets/pools/whitepool.light.svg diff --git a/website_bkp/assets/pools/whitepool.svg b/website_next/assets/pools/whitepool.svg similarity index 100% rename from website_bkp/assets/pools/whitepool.svg rename to website_next/assets/pools/whitepool.svg diff --git a/website_bkp/assets/pools/wiz.svg b/website_next/assets/pools/wiz.svg similarity index 100% rename from website_bkp/assets/pools/wiz.svg rename to website_next/assets/pools/wiz.svg diff --git a/website_bkp/assets/favicon/web-app-manifest-192x192.png b/website_next/assets/web-app-manifest-192x192.png similarity index 100% rename from website_bkp/assets/favicon/web-app-manifest-192x192.png rename to website_next/assets/web-app-manifest-192x192.png diff --git a/website_bkp/assets/favicon/web-app-manifest-512x512.png b/website_next/assets/web-app-manifest-512x512.png similarity index 100% rename from website_bkp/assets/favicon/web-app-manifest-512x512.png rename to website_next/assets/web-app-manifest-512x512.png diff --git a/website/build/index.js b/website_next/build/index.js similarity index 100% rename from website/build/index.js rename to website_next/build/index.js diff --git a/website/build/style.css b/website_next/build/style.css similarity index 100% rename from website/build/style.css rename to website_next/build/style.css diff --git a/website/cube/index.js b/website_next/cube/index.js similarity index 100% rename from website/cube/index.js rename to website_next/cube/index.js diff --git a/website/cube/style.css b/website_next/cube/style.css similarity index 100% rename from website/cube/style.css rename to website_next/cube/style.css diff --git a/website_bkp/scripts/entry.js b/website_next/entry.js similarity index 100% rename from website_bkp/scripts/entry.js rename to website_next/entry.js diff --git a/website/explore/index.js b/website_next/explore/index.js similarity index 100% rename from website/explore/index.js rename to website_next/explore/index.js diff --git a/website/explore/style.css b/website_next/explore/style.css similarity index 100% rename from website/explore/style.css rename to website_next/explore/style.css diff --git a/website_bkp/assets/favicon/favicon-96x96.png b/website_next/favicon-96x96.png similarity index 100% rename from website_bkp/assets/favicon/favicon-96x96.png rename to website_next/favicon-96x96.png diff --git a/website_bkp/assets/favicon/favicon.ico b/website_next/favicon.ico similarity index 100% rename from website_bkp/assets/favicon/favicon.ico rename to website_next/favicon.ico diff --git a/website_bkp/assets/favicon/favicon.svg b/website_next/favicon.svg similarity index 100% rename from website_bkp/assets/favicon/favicon.svg rename to website_next/favicon.svg diff --git a/website/header/index.js b/website_next/header/index.js similarity index 83% rename from website/header/index.js rename to website_next/header/index.js index ed832559f..2180a468c 100644 --- a/website/header/index.js +++ b/website_next/header/index.js @@ -3,9 +3,12 @@ import { createCube } from "../cube/index.js"; const header = document.createElement("header"); const home = document.createElement("a"); +const cube = document.createElement("span"); + home.href = "/"; home.ariaLabel = "bitview home"; -home.append(createCube(), "bitview"); +cube.append(createCube()); +home.append(cube, "bitview"); const nav = document.createElement("nav"); nav.setAttribute("aria-label", "Primary"); diff --git a/website/header/style.css b/website_next/header/style.css similarity index 72% rename from website/header/style.css rename to website_next/header/style.css index b64de6c78..f88bbb3ab 100644 --- a/website/header/style.css +++ b/website_next/header/style.css @@ -5,27 +5,43 @@ body { z-index: 10; display: grid; grid-template-columns: 1fr auto 1fr; - align-items: start; + align-items: center; font-size: var(--font-size-sm); line-height: 1; text-transform: uppercase; > a { + --color: var(--white); + opacity: 0.8; + justify-self: start; display: flex; align-items: center; - gap: 0.625rem; - color: white; + gap: 0.5rem; + color: var(--color); + font-size: var(--font-size-base); text-decoration: none; text-transform: lowercase; - &:hover, + &:hover { + opacity: 1; + } + &:active { - color: var(--orange); + opacity: 1; + --color: var(--orange); + } + + > span { + display: inline-grid; + padding: 0.2rem 0.3rem; + color: var(--black); + background-color: var(--color); + border-radius: 0.25rem; } .cube { - --size: 1rem; + --size: 0.75rem; animation: cube-fill 5s linear infinite alternate; } } diff --git a/website/home/index.js b/website_next/home/index.js similarity index 100% rename from website/home/index.js rename to website_next/home/index.js diff --git a/website/home/style.css b/website_next/home/style.css similarity index 100% rename from website/home/style.css rename to website_next/home/style.css diff --git a/website_next/index.html b/website_next/index.html new file mode 100644 index 000000000..61b84f9df --- /dev/null +++ b/website_next/index.html @@ -0,0 +1,94 @@ + + + + + bitview + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website_bkp/jsconfig.json b/website_next/jsconfig.json similarity index 100% rename from website_bkp/jsconfig.json rename to website_next/jsconfig.json diff --git a/website/learn/data.js b/website_next/learn/data.js similarity index 100% rename from website/learn/data.js rename to website_next/learn/data.js diff --git a/website/learn/index.js b/website_next/learn/index.js similarity index 100% rename from website/learn/index.js rename to website_next/learn/index.js diff --git a/website/learn/style.css b/website_next/learn/style.css similarity index 100% rename from website/learn/style.css rename to website_next/learn/style.css diff --git a/website_bkp/llms-full.txt b/website_next/llms-full.txt similarity index 100% rename from website_bkp/llms-full.txt rename to website_next/llms-full.txt diff --git a/website_bkp/llms.txt b/website_next/llms.txt similarity index 100% rename from website_bkp/llms.txt rename to website_next/llms.txt diff --git a/website/main.js b/website_next/main.js similarity index 100% rename from website/main.js rename to website_next/main.js diff --git a/website_bkp/manifest.webmanifest b/website_next/manifest.webmanifest similarity index 62% rename from website_bkp/manifest.webmanifest rename to website_next/manifest.webmanifest index e4b2ee912..a51e2790c 100644 --- a/website_bkp/manifest.webmanifest +++ b/website_next/manifest.webmanifest @@ -1,12 +1,8 @@ { "name": "bitview", "short_name": "bitview", - "description": "Bitcoin transparency, amplified", - "categories": [ - "bitcoin", - "on-chain", - "data" - ], + "description": "Explore Bitcoin data from blocks to patterns.", + "categories": ["bitcoin", "on-chain", "data"], "start_url": "/", "scope": "/", "display": "standalone", @@ -16,25 +12,25 @@ "lang": "en", "icons": [ { - "src": "/assets/favicon/web-app-manifest-192x192.png", + "src": "/assets/web-app-manifest-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/favicon/web-app-manifest-192x192.png", + "src": "/assets/web-app-manifest-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/favicon/web-app-manifest-512x512.png", + "src": "/assets/web-app-manifest-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/favicon/web-app-manifest-512x512.png", + "src": "/assets/web-app-manifest-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/website_bkp/robots.txt b/website_next/robots.txt similarity index 100% rename from website_bkp/robots.txt rename to website_next/robots.txt diff --git a/website_bkp/service-worker.js b/website_next/service-worker.js similarity index 100% rename from website_bkp/service-worker.js rename to website_next/service-worker.js diff --git a/website_bkp/styles/fonts.css b/website_next/styles/fonts.css similarity index 72% rename from website_bkp/styles/fonts.css rename to website_next/styles/fonts.css index 63a1cd5d5..a2989d984 100644 --- a/website_bkp/styles/fonts.css +++ b/website_next/styles/fonts.css @@ -15,6 +15,7 @@ font-display: block; } +/* Preloaded in index.html — keep URL in sync. */ @font-face { font-family: Instrument; src: url("/assets/fonts/InstrumentSerif-Regular.woff2") format("woff2"); @@ -29,12 +30,23 @@ font-display: block; } +:root { + --font-mono: + "Lilex", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; + --font-serif: + Instrument, Charter, "Bitstream Charter", "Sitka Text", Cambria, serif; +} + html { font-family: var(--font-mono); } -h1 { +h1, +h2, +h3 { font-family: var(--font-serif); + font-weight: 400; } code { diff --git a/website_next/styles/main.css b/website_next/styles/main.css new file mode 100644 index 000000000..856b971f0 --- /dev/null +++ b/website_next/styles/main.css @@ -0,0 +1,33 @@ +[hidden] { + display: none !important; +} + +html, +body { + background: var(--black); +} + +body { + > main { + position: fixed; + inset: 0; + overflow: auto; + color: white; + opacity: 0; + pointer-events: none; + scroll-behavior: smooth; + transition: opacity 150ms ease; + } + + > main[data-active] { + opacity: 1; + pointer-events: auto; + } +} + +@media (prefers-reduced-motion: reduce) { + body > main { + scroll-behavior: auto; + transition: none; + } +} diff --git a/website_bkp/styles/reset.css b/website_next/styles/reset.css similarity index 100% rename from website_bkp/styles/reset.css rename to website_next/styles/reset.css diff --git a/website_bkp/styles/variables.css b/website_next/styles/variables.css similarity index 85% rename from website_bkp/styles/variables.css rename to website_next/styles/variables.css index a41fc41cd..6132d5bda 100644 --- a/website_bkp/styles/variables.css +++ b/website_next/styles/variables.css @@ -33,12 +33,6 @@ --inv-border-color: light-dark(var(--dark-gray), var(--light-gray)); --off-border-color: light-dark(var(--dark-white), var(--light-black)); - --font-mono: - "Lilex", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - "Liberation Mono", "Courier New", monospace; - --font-serif: - Instrument, Charter, "Bitstream Charter", "Sitka Text", Cambria, serif; - --font-size-xs: 0.75rem; --line-height-xs: calc(1 / 0.75); --font-size-sm: 0.875rem; @@ -51,9 +45,6 @@ --line-height-xl: calc(1.75 / 1.25); --main-padding: 2rem; - /*@media (max-width: 767px) { - --main-padding: 1.5rem; - }*/ --negative-main-padding: calc(-1 * var(--main-padding)); --font-weight-base: 400; --max-main-width: 70dvw; diff --git a/website_bkp/tsconfig.json b/website_next/tsconfig.json similarity index 100% rename from website_bkp/tsconfig.json rename to website_next/tsconfig.json