mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-26 06:04:29 -07:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee30d1d36d | |||
| 0d9415db9d | |||
| 8020e1126f | |||
| 3439422057 | |||
| 68d2bf736f | |||
| d78c39fd8c | |||
| b1dcad86b4 | |||
| 9b6124074d | |||
| 02cbaa1e80 | |||
| a12f1321c7 |
@@ -39,11 +39,10 @@ permissions:
|
||||
# If there's a prerelease-style suffix to the version, then the release(s)
|
||||
# will be marked as a prerelease.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
tags:
|
||||
- "**[0-9]+.[0-9]+.[0-9]+*"
|
||||
- '**[0-9]+.[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
# Run 'dist plan' (or host) to determine what tasks we need to do
|
||||
|
||||
Generated
+72
-72
@@ -152,9 +152,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64"
|
||||
checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"flate2",
|
||||
@@ -374,7 +374,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"brk_cli",
|
||||
"brk_computer",
|
||||
@@ -391,7 +391,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_cli"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_core",
|
||||
@@ -412,7 +412,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_computer"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_exit",
|
||||
@@ -427,7 +427,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_core"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -444,7 +444,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_exit"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"brk_logger",
|
||||
"ctrlc",
|
||||
@@ -453,7 +453,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_fetcher"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_logger",
|
||||
@@ -466,7 +466,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_indexer"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -485,7 +485,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_logger"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"env_logger",
|
||||
@@ -495,7 +495,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_parser"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -510,7 +510,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_query"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_indexer",
|
||||
@@ -526,7 +526,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_server"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"brk_computer",
|
||||
@@ -552,7 +552,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_vec"
|
||||
version = "0.0.25"
|
||||
version = "0.0.29"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"axum",
|
||||
@@ -566,9 +566,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "7.0.0"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
|
||||
checksum = "cf19e729cdbd51af9a397fb9ef8ac8378007b797f8273cfbfdf45dcaa316167b"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -577,9 +577,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.3"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
|
||||
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -694,9 +694,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.36"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -704,9 +704,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.36"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1107,9 +1107,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "fjall"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b2ced3483989a62b3533c9f99054d73b527c6c0045cf22b00fe87956f1a46f"
|
||||
checksum = "958511f67d1f80e6bff9ffac05c626bb340d4602ca6ea5617d9901c218c894f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"byteview",
|
||||
@@ -1478,9 +1478,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.8"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0"
|
||||
checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"jiff-tzdb-platform",
|
||||
@@ -1493,9 +1493,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.8"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605"
|
||||
checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1585,9 +1585,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "lsm-tree"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a63a5e98a38b51765274137d8aedfbd848da5f4d016867e186b673fcc06a8c"
|
||||
checksum = "87d58bdef2dcbf50fce9f343265bdbd7fb08a458d241eb837ce426be22d674b4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crossbeam-skiplist",
|
||||
@@ -1791,9 +1791,9 @@ checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
|
||||
[[package]]
|
||||
name = "oxc"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "548086420c5c78546c7417384689af59ed11dbe9462e8bfef42636be0f545b96"
|
||||
checksum = "339134dd7e4bb36c2d0e97601fe4193b37649f729e94e7c26667feecd439b27e"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1834,9 +1834,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_allocator"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acaf33eacde1fca8fdb26655d7486842a8106916bc3855265607db2b4a4eaec4"
|
||||
checksum = "56c3dd872f5f819775c28163977399a1dd4f2177f3745dcb1bfd4214bae27e43"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
@@ -1848,9 +1848,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3044daf0f6b02f27330954141d799f9206e04b9175a3f4fa199f78c5ef46b2b4"
|
||||
checksum = "a1bebb401e36d73f35400ee9609ab6372b457543ce7bb1ef17c922235f24ba7b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -1865,9 +1865,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_macros"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee5d1546ecb309530b30b48f1aefefad7e6d53b8502e7b91b20d6a523af270e"
|
||||
checksum = "3b997c2a787321814d6e92f212486b4d590af4dbfff5c2265d3b0386e016eafe"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1876,9 +1876,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_visit"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b29d0e9e05d2638317c39470b5a528e268fc088ae1e3fda26b049661f2de25ad"
|
||||
checksum = "e1ee363bd1ff2000ae2a1052bb4d68e827e62f76e0139449ad1301ad9adc6ac4"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1888,9 +1888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_cfg"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b3740da43d597136474fa738bafb697c8469b8ecd9c256819ae443ec91a67aa"
|
||||
checksum = "77cb606168f768c747885ae48272287a028de5374db865c29d6d307d3b601a97"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"itertools",
|
||||
@@ -1903,9 +1903,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_codegen"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee5e197f8bed070bcc6e9744a7a5f91bc4ff250543f07849567e6e602383c7db"
|
||||
checksum = "4afef88d94fe9eee073332e3f908bd429baa989300d83152dab10dad99bd2a66"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -1924,15 +1924,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_data_structures"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ca20f4fc9af4f462bfc6bbca60e3f4c2ca9c4f09e99363c0c85d90bb936641c"
|
||||
checksum = "235fe6251a3f06813e77b45f3cd9c7ec5d0a23741c33f6c308b5af393d5d2409"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_diagnostics"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50e5ef1106d01ade76eec600e5b0da38932f555d1cb661f0d5ec7f3d717da22d"
|
||||
checksum = "2cd0f62519773d942baf1a17474e53b535182182f2cb41319ad1c2782e34310d"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"oxc-miette",
|
||||
@@ -1940,9 +1940,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ecmascript"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76b1ea0ef90fda6b68127181b3b136b21041a595e8c2028c4e08fcf85f99a10c"
|
||||
checksum = "5d073fdd2a3e1adb63731faab3c3861d0f9244cc15e88453d78460a4b2a604ca"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"num-bigint",
|
||||
@@ -1954,9 +1954,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_estree"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9ce9584683d43622ef4b66bd605ce9878f3bf7468b9b59ad041f33af13c34d"
|
||||
checksum = "59df015cfd58d084b27d049281835094556a4469db3e2ac45b0676336e0aeed8"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_index"
|
||||
@@ -1966,9 +1966,9 @@ checksum = "2fa07b0cfa997730afed43705766ef27792873fdf5215b1391949fec678d2392"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_mangler"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20c80a552dc097088d466679bcaba2576bbe88a430ca9c5b0cb67e23787aaa7a"
|
||||
checksum = "7dfc3363726f4ade77ba4d9e56cc38cc306436feee7b72e1c69436fb30c02b9b"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"itertools",
|
||||
@@ -1983,9 +1983,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_minifier"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5e504ac83f23ff755eae4ebd6291258b44e05cf58379e1fe1c00b1007e41f29"
|
||||
checksum = "f095580f12a6277d4cb532310ba95cc6d1f719b6c59341fb392b71e37d1207e6"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"oxc_allocator",
|
||||
@@ -2005,9 +2005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_parser"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "688491b2dfe8049a6410bc6b92f71e75bebfe9a1f352a64084a62069cd644e7f"
|
||||
checksum = "8d54fd003e5347dcb5ccdcc96cb283bf32a648ff291912b5a6e5e718b3359935"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -2028,9 +2028,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_regular_expression"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be6231edf43b8ca0fa8edad93b0b8e9067a3991ea2d8aa9f22a4c8fa464f267"
|
||||
checksum = "5e6e8058355e43a2388112eddf73031d8749b40255ad6f3a824e35fe0c6addec"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast_macros",
|
||||
@@ -2044,9 +2044,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_semantic"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f5c80c996fafc27a8444732bbba06f1de3eb488c585d65293a4b40b089ff564"
|
||||
checksum = "3f9f297db174c99b43e1b268b0960dcc588767093575cc39bb5517196a7a21d3"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"oxc_allocator",
|
||||
@@ -2080,9 +2080,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_span"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bce0a945765d00dd9ee0bfdc38fa265008e66f919157894c0383c525d026511f"
|
||||
checksum = "69575b94d8fdac097784abf48a5e43ee38375aa377f8e9bb8bc80f2ef3d2269c"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"oxc-miette",
|
||||
@@ -2093,9 +2093,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_syntax"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12b876a00908cb1fc6648823d7d8579a69af1c5a5c6d4cf6135040e09f41d116"
|
||||
checksum = "32c4940ed3e38ce51fb6bc3e880edb815182bdcdc19c6dc110857625aac9c9a7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -2114,9 +2114,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_traverse"
|
||||
version = "0.64.0"
|
||||
version = "0.65.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9c25f3da54211abd4b6ff1390a0f28d42b2128cb33f4b38edbdc5cb71bc3d3c"
|
||||
checksum = "5f8868dcb4ac2cd1e08dadbf34cd4fd9bbf36b70ef64dfa3376e1042a9f705a3"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"itoa",
|
||||
@@ -2718,9 +2718,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -3153,9 +3153,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "value-log"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd29b17c041f94e0885179637289815cd038f0c9fc19c4549d5a97017404fb7d"
|
||||
checksum = "62fc7c4ce161f049607ecea654dca3f2d727da5371ae85e2e4f14ce2b98ed67c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"byteview",
|
||||
|
||||
+12
-10
@@ -4,7 +4,7 @@ members = ["crates/*"]
|
||||
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
|
||||
package.license = "MIT"
|
||||
package.edition = "2024"
|
||||
package.version = "0.0.25"
|
||||
package.version = "0.0.29"
|
||||
package.repository = "https://github.com/bitcoinresearchkit/brk"
|
||||
|
||||
[profile.release]
|
||||
@@ -31,11 +31,11 @@ brk_query = { version = "0", path = "crates/brk_query" }
|
||||
brk_server = { version = "0", path = "crates/brk_server" }
|
||||
brk_vec = { version = "0", path = "crates/brk_vec" }
|
||||
byteview = "0.6.1"
|
||||
clap = { version = "4.5.36", features = ["derive", "string"] }
|
||||
clap = { version = "4.5.37", features = ["derive", "string"] }
|
||||
color-eyre = "0.6.3"
|
||||
derive_deref = "1.1.1"
|
||||
fjall = "2.8.0"
|
||||
jiff = "0.2.8"
|
||||
fjall = "2.9.0"
|
||||
jiff = "0.2.10"
|
||||
log = { version = "0.4.27" }
|
||||
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
|
||||
rayon = "1.10.0"
|
||||
@@ -50,19 +50,21 @@ tag-name = "v{{version}}"
|
||||
pre-release-commit-message = "release: v{{version}}"
|
||||
tag-message = "release: v{{version}}"
|
||||
|
||||
# Config for 'dist'
|
||||
[workspace.metadata.dist]
|
||||
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
|
||||
cargo-dist-version = "0.28.0"
|
||||
# CI backends to support
|
||||
ci = "github"
|
||||
# The installers to generate for each app
|
||||
installers = []
|
||||
# Target platforms to build apps for (Rust target-triple syntax)
|
||||
targets = [
|
||||
"aarch64-apple-darwin",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
]
|
||||
github-custom-runners.global = "ubuntu-latest"
|
||||
|
||||
[workspace.metadata.dist.github-custom-runners]
|
||||
global = "ubuntu-latest"
|
||||
aarch64-apple-darwin.runner = "macos-14"
|
||||
x86_64-unknown-linux-gnu.runner = "ubuntu-latest"
|
||||
x86_64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
|
||||
aarch64-unknown-linux-gnu.runner = "ubuntu-latest"
|
||||
aarch64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
|
||||
|
||||
@@ -92,6 +92,7 @@ Heartfelt thanks go out to every donor on [Nostr](https://primal.net/p/npub1jagm
|
||||
If you'd like to have your own instance hosted for you please contact [hosting@bitcoinresearchkit.org](mailto:hosting@bitcoinresearchkit.org).
|
||||
|
||||
- 2 separate dedicated servers (1 GB/s each) with different ISPs and Cloudflare integration for enhanced performance and optimal availability
|
||||
- 99.9% SLA
|
||||
- Direct communication for feature requests and support
|
||||
- Updates delivered at your convenience
|
||||
- Optional subdomains: `*.bitcoinresearchkit.org`, `*.kibo.money` and `*.satonomics.xyz`
|
||||
|
||||
@@ -154,6 +154,30 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_range<A, F>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
other: &mut StoredVec<I, A>,
|
||||
mut t: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: StoredType,
|
||||
F: FnMut(I) -> (I, T),
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
(index.to_usize()?..other.len()).try_for_each(|i| {
|
||||
let (i, v) = t(I::from(i));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_transform<A, B, F>(
|
||||
&mut self,
|
||||
max_from: A,
|
||||
|
||||
@@ -120,10 +120,10 @@ impl Vecs {
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, _, starting_indexes, exit| {
|
||||
v.compute_transform(
|
||||
v.compute_range(
|
||||
starting_indexes.height,
|
||||
indexer.mut_vecs().height_to_weight.mut_vec(),
|
||||
|(h, ..)| (h, StoredU32::from(1_u32)),
|
||||
|h| (h, StoredU32::from(1_u32)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
|
||||
@@ -209,8 +209,6 @@ where
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType,
|
||||
T: Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
@@ -295,20 +293,14 @@ where
|
||||
|
||||
if needs_average_sum_or_total {
|
||||
let len = values.len();
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let len = len as f64;
|
||||
let total = values
|
||||
.iter()
|
||||
.map(|v| f64::from(v.clone()))
|
||||
.fold(0.0, |a, b| a + b);
|
||||
let avg = T::from(total / len);
|
||||
let avg = sum.clone() / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_total {
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
@@ -345,8 +337,6 @@ where
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType,
|
||||
T: Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
if self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
@@ -415,14 +405,12 @@ where
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
let len = values.len() as f64;
|
||||
let total = values
|
||||
.into_iter()
|
||||
.map(|v| f64::from(v))
|
||||
.fold(0.0, |a, b| a + b);
|
||||
|
||||
let len = values.len();
|
||||
let total = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
// TODO: Multiply by count then divide by total
|
||||
// Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example)
|
||||
let avg = T::from(total / len);
|
||||
let avg = total / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
@@ -432,6 +420,7 @@ where
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
|
||||
@@ -27,8 +27,7 @@ const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromDateindex<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
|
||||
@@ -4,10 +4,10 @@ use brk_vec::StoredType;
|
||||
|
||||
pub trait ComputedType
|
||||
where
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>,
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord,
|
||||
{
|
||||
}
|
||||
impl<T> ComputedType for T where
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::{fs, ops::Deref, path::Path};
|
||||
|
||||
use brk_core::{
|
||||
Date, Dateindex, Decadeindex, Difficultyepoch, Halvingepoch, Height, Monthindex, Quarterindex,
|
||||
Timestamp, Txindex, Txinindex, Txoutindex, Weekindex, Yearindex,
|
||||
Addressindex, Date, Dateindex, Decadeindex, Difficultyepoch, Emptyindex, Halvingepoch, Height,
|
||||
Monthindex, Multisigindex, Opreturnindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex,
|
||||
P2TRindex, P2WPKHindex, P2WSHindex, Pushonlyindex, Quarterindex, Timestamp, Txindex, Txinindex,
|
||||
Txoutindex, Unknownindex, Weekindex, Yearindex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
@@ -12,6 +14,7 @@ use super::ComputedVec;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub addressindex_to_addressindex: ComputedVec<Addressindex, Addressindex>,
|
||||
pub dateindex_to_date: ComputedVec<Dateindex, Date>,
|
||||
pub dateindex_to_dateindex: ComputedVec<Dateindex, Dateindex>,
|
||||
pub dateindex_to_first_height: ComputedVec<Dateindex, Height>,
|
||||
@@ -27,6 +30,7 @@ pub struct Vecs {
|
||||
pub difficultyepoch_to_first_height: ComputedVec<Difficultyepoch, Height>,
|
||||
pub difficultyepoch_to_last_height: ComputedVec<Difficultyepoch, Height>,
|
||||
pub difficultyepoch_to_timestamp: ComputedVec<Difficultyepoch, Timestamp>,
|
||||
pub emptyindex_to_emptyindex: ComputedVec<Emptyindex, Emptyindex>,
|
||||
pub halvingepoch_to_first_height: ComputedVec<Halvingepoch, Height>,
|
||||
pub halvingepoch_to_halvingepoch: ComputedVec<Halvingepoch, Halvingepoch>,
|
||||
pub halvingepoch_to_last_height: ComputedVec<Halvingepoch, Height>,
|
||||
@@ -45,12 +49,26 @@ pub struct Vecs {
|
||||
pub monthindex_to_quarterindex: ComputedVec<Monthindex, Quarterindex>,
|
||||
pub monthindex_to_timestamp: ComputedVec<Monthindex, Timestamp>,
|
||||
pub monthindex_to_yearindex: ComputedVec<Monthindex, Yearindex>,
|
||||
pub multisigindex_to_multisigindex: ComputedVec<Multisigindex, Multisigindex>,
|
||||
pub opreturnindex_to_opreturnindex: ComputedVec<Opreturnindex, Opreturnindex>,
|
||||
pub p2pk33index_to_p2pk33index: ComputedVec<P2PK33index, P2PK33index>,
|
||||
pub p2pk65index_to_p2pk65index: ComputedVec<P2PK65index, P2PK65index>,
|
||||
pub p2pkhindex_to_p2pkhindex: ComputedVec<P2PKHindex, P2PKHindex>,
|
||||
pub p2shindex_to_p2shindex: ComputedVec<P2SHindex, P2SHindex>,
|
||||
pub p2trindex_to_p2trindex: ComputedVec<P2TRindex, P2TRindex>,
|
||||
pub p2wpkhindex_to_p2wpkhindex: ComputedVec<P2WPKHindex, P2WPKHindex>,
|
||||
pub p2wshindex_to_p2wshindex: ComputedVec<P2WSHindex, P2WSHindex>,
|
||||
pub pushonlyindex_to_pushonlyindex: ComputedVec<Pushonlyindex, Pushonlyindex>,
|
||||
pub quarterindex_to_first_monthindex: ComputedVec<Quarterindex, Monthindex>,
|
||||
pub quarterindex_to_last_monthindex: ComputedVec<Quarterindex, Monthindex>,
|
||||
pub quarterindex_to_quarterindex: ComputedVec<Quarterindex, Quarterindex>,
|
||||
pub quarterindex_to_timestamp: ComputedVec<Quarterindex, Timestamp>,
|
||||
pub txindex_to_last_txinindex: ComputedVec<Txindex, Txinindex>,
|
||||
pub txindex_to_last_txoutindex: ComputedVec<Txindex, Txoutindex>,
|
||||
pub txindex_to_txindex: ComputedVec<Txindex, Txindex>,
|
||||
pub txinindex_to_txinindex: ComputedVec<Txinindex, Txinindex>,
|
||||
pub txoutindex_to_txoutindex: ComputedVec<Txoutindex, Txoutindex>,
|
||||
pub unknownindex_to_unknownindex: ComputedVec<Unknownindex, Unknownindex>,
|
||||
pub weekindex_to_first_dateindex: ComputedVec<Weekindex, Dateindex>,
|
||||
pub weekindex_to_last_dateindex: ComputedVec<Weekindex, Dateindex>,
|
||||
pub weekindex_to_timestamp: ComputedVec<Weekindex, Timestamp>,
|
||||
@@ -307,6 +325,86 @@ impl Vecs {
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk33index_to_p2pk33index: ComputedVec::forced_import(
|
||||
&path.join("p2pk33index_to_p2pk33index"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk65index_to_p2pk65index: ComputedVec::forced_import(
|
||||
&path.join("p2pk65index_to_p2pk65index"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pkhindex_to_p2pkhindex: ComputedVec::forced_import(
|
||||
&path.join("p2pkhindex_to_p2pkhindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2shindex_to_p2shindex: ComputedVec::forced_import(
|
||||
&path.join("p2shindex_to_p2shindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2trindex_to_p2trindex: ComputedVec::forced_import(
|
||||
&path.join("p2trindex_to_p2trindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2wpkhindex_to_p2wpkhindex: ComputedVec::forced_import(
|
||||
&path.join("p2wpkhindex_to_p2wpkhindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2wshindex_to_p2wshindex: ComputedVec::forced_import(
|
||||
&path.join("p2wshindex_to_p2wshindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txindex: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txinindex_to_txinindex: ComputedVec::forced_import(
|
||||
&path.join("txinindex_to_txinindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
emptyindex_to_emptyindex: ComputedVec::forced_import(
|
||||
&path.join("emptyindex_to_emptyindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
multisigindex_to_multisigindex: ComputedVec::forced_import(
|
||||
&path.join("multisigindex_to_multisigindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
opreturnindex_to_opreturnindex: ComputedVec::forced_import(
|
||||
&path.join("opreturnindex_to_opreturnindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
pushonlyindex_to_pushonlyindex: ComputedVec::forced_import(
|
||||
&path.join("pushonlyindex_to_pushonlyindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
unknownindex_to_unknownindex: ComputedVec::forced_import(
|
||||
&path.join("unknownindex_to_unknownindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
addressindex_to_addressindex: ComputedVec::forced_import(
|
||||
&path.join("addressindex_to_addressindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txoutindex_to_txoutindex: ComputedVec::forced_import(
|
||||
&path.join("txoutindex_to_txoutindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -323,10 +421,10 @@ impl Vecs {
|
||||
let txinindexes_count = indexer_vecs.txinindex_to_txoutindex.len();
|
||||
let txoutindexes_count = indexer_vecs.txoutindex_to_addressindex.len();
|
||||
|
||||
self.height_to_height.compute_transform(
|
||||
self.height_to_height.compute_range(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
|(h, ..)| (h, h),
|
||||
|h| (h, h),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -340,12 +438,12 @@ impl Vecs {
|
||||
self.height_to_fixed_timestamp.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
|(h, d, s, ..)| {
|
||||
let d = h
|
||||
|(h, timestamp, s, ..)| {
|
||||
let timestamp = h
|
||||
.decremented()
|
||||
.and_then(|h| s.unwrap_cached_get(h))
|
||||
.map_or(d, |prev_d| prev_d.max(d));
|
||||
(h, d)
|
||||
.map_or(timestamp, |prev_d| prev_d.max(timestamp));
|
||||
(h, timestamp)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
@@ -397,17 +495,17 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_to_dateindex.compute_transform(
|
||||
self.dateindex_to_dateindex.compute_range(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_first_height.mut_vec(),
|
||||
|(di, ..)| (di, di),
|
||||
|di| (di, di),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_to_date.compute_transform(
|
||||
self.dateindex_to_date.compute_range(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_dateindex.mut_vec(),
|
||||
|(di, ..)| (di, Date::from(di)),
|
||||
|di| (di, Date::from(di)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -448,10 +546,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(starting_dateindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.dateindex_to_weekindex.compute_transform(
|
||||
self.dateindex_to_weekindex.compute_range(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_dateindex.mut_vec(),
|
||||
|(di, ..)| (di, Weekindex::from(di)),
|
||||
|di| (di, Weekindex::from(di)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -470,10 +568,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex_to_weekindex.compute_transform(
|
||||
self.weekindex_to_weekindex.compute_range(
|
||||
starting_weekindex,
|
||||
self.weekindex_to_first_dateindex.mut_vec(),
|
||||
|(wi, ..)| (wi, wi),
|
||||
|wi| (wi, wi),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -491,10 +589,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(starting_dateindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.dateindex_to_monthindex.compute_transform(
|
||||
self.dateindex_to_monthindex.compute_range(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_dateindex.mut_vec(),
|
||||
|(di, ..)| (di, Monthindex::from(di)),
|
||||
|di| (di, Monthindex::from(di)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -515,10 +613,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex_to_monthindex.compute_transform(
|
||||
self.monthindex_to_monthindex.compute_range(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_first_dateindex.mut_vec(),
|
||||
|(mi, ..)| (mi, mi),
|
||||
|mi| (mi, mi),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -536,10 +634,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_quarterindex.compute_transform(
|
||||
self.monthindex_to_quarterindex.compute_range(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_monthindex.mut_vec(),
|
||||
|(mi, ..)| (mi, Quarterindex::from(mi)),
|
||||
|mi| (mi, Quarterindex::from(mi)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -560,10 +658,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex_to_quarterindex.compute_transform(
|
||||
self.quarterindex_to_quarterindex.compute_range(
|
||||
starting_quarterindex,
|
||||
self.quarterindex_to_first_monthindex.mut_vec(),
|
||||
|(yi, ..)| (yi, yi),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -581,10 +679,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_yearindex.compute_transform(
|
||||
self.monthindex_to_yearindex.compute_range(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_monthindex.mut_vec(),
|
||||
|(mi, ..)| (mi, Yearindex::from(mi)),
|
||||
|i| (i, Yearindex::from(i)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -605,10 +703,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex_to_yearindex.compute_transform(
|
||||
self.yearindex_to_yearindex.compute_range(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_first_monthindex.mut_vec(),
|
||||
|(yi, ..)| (yi, yi),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -626,10 +724,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(starting_yearindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.yearindex_to_decadeindex.compute_transform(
|
||||
self.yearindex_to_decadeindex.compute_range(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_yearindex.mut_vec(),
|
||||
|(yi, ..)| (yi, Decadeindex::from(yi)),
|
||||
|i| (i, Decadeindex::from(i)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -648,10 +746,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex_to_decadeindex.compute_transform(
|
||||
self.decadeindex_to_decadeindex.compute_range(
|
||||
starting_decadeindex,
|
||||
self.decadeindex_to_first_yearindex.mut_vec(),
|
||||
|(di, ..)| (di, di),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -669,10 +767,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_difficultyepoch.compute_transform(
|
||||
self.height_to_difficultyepoch.compute_range(
|
||||
starting_indexes.height,
|
||||
self.height_to_height.mut_vec(),
|
||||
|(h, ..)| (h, Difficultyepoch::from(h)),
|
||||
|h| (h, Difficultyepoch::from(h)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -691,10 +789,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch_to_difficultyepoch.compute_transform(
|
||||
self.difficultyepoch_to_difficultyepoch.compute_range(
|
||||
starting_difficultyepoch,
|
||||
self.difficultyepoch_to_first_height.mut_vec(),
|
||||
|(de, ..)| (de, de),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -717,10 +815,10 @@ impl Vecs {
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_halvingepoch.compute_transform(
|
||||
self.height_to_halvingepoch.compute_range(
|
||||
starting_indexes.height,
|
||||
self.height_to_height.mut_vec(),
|
||||
|(h, ..)| (h, Halvingepoch::from(h)),
|
||||
|h| (h, Halvingepoch::from(h)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -739,10 +837,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.halvingepoch_to_halvingepoch.compute_transform(
|
||||
self.halvingepoch_to_halvingepoch.compute_range(
|
||||
starting_halvingepoch,
|
||||
self.halvingepoch_to_first_height.mut_vec(),
|
||||
|(he, ..)| (he, he),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -758,6 +856,105 @@ impl Vecs {
|
||||
// exit,
|
||||
// )?;
|
||||
|
||||
// ---
|
||||
|
||||
self.addressindex_to_addressindex.compute_range(
|
||||
starting_indexes.addressindex,
|
||||
indexer_vecs.addressindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.txoutindex_to_txoutindex.compute_range(
|
||||
starting_indexes.txoutindex,
|
||||
indexer_vecs.txoutindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2pk33index_to_p2pk33index.compute_range(
|
||||
starting_indexes.p2pk33index,
|
||||
indexer_vecs.p2pk33index_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2pk65index_to_p2pk65index.compute_range(
|
||||
starting_indexes.p2pk65index,
|
||||
indexer_vecs.p2pk65index_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2pkhindex_to_p2pkhindex.compute_range(
|
||||
starting_indexes.p2pkhindex,
|
||||
indexer_vecs.p2pkhindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2shindex_to_p2shindex.compute_range(
|
||||
starting_indexes.p2shindex,
|
||||
indexer_vecs.p2shindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2trindex_to_p2trindex.compute_range(
|
||||
starting_indexes.p2trindex,
|
||||
indexer_vecs.p2trindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2wpkhindex_to_p2wpkhindex.compute_range(
|
||||
starting_indexes.p2wpkhindex,
|
||||
indexer_vecs.p2wpkhindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.p2wshindex_to_p2wshindex.compute_range(
|
||||
starting_indexes.p2wshindex,
|
||||
indexer_vecs.p2wshindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.txindex_to_txindex.compute_range(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.txinindex_to_txinindex.compute_range(
|
||||
starting_indexes.txinindex,
|
||||
indexer_vecs.txinindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.emptyindex_to_emptyindex.compute_range(
|
||||
starting_indexes.emptyindex,
|
||||
indexer_vecs.emptyindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.multisigindex_to_multisigindex.compute_range(
|
||||
starting_indexes.multisigindex,
|
||||
indexer_vecs.multisigindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.opreturnindex_to_opreturnindex.compute_range(
|
||||
starting_indexes.opreturnindex,
|
||||
indexer_vecs.opreturnindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.pushonlyindex_to_pushonlyindex.compute_range(
|
||||
starting_indexes.pushonlyindex,
|
||||
indexer_vecs.pushonlyindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
self.unknownindex_to_unknownindex.compute_range(
|
||||
starting_indexes.unknownindex,
|
||||
indexer_vecs.unknownindex_to_height.mut_vec(),
|
||||
|i| (i, i),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(Indexes {
|
||||
indexes: starting_indexes,
|
||||
dateindex: starting_dateindex,
|
||||
@@ -821,6 +1018,22 @@ impl Vecs {
|
||||
self.quarterindex_to_last_monthindex.any_vec(),
|
||||
self.quarterindex_to_quarterindex.any_vec(),
|
||||
self.quarterindex_to_timestamp.any_vec(),
|
||||
self.p2pk33index_to_p2pk33index.any_vec(),
|
||||
self.p2pk65index_to_p2pk65index.any_vec(),
|
||||
self.p2pkhindex_to_p2pkhindex.any_vec(),
|
||||
self.p2shindex_to_p2shindex.any_vec(),
|
||||
self.p2trindex_to_p2trindex.any_vec(),
|
||||
self.p2wpkhindex_to_p2wpkhindex.any_vec(),
|
||||
self.p2wshindex_to_p2wshindex.any_vec(),
|
||||
self.txindex_to_txindex.any_vec(),
|
||||
self.txinindex_to_txinindex.any_vec(),
|
||||
self.emptyindex_to_emptyindex.any_vec(),
|
||||
self.multisigindex_to_multisigindex.any_vec(),
|
||||
self.opreturnindex_to_opreturnindex.any_vec(),
|
||||
self.pushonlyindex_to_pushonlyindex.any_vec(),
|
||||
self.unknownindex_to_unknownindex.any_vec(),
|
||||
self.addressindex_to_addressindex.any_vec(),
|
||||
self.txoutindex_to_txoutindex.any_vec(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ pub struct Vecs {
|
||||
pub decadeindex_to_ohlc_in_sats: ComputedVec<Decadeindex, OHLCSats>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
const VERSION_IN_SATS: Version = Version::ONE;
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
@@ -87,7 +90,7 @@ impl Vecs {
|
||||
)?,
|
||||
dateindex_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_close_in_cents: ComputedVec::forced_import(
|
||||
@@ -122,7 +125,7 @@ impl Vecs {
|
||||
)?,
|
||||
height_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("height_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_close_in_cents: ComputedVec::forced_import(
|
||||
@@ -176,28 +179,28 @@ impl Vecs {
|
||||
timeindexes_to_open_in_sats: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"open_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
)?,
|
||||
timeindexes_to_high_in_sats: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"high_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_max(),
|
||||
)?,
|
||||
timeindexes_to_low_in_sats: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"low_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_min(),
|
||||
)?,
|
||||
timeindexes_to_close_in_sats: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"close_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
@@ -232,28 +235,28 @@ impl Vecs {
|
||||
chainindexes_to_open_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"open_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
)?,
|
||||
chainindexes_to_high_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"high_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_max(),
|
||||
)?,
|
||||
chainindexes_to_low_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"low_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_min(),
|
||||
)?,
|
||||
chainindexes_to_close_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"close_in_sats",
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
@@ -264,7 +267,7 @@ impl Vecs {
|
||||
)?,
|
||||
weekindex_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_ohlc: ComputedVec::forced_import(
|
||||
@@ -274,7 +277,7 @@ impl Vecs {
|
||||
)?,
|
||||
difficultyepoch_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_ohlc: ComputedVec::forced_import(
|
||||
@@ -284,7 +287,7 @@ impl Vecs {
|
||||
)?,
|
||||
monthindex_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_ohlc: ComputedVec::forced_import(
|
||||
@@ -294,7 +297,7 @@ impl Vecs {
|
||||
)?,
|
||||
quarterindex_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_ohlc: ComputedVec::forced_import(
|
||||
@@ -304,7 +307,7 @@ impl Vecs {
|
||||
)?,
|
||||
yearindex_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
// halvingepoch_to_ohlc: StorableVec::forced_import(&path.join("halvingepoch_to_ohlc"), Version::ZERO, compressed)?,
|
||||
@@ -315,7 +318,7 @@ impl Vecs {
|
||||
)?,
|
||||
decadeindex_to_ohlc_in_sats: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_ohlc_in_sats"),
|
||||
Version::ZERO,
|
||||
VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
|
||||
@@ -23,27 +23,27 @@ pub struct Bitcoin(f64);
|
||||
impl Add for Bitcoin {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
Self::from(Sats::from(self) + Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Bitcoin {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 * rhs.0)
|
||||
Self::from(Sats::from(self) * Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Bitcoin {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
Self::from(Sats::from(self) / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for Bitcoin {
|
||||
fn from(value: Sats) -> Self {
|
||||
Self(u64::from(value) as f64 / (u64::from(Sats::ONE_BTC) as f64))
|
||||
Self(f64::from(value) / (f64::from(Sats::ONE_BTC)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
@@ -43,3 +45,17 @@ impl From<Cents> for u64 {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Cents {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Cents {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ impl From<usize> for Dollars {
|
||||
impl Add for Dollars {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
Self::from(Cents::from(self) + Cents::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Dollars {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
Self::from(Cents::from(self) / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Bitcoin, Dollars, Height};
|
||||
use super::{Bitcoin, Cents, Dollars, Height};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -30,6 +30,7 @@ pub struct Sats(u64);
|
||||
|
||||
impl Sats {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const MAX: Self = Self(u64::MAX);
|
||||
pub const ONE_BTC: Self = Self(100_000_000);
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
@@ -39,8 +40,8 @@ impl Sats {
|
||||
|
||||
impl Add for Sats {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Sats) -> Self::Output {
|
||||
Sats::from(self.0 + rhs.0)
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +94,12 @@ impl Sum for Sats {
|
||||
impl Div<Dollars> for Sats {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Dollars) -> Self::Output {
|
||||
Self((self.0 as f64 / f64::from(rhs)) as u64)
|
||||
let raw_cents = u64::from(Cents::from(rhs));
|
||||
if raw_cents != 0 {
|
||||
Self(self.0 * 100 / raw_cents)
|
||||
} else {
|
||||
Self::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +124,7 @@ impl From<usize> for Sats {
|
||||
|
||||
impl From<f64> for Sats {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as u64)
|
||||
Self(value.round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +147,7 @@ impl From<Sats> for Amount {
|
||||
|
||||
impl From<Bitcoin> for Sats {
|
||||
fn from(value: Bitcoin) -> Self {
|
||||
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)).round() as u64)
|
||||
Self((f64::from(value) * (Sats::ONE_BTC.0 as f64)).round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,3 +64,10 @@ impl Div<usize> for Weight {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Weight> for Weight {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 / rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ color-eyre = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
log = { workspace = true }
|
||||
minreq = { workspace = true }
|
||||
oxc = { version = "0.64.0", features = ["codegen", "minifier"] }
|
||||
oxc = { version = "0.65.0", features = ["codegen", "minifier"] }
|
||||
serde = { workspace = true }
|
||||
tokio = { version = "1.44.2", features = ["full"] }
|
||||
tower-http = { version = "0.6.2", features = ["compression-full", "trace"] }
|
||||
|
||||
@@ -37,9 +37,8 @@
|
||||
line-height: 1.5;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
tab-size: 4;
|
||||
font-family: "Geist mono", ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
font-family: "Geist mono", ui-monospace, SFMono-Regular, Menlo, Monaco,
|
||||
Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-feature-settings: "ss03";
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
@@ -134,6 +133,7 @@
|
||||
letter-spacing: inherit;
|
||||
color: inherit;
|
||||
background: transparent;
|
||||
text-transform: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
@@ -590,7 +590,7 @@
|
||||
> fieldset {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
gap: 1.25rem;
|
||||
|
||||
> label {
|
||||
pointer-events: auto;
|
||||
@@ -626,6 +626,7 @@
|
||||
}
|
||||
|
||||
select {
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
@@ -884,7 +885,7 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
z-index: 20;
|
||||
pointer-events: none;
|
||||
}
|
||||
.shadow-left {
|
||||
@@ -979,7 +980,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
z-index: 20;
|
||||
flex: 1;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
@@ -1607,9 +1607,8 @@
|
||||
</main>
|
||||
<aside id="aside">
|
||||
<div id="charts" hidden></div>
|
||||
<div id="table" hidden></div>
|
||||
<div id="simulation" hidden></div>
|
||||
<div id="live-price" hidden></div>
|
||||
<div id="moscow-time" hidden></div>
|
||||
</aside>
|
||||
<div id="share-div" hidden>
|
||||
<div id="share-content-div">
|
||||
|
||||
@@ -32,6 +32,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
* @param {Colors} args.colors
|
||||
* @param {Index} args.index
|
||||
* @param {Utilities} args.utils
|
||||
* @param {Elements} args.elements
|
||||
* @param {DeepPartial<ChartOptions>} [args.options]
|
||||
*/
|
||||
function createLightweightChart({
|
||||
@@ -40,13 +41,15 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
colors,
|
||||
index,
|
||||
utils,
|
||||
elements,
|
||||
options: _options = {},
|
||||
}) {
|
||||
console.log(elements.style.fontFamily);
|
||||
/** @satisfies {DeepPartial<ChartOptions>} */
|
||||
const options = {
|
||||
autoSize: true,
|
||||
layout: {
|
||||
fontFamily: "Geist mono",
|
||||
fontFamily: elements.style.fontFamily,
|
||||
// fontSize: 13,
|
||||
background: { color: "transparent" },
|
||||
attributionLogo: false,
|
||||
@@ -134,6 +137,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
* @param {Signals} args.signals
|
||||
* @param {Colors} args.colors
|
||||
* @param {Utilities} args.utils
|
||||
* @param {Elements} args.elements
|
||||
* @param {VecsResources} args.vecsResources
|
||||
* @param {Owner | null} [args.owner]
|
||||
* @param {true} [args.fitContentOnResize]
|
||||
@@ -144,6 +148,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
signals,
|
||||
colors,
|
||||
utils,
|
||||
elements,
|
||||
id,
|
||||
vecsResources,
|
||||
owner: _owner,
|
||||
@@ -281,6 +286,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
signals,
|
||||
colors,
|
||||
utils,
|
||||
elements,
|
||||
});
|
||||
|
||||
if (fitContentOnResize) {
|
||||
@@ -366,7 +372,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
this.addPriceScaleSelectorIfNeeded({
|
||||
paneIndex,
|
||||
seriesType: "Candlestick",
|
||||
id,
|
||||
id: `${id}-${paneIndex}`,
|
||||
unit,
|
||||
});
|
||||
|
||||
@@ -449,7 +455,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
this.addPriceScaleSelectorIfNeeded({
|
||||
paneIndex,
|
||||
seriesType: "Line",
|
||||
id,
|
||||
id: `${id}-${paneIndex}`,
|
||||
unit,
|
||||
});
|
||||
|
||||
@@ -532,7 +538,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
this.addPriceScaleSelectorIfNeeded({
|
||||
paneIndex,
|
||||
seriesType: "Baseline",
|
||||
id,
|
||||
id: `${id}-${paneIndex}`,
|
||||
unit,
|
||||
});
|
||||
|
||||
|
||||
@@ -21,11 +21,11 @@ const importSignals = import("./v0.2.4-treeshaked/script.js").then(
|
||||
(compute, effect) => {
|
||||
let dispose = /** @type {VoidFunction | null} */ (null);
|
||||
// @ts-ignore
|
||||
_signals.createEffect(compute, (v) => {
|
||||
_signals.createEffect(compute, (v, oldV) => {
|
||||
dispose?.();
|
||||
signals.createRoot((_dispose) => {
|
||||
dispose = _dispose;
|
||||
effect(v);
|
||||
return effect(v, oldV);
|
||||
});
|
||||
signals.onCleanup(() => dispose?.());
|
||||
});
|
||||
|
||||
@@ -38,6 +38,7 @@ export function init({
|
||||
id: "charts",
|
||||
utils,
|
||||
vecsResources,
|
||||
elements,
|
||||
});
|
||||
|
||||
const index = createIndexSelector({ elements, signals, utils });
|
||||
@@ -57,12 +58,13 @@ export function init({
|
||||
/** @satisfies {Unit} */ ("Sats"),
|
||||
]),
|
||||
signals,
|
||||
sorted: true,
|
||||
});
|
||||
|
||||
signals.createEffect(topUnit, (topUnit) => {
|
||||
const { field: seriesTypeField, selected: topSeriesType } =
|
||||
utils.dom.createHorizontalChoiceField({
|
||||
defaultValue: "Candles",
|
||||
defaultValue: "Line",
|
||||
keyPrefix: "charts",
|
||||
key: "seriestype-0",
|
||||
choices: /** @type {const} */ (["Candles", "Line"]),
|
||||
@@ -80,6 +82,7 @@ export function init({
|
||||
key: "unit-1",
|
||||
choices: bottomUnits,
|
||||
signals,
|
||||
sorted: true,
|
||||
});
|
||||
|
||||
signals.createEffect(bottomUnit, (bottomUnit) => {
|
||||
|
||||
+226
-195
@@ -1,7 +1,7 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, Unit, AnySeriesBlueprint, ChartableIndex } from "./options"
|
||||
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, ChartableIndex } from "./options"
|
||||
* @import {Valued, SingleValueData, CandlestickData, ChartData, OHLCTuple} from "../packages/lightweight-charts/wrapper"
|
||||
* @import * as _ from "../packages/ufuzzy/v1.0.14/types"
|
||||
* @import { createChart as CreateClassicChart, LineStyleOptions, DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, ISeriesApi, Time, LineData, LogicalRange, SeriesType, BaselineStyleOptions, SeriesOptionsCommon, BaselineData, CandlestickStyleOptions } from "../packages/lightweight-charts/v5.0.5-treeshaked/types"
|
||||
@@ -9,7 +9,38 @@
|
||||
* @import {Signal, Signals} from "../packages/solid-signals/types";
|
||||
* @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/owner"
|
||||
* @import { createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo } from "../packages/solid-signals/v0.2.4-treeshaked/types/signals";
|
||||
* @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes, Quarterindex} from "./vecid-to-indexes"
|
||||
* @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes, Quarterindex, Emptyindex, Multisigindex, Opreturnindex, Pushonlyindex, Unknownindex} from "./vecid-to-indexes"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {"" |
|
||||
* "BTC" |
|
||||
* "Cents" |
|
||||
* "Coinblocks" |
|
||||
* "Count" |
|
||||
* "Date" |
|
||||
* "Difficulty" |
|
||||
* "ExaHash / Second" |
|
||||
* "Gigabytes" |
|
||||
* "Hash" |
|
||||
* "Index" |
|
||||
* "mb" |
|
||||
* "%" |
|
||||
* "Ratio" |
|
||||
* "Sats" |
|
||||
* "Seconds" |
|
||||
* "Timestamp" |
|
||||
* "tx" |
|
||||
* "Type" |
|
||||
* "USD / (PetaHash / Second)" |
|
||||
* "USD" |
|
||||
* "Version" |
|
||||
* "WU" |
|
||||
* "Bool" |
|
||||
* "Locktime" |
|
||||
* "sat/vB" |
|
||||
* "vB"
|
||||
* } Unit
|
||||
*/
|
||||
|
||||
function initPackages() {
|
||||
@@ -113,22 +144,6 @@ function createUtils() {
|
||||
if (!element) throw `Element with id = "${id}" should exist`;
|
||||
return element;
|
||||
},
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Elements} elements
|
||||
*/
|
||||
queryOrCreateMetaElement(name, elements) {
|
||||
let meta = /** @type {HTMLMetaElement | null} */ (
|
||||
window.document.querySelector(`meta[name="${name}"]`)
|
||||
);
|
||||
|
||||
if (!meta) {
|
||||
meta = window.document.createElement("meta");
|
||||
meta.name = name;
|
||||
elements.head.appendChild(meta);
|
||||
}
|
||||
return meta;
|
||||
},
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
@@ -206,14 +221,14 @@ function createUtils() {
|
||||
},
|
||||
/**
|
||||
* @param {Object} arg
|
||||
* @param {string} arg.text
|
||||
* @param {string | HTMLElement} arg.inside
|
||||
* @param {string} arg.title
|
||||
* @param {VoidFunction} arg.onClick
|
||||
* @param {(event: MouseEvent) => void} arg.onClick
|
||||
*/
|
||||
createButtonElement({ text, onClick, title }) {
|
||||
createButtonElement({ inside: text, onClick, title }) {
|
||||
const button = window.document.createElement("button");
|
||||
|
||||
button.innerHTML = text;
|
||||
button.append(text);
|
||||
|
||||
button.title = title;
|
||||
|
||||
@@ -330,17 +345,23 @@ function createUtils() {
|
||||
* @param {T} args.choices
|
||||
* @param {string} [args.keyPrefix]
|
||||
* @param {string} args.key
|
||||
* @param {boolean} [args.sorted]
|
||||
* @param {{createEffect: CreateEffect, createSignal: Signals["createSignal"]}} args.signals
|
||||
*/
|
||||
createHorizontalChoiceField({
|
||||
title,
|
||||
id,
|
||||
choices,
|
||||
choices: unsortedChoices,
|
||||
defaultValue,
|
||||
keyPrefix,
|
||||
key,
|
||||
signals,
|
||||
sorted,
|
||||
}) {
|
||||
const choices = sorted
|
||||
? /** @type {T} */ (/** @type {any} */ (unsortedChoices.toSorted()))
|
||||
: unsortedChoices;
|
||||
|
||||
/** @type {Signal<T[number]>} */
|
||||
const selected = signals.createSignal(defaultValue, {
|
||||
save: {
|
||||
@@ -349,6 +370,9 @@ function createUtils() {
|
||||
key,
|
||||
},
|
||||
});
|
||||
if (!choices.includes(selected())) {
|
||||
selected.set(() => defaultValue);
|
||||
}
|
||||
|
||||
const field = window.document.createElement("div");
|
||||
field.classList.add("field");
|
||||
@@ -395,128 +419,6 @@ function createUtils() {
|
||||
|
||||
return { field, selected };
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} args.title
|
||||
* @param {string} args.placeholder
|
||||
* @param {Signal<number | null>} args.signal
|
||||
* @param {number} args.min
|
||||
* @param {number} args.step
|
||||
* @param {number} [args.max]
|
||||
* @param {{createEffect: typeof CreateEffect}} args.signals
|
||||
*/
|
||||
createInputNumberElement({
|
||||
id,
|
||||
title,
|
||||
signal,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
placeholder,
|
||||
signals,
|
||||
}) {
|
||||
const input = window.document.createElement("input");
|
||||
if (!id || !title || !placeholder) throw Error("input attribute missing");
|
||||
input.id = id;
|
||||
input.title = title;
|
||||
input.placeholder = placeholder;
|
||||
input.type = "number";
|
||||
input.min = String(min);
|
||||
if (max) {
|
||||
input.max = String(max);
|
||||
}
|
||||
input.step = String(step);
|
||||
|
||||
let stateValue = /** @type {string | null} */ (null);
|
||||
|
||||
signals.createEffect(
|
||||
() => {
|
||||
const value = signal();
|
||||
return value ? String(value) : "";
|
||||
},
|
||||
(value) => {
|
||||
if (stateValue !== value) {
|
||||
input.value = value;
|
||||
stateValue = value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
input.addEventListener("input", () => {
|
||||
const valueSer = input.value;
|
||||
stateValue = valueSer;
|
||||
const value = Number(valueSer);
|
||||
if (value >= min && (max ? value <= max : true)) {
|
||||
signal.set(value);
|
||||
}
|
||||
});
|
||||
|
||||
return { input, signal };
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} args.title
|
||||
* @param {Signal<number | null>} args.signal
|
||||
* @param {{createEffect: typeof CreateEffect}} args.signals
|
||||
*/
|
||||
createInputDollar({ id, title, signal, signals }) {
|
||||
return this.createInputNumberElement({
|
||||
id,
|
||||
placeholder: "USD",
|
||||
min: 0,
|
||||
title,
|
||||
signal,
|
||||
signals,
|
||||
step: 1,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} args.title
|
||||
* @param {Signal<Date | null>} args.signal
|
||||
* @param {{createEffect: typeof CreateEffect}} args.signals
|
||||
*/
|
||||
createInputDate({ id, title, signal, signals }) {
|
||||
const input = window.document.createElement("input");
|
||||
input.id = id;
|
||||
input.title = title;
|
||||
input.type = "date";
|
||||
const min = "2011-01-01";
|
||||
const minDate = new Date(min);
|
||||
const maxDate = new Date();
|
||||
const max = date.toString(maxDate);
|
||||
input.min = min;
|
||||
input.max = max;
|
||||
|
||||
let stateValue = /** @type {string | null} */ (null);
|
||||
|
||||
signals.createEffect(
|
||||
() => {
|
||||
const dateSignal = signal();
|
||||
return dateSignal ? date.toString(dateSignal) : "";
|
||||
},
|
||||
(value) => {
|
||||
if (stateValue !== value) {
|
||||
input.value = value;
|
||||
stateValue = value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
input.addEventListener("change", () => {
|
||||
const value = input.value;
|
||||
const date = new Date(value);
|
||||
if (date >= minDate && date <= maxDate) {
|
||||
stateValue = value;
|
||||
signal.set(value ? date : null);
|
||||
}
|
||||
});
|
||||
|
||||
return { input, signal };
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {1 | 2 | 3} [args.level]
|
||||
@@ -536,46 +438,64 @@ function createUtils() {
|
||||
};
|
||||
},
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} param0.name
|
||||
* @param {string} param0.value
|
||||
* @template {string} Name
|
||||
* @template {string} Value
|
||||
* @template {Value | {name: Name; value: Value}} T
|
||||
* @param {T} arg
|
||||
*/
|
||||
createOption({ name, value }) {
|
||||
createOption(arg) {
|
||||
const option = window.document.createElement("option");
|
||||
option.value = value;
|
||||
option.innerText = name;
|
||||
if (typeof arg === "object") {
|
||||
option.value = arg.value;
|
||||
option.innerText = arg.name;
|
||||
} else {
|
||||
option.value = arg;
|
||||
option.innerText = arg;
|
||||
}
|
||||
return option;
|
||||
},
|
||||
/**
|
||||
* @template {{name: string; value: string}} T
|
||||
* @param {Object} param0
|
||||
* @param {string} param0.id
|
||||
* @param {(({name: string; value: string} & T) | {name: string; list: ({name: string; value: string} & T)[]})[]} param0.list
|
||||
* @param {Signal<T>} param0.signal
|
||||
* @template {string} Name
|
||||
* @template {string} Value
|
||||
* @template {Value | {name: Name; value: Value}} T
|
||||
* @param {Object} args
|
||||
* @param {string} [args.id]
|
||||
* @param {boolean} [args.deep]
|
||||
* @param {readonly ((T) | {name: string; list: T[]})[]} args.list
|
||||
* @param {Signal<T>} args.signal
|
||||
*/
|
||||
createSelect({ id, list, signal }) {
|
||||
createSelect({ id, list, signal, deep = false }) {
|
||||
const select = window.document.createElement("select");
|
||||
select.name = id;
|
||||
select.id = id;
|
||||
|
||||
if (id) {
|
||||
select.name = id;
|
||||
select.id = id;
|
||||
}
|
||||
|
||||
/** @type {Record<string, VoidFunction>} */
|
||||
const setters = {};
|
||||
|
||||
list.forEach((anyOption, index) => {
|
||||
if ("list" in anyOption) {
|
||||
if (typeof anyOption === "object" && "list" in anyOption) {
|
||||
const { name, list } = anyOption;
|
||||
const optGroup = window.document.createElement("optgroup");
|
||||
optGroup.label = name;
|
||||
select.append(optGroup);
|
||||
list.forEach((option) => {
|
||||
optGroup.append(this.createOption(option));
|
||||
setters[option.value] = () => signal.set(() => option);
|
||||
const key = /** @type {string} */ (
|
||||
typeof option === "object" ? option.value : option
|
||||
);
|
||||
setters[key] = () => signal.set(() => option);
|
||||
});
|
||||
} else {
|
||||
select.append(this.createOption(anyOption));
|
||||
setters[anyOption.value] = () => signal.set(() => anyOption);
|
||||
const key = /** @type {string} */ (
|
||||
typeof anyOption === "object" ? anyOption.value : anyOption
|
||||
);
|
||||
setters[key] = () => signal.set(() => anyOption);
|
||||
}
|
||||
if (index !== list.length - 1) {
|
||||
if (deep && index !== list.length - 1) {
|
||||
select.append(window.document.createElement("hr"));
|
||||
}
|
||||
});
|
||||
@@ -588,34 +508,13 @@ function createUtils() {
|
||||
}
|
||||
});
|
||||
|
||||
select.value = signal().value;
|
||||
const initialSignal = signal();
|
||||
const initialValue =
|
||||
typeof initialSignal === "object" ? initialSignal.value : initialSignal;
|
||||
select.value = String(initialValue);
|
||||
|
||||
return { select, signal };
|
||||
},
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {Signal<any>} param0.signal
|
||||
* @param {HTMLInputElement} [param0.input]
|
||||
* @param {HTMLSelectElement} [param0.select]
|
||||
*/
|
||||
createResetableInput({ input, select, signal }) {
|
||||
const div = window.document.createElement("div");
|
||||
|
||||
const element = input || select;
|
||||
if (!element) throw "createResetableField element missing";
|
||||
div.append(element);
|
||||
|
||||
const button = this.createButtonElement({
|
||||
onClick: signal.reset,
|
||||
text: "Reset",
|
||||
title: "Reset field",
|
||||
});
|
||||
button.type = "reset";
|
||||
|
||||
div.append(button);
|
||||
|
||||
return div;
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.title
|
||||
@@ -777,6 +676,79 @@ function createUtils() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VecId} id
|
||||
*/
|
||||
function vecidToUnit(id) {
|
||||
/** @type {Unit} */
|
||||
let unit;
|
||||
if (id.includes("index") || id.includes("height") || id.includes("epoch")) {
|
||||
unit = "Index";
|
||||
} else if (id.includes("type")) {
|
||||
unit = "Type";
|
||||
} else if (id === "locktime") {
|
||||
unit = "Locktime";
|
||||
} else if (id.startsWith("is-")) {
|
||||
unit = "Bool";
|
||||
} else if (
|
||||
id.includes("hash") ||
|
||||
id.includes("address") ||
|
||||
id.includes("txid")
|
||||
) {
|
||||
unit = "Hash";
|
||||
} else if (id.includes("interval")) {
|
||||
unit = "Seconds";
|
||||
} else if (id.includes("feerate")) {
|
||||
unit = "sat/vB";
|
||||
} else if (id.includes("in-cents")) {
|
||||
unit = "Cents";
|
||||
} else if (id.includes("in-usd")) {
|
||||
unit = "USD";
|
||||
} else if (id.includes("in-btc")) {
|
||||
unit = "BTC";
|
||||
} else if (
|
||||
id.includes("in-sats") ||
|
||||
id.startsWith("sats-") ||
|
||||
id.includes("input-value") ||
|
||||
id.includes("output-value") ||
|
||||
id.includes("fee") ||
|
||||
id.includes("coinbase") ||
|
||||
id.includes("subsidy")
|
||||
) {
|
||||
unit = "Sats";
|
||||
} else if (
|
||||
id.includes("open") ||
|
||||
id.includes("high") ||
|
||||
id.includes("low") ||
|
||||
id.includes("close") ||
|
||||
id.includes("ohlc")
|
||||
) {
|
||||
unit = "USD";
|
||||
} else if (id.includes("count") || id.match(/v[1-3]/g)) {
|
||||
unit = "Count";
|
||||
} else if (id.includes("date")) {
|
||||
unit = "Date";
|
||||
} else if (id.includes("timestamp")) {
|
||||
unit = "Timestamp";
|
||||
} else if (id.includes("difficulty")) {
|
||||
unit = "Difficulty";
|
||||
} else if (id.includes("-size")) {
|
||||
unit = "mb";
|
||||
} else if (id.includes("weight")) {
|
||||
unit = "WU";
|
||||
} else if (id.includes("vbytes") || id.includes("vsize")) {
|
||||
unit = "vB";
|
||||
} else if (id.includes("version")) {
|
||||
unit = "Version";
|
||||
} else if (id === "value") {
|
||||
unit = "Sats";
|
||||
} else {
|
||||
console.log();
|
||||
throw Error(`Unit not set for "${id}"`);
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
const locale = {
|
||||
numberToUSFormat,
|
||||
/** @param {number} value */
|
||||
@@ -885,6 +857,20 @@ function createUtils() {
|
||||
return v;
|
||||
},
|
||||
},
|
||||
vecIds: {
|
||||
/**
|
||||
* @param {VecId[]} v
|
||||
*/
|
||||
serialize(v) {
|
||||
return v.join(",");
|
||||
},
|
||||
/**
|
||||
* @param {string} v
|
||||
*/
|
||||
deserialize(v) {
|
||||
return /** @type {VecId[]} */ (v.split(","));
|
||||
},
|
||||
},
|
||||
number: {
|
||||
/**
|
||||
* @param {number} v
|
||||
@@ -1289,6 +1275,7 @@ function createUtils() {
|
||||
runWhenIdle,
|
||||
getNumberOfDaysBetweenTwoDates,
|
||||
stringToId,
|
||||
vecidToUnit,
|
||||
};
|
||||
}
|
||||
/** @typedef {ReturnType<typeof createUtils>} Utilities */
|
||||
@@ -1318,7 +1305,16 @@ function createVecsResources(signals, utils) {
|
||||
return {
|
||||
url: utils.api.genUrl(index, id, from),
|
||||
fetched,
|
||||
async fetch() {
|
||||
/**
|
||||
* Defaults
|
||||
* - from: -10_000
|
||||
* - to: undefined
|
||||
*
|
||||
* @param {Object} [args]
|
||||
* @param {number} [args.from]
|
||||
* @param {number} [args.to]
|
||||
*/
|
||||
async fetch(args) {
|
||||
if (loading) return fetched();
|
||||
if (at) {
|
||||
const diff = new Date().getTime() - at.getTime();
|
||||
@@ -1333,7 +1329,8 @@ function createVecsResources(signals, utils) {
|
||||
},
|
||||
index,
|
||||
id,
|
||||
from,
|
||||
args?.from ?? from,
|
||||
args?.to,
|
||||
)
|
||||
);
|
||||
at = new Date();
|
||||
@@ -1426,6 +1423,7 @@ function getElements() {
|
||||
selectors: getElementById("frame-selectors"),
|
||||
style: getComputedStyle(window.document.documentElement),
|
||||
charts: getElementById("charts"),
|
||||
table: getElementById("table"),
|
||||
simulation: getElementById("simulation"),
|
||||
};
|
||||
}
|
||||
@@ -1911,6 +1909,12 @@ function main() {
|
||||
optionsPromise.then(async ({ initOptions }) => {
|
||||
const vecIdToIndexes = createVecIdToIndexes();
|
||||
|
||||
if (env.localhost) {
|
||||
Object.keys(vecIdToIndexes).forEach((id) => {
|
||||
utils.vecidToUnit(/** @type {VecId} */ (id));
|
||||
});
|
||||
}
|
||||
|
||||
function initDark() {
|
||||
const preferredColorSchemeMatchMedia = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
@@ -1994,7 +1998,8 @@ function main() {
|
||||
undefined
|
||||
);
|
||||
let firstTimeLoadingChart = true;
|
||||
let firstTimeLoadingSim = true;
|
||||
let firstTimeLoadingTable = true;
|
||||
let firstTimeLoadingSimulation = true;
|
||||
|
||||
signals.createEffect(options.selected, (option) => {
|
||||
if (previousElement) {
|
||||
@@ -2027,7 +2032,9 @@ function main() {
|
||||
colors,
|
||||
elements,
|
||||
lightweightCharts,
|
||||
selected: /** @type {any} */ (lastChartOption),
|
||||
selected: /** @type {Accessor<ChartOption>} */ (
|
||||
lastChartOption
|
||||
),
|
||||
signals,
|
||||
utils,
|
||||
webSockets,
|
||||
@@ -2043,15 +2050,39 @@ function main() {
|
||||
|
||||
break;
|
||||
}
|
||||
case "table": {
|
||||
element = elements.table;
|
||||
|
||||
if (firstTimeLoadingTable) {
|
||||
const tableScript = import("./table.js");
|
||||
utils.dom.importStyleAndThen("/styles/table.css", () =>
|
||||
tableScript.then(({ init }) =>
|
||||
signals.runWithOwner(owner, () =>
|
||||
init({
|
||||
colors,
|
||||
elements,
|
||||
signals,
|
||||
utils,
|
||||
vecsResources,
|
||||
option,
|
||||
vecIdToIndexes,
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
firstTimeLoadingTable = false;
|
||||
|
||||
break;
|
||||
}
|
||||
case "simulation": {
|
||||
element = elements.simulation;
|
||||
|
||||
lastSimulationOption.set(option);
|
||||
|
||||
if (firstTimeLoadingSim) {
|
||||
if (firstTimeLoadingSimulation) {
|
||||
const lightweightCharts = packages.lightweightCharts();
|
||||
const simulationScript = import("./simulation.js");
|
||||
|
||||
utils.dom.importStyleAndThen(
|
||||
"/styles/simulation.css",
|
||||
() =>
|
||||
@@ -2071,7 +2102,7 @@ function main() {
|
||||
),
|
||||
);
|
||||
}
|
||||
firstTimeLoadingSim = false;
|
||||
firstTimeLoadingSimulation = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,28 +12,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {"" |
|
||||
* "BTC" |
|
||||
* "Coinblocks" |
|
||||
* "Count" |
|
||||
* "Date" |
|
||||
* "USD / (PetaHash / Second)" |
|
||||
* "ExaHash / Second" |
|
||||
* "Height" |
|
||||
* "Gigabytes" |
|
||||
* "Megabytes" |
|
||||
* "Percentage" |
|
||||
* "Ratio" |
|
||||
* "Sats" |
|
||||
* "sat/vB" |
|
||||
* "Seconds" |
|
||||
* "Transactions" |
|
||||
* "USD" |
|
||||
* "Version" |
|
||||
* "Virtual Bytes" |
|
||||
* "Weight Units"
|
||||
* } Unit
|
||||
*
|
||||
* @typedef {Object} BaseSeriesBlueprint
|
||||
* @property {string} title
|
||||
* @property {boolean} [defaultActive]
|
||||
@@ -85,6 +63,14 @@
|
||||
*
|
||||
* @typedef {Required<Omit<PartialChartOption, "top" | "bottom">> & ProcessedChartOptionAddons & ProcessedOptionAddons} ChartOption
|
||||
*
|
||||
* @typedef {Object} PartialTableOptionSpecific
|
||||
* @property {"table"} kind
|
||||
* @property {string} title
|
||||
*
|
||||
* @typedef {PartialOption & PartialTableOptionSpecific} PartialTableOption
|
||||
*
|
||||
* @typedef {Required<PartialTableOption> & ProcessedOptionAddons} TableOption
|
||||
*
|
||||
* @typedef {Object} PartialSimulationOptionSpecific
|
||||
* @property {"simulation"} kind
|
||||
* @property {string} title
|
||||
@@ -102,9 +88,9 @@
|
||||
*
|
||||
* @typedef {Required<PartialUrlOption> & ProcessedOptionAddons} UrlOption
|
||||
*
|
||||
* @typedef {PartialChartOption | PartialSimulationOption | PartialUrlOption} AnyPartialOption
|
||||
* @typedef {PartialChartOption | PartialTableOption | PartialSimulationOption | PartialUrlOption} AnyPartialOption
|
||||
*
|
||||
* @typedef {ChartOption | SimulationOption | UrlOption} Option
|
||||
* @typedef {ChartOption | TableOption | SimulationOption | UrlOption} Option
|
||||
*
|
||||
* @typedef {Object} PartialOptionsGroup
|
||||
* @property {string} name
|
||||
@@ -201,17 +187,18 @@ function createPartialOptions(colors) {
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecIdSumBase & TotalVecIdBase} args.concat
|
||||
* @param {string} [args.name]
|
||||
*/
|
||||
function createSumTotalSeries({ concat }) {
|
||||
function createSumTotalSeries({ concat, name }) {
|
||||
return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([
|
||||
{
|
||||
key: `${concat}-sum`,
|
||||
title: "Sum",
|
||||
title: name ? `${name} Sum` : "Sum",
|
||||
color: colors.bitcoin,
|
||||
},
|
||||
{
|
||||
key: `total-${concat}`,
|
||||
title: "Total",
|
||||
title: name ? `Total ${name}` : "Total",
|
||||
color: colors.offBitcoin,
|
||||
defaultActive: false,
|
||||
},
|
||||
@@ -224,6 +211,18 @@ function createPartialOptions(colors) {
|
||||
*/
|
||||
function createMinMaxPercentilesSeries({ concat }) {
|
||||
return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([
|
||||
{
|
||||
key: `${concat}-max`,
|
||||
title: "Max",
|
||||
color: colors.pink,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
key: `${concat}-min`,
|
||||
title: "Min",
|
||||
color: colors.green,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
key: `${concat}-median`,
|
||||
title: "Median",
|
||||
@@ -254,21 +253,20 @@ function createPartialOptions(colors) {
|
||||
color: colors.lime,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
key: `${concat}-max`,
|
||||
title: "Max",
|
||||
color: colors.pink,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
key: `${concat}-min`,
|
||||
title: "Min",
|
||||
color: colors.green,
|
||||
defaultActive: false,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VecIdAverageBase & VecIdSumBase & TotalVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
|
||||
*/
|
||||
function createAverageSumTotalMinMaxPercentilesSeries(key) {
|
||||
return [
|
||||
createAverageSeries({ concat: key }),
|
||||
...createSumTotalSeries({ concat: key }),
|
||||
...createMinMaxPercentilesSeries({ concat: key }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {ChartableVecId & VecIdAverageBase & VecIdSumBase & TotalVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.key
|
||||
@@ -280,9 +278,7 @@ function createPartialOptions(colors) {
|
||||
key,
|
||||
name,
|
||||
}),
|
||||
createAverageSeries({ concat: key }),
|
||||
...createSumTotalSeries({ concat: key }),
|
||||
...createMinMaxPercentilesSeries({ concat: key }),
|
||||
...createAverageSumTotalMinMaxPercentilesSeries(key),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -363,17 +359,10 @@ function createPartialOptions(colors) {
|
||||
{
|
||||
name: "Count",
|
||||
title: "Transaction Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-count",
|
||||
name: "Count",
|
||||
}),
|
||||
createAverageSeries({ concat: "tx-count" }),
|
||||
...createSumTotalSeries({ concat: "tx-count" }),
|
||||
...createMinMaxPercentilesSeries({
|
||||
concat: "tx-count",
|
||||
}),
|
||||
],
|
||||
bottom: createBaseAverageSumTotalMinMaxPercentilesSeries({
|
||||
key: "tx-count",
|
||||
name: "Count",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Subsidy",
|
||||
@@ -415,9 +404,9 @@ function createPartialOptions(colors) {
|
||||
name: "Fee",
|
||||
title: "Transaction Fee",
|
||||
bottom: [
|
||||
createAverageSeries({ concat: "fee" }),
|
||||
...createSumTotalSeries({ concat: "fee" }),
|
||||
...createMinMaxPercentilesSeries({ concat: "fee" }),
|
||||
...createAverageSumTotalMinMaxPercentilesSeries("fee"),
|
||||
...createAverageSumTotalMinMaxPercentilesSeries("fee-in-btc"),
|
||||
...createAverageSumTotalMinMaxPercentilesSeries("fee-in-usd"),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -451,41 +440,42 @@ function createPartialOptions(colors) {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Version",
|
||||
tree: [
|
||||
{
|
||||
name: "1",
|
||||
title: "Transaction V1 Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v1",
|
||||
name: "Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v1" }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "2",
|
||||
title: "Transaction V2 Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v2",
|
||||
name: "Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v2" }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "3",
|
||||
title: "Transaction V3 Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v3",
|
||||
name: "Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v3" }),
|
||||
],
|
||||
},
|
||||
name: "Versions",
|
||||
title: "Transaction Versions",
|
||||
bottom: [
|
||||
// {
|
||||
// name: "1",
|
||||
// title: "Transaction V1 Count",
|
||||
// bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v1",
|
||||
name: "v1 Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v1", name: "v1" }),
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: "2",
|
||||
// title: "Transaction V2 Count",
|
||||
// bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v2",
|
||||
name: "v2 Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v2", name: "v2" }),
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: "3",
|
||||
// title: "Transaction V3 Count",
|
||||
// bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v3",
|
||||
name: "v3 Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v3", name: "v3" }),
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -540,6 +530,11 @@ function createPartialOptions(colors) {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "table",
|
||||
title: "Table",
|
||||
name: "Table",
|
||||
},
|
||||
{
|
||||
name: "Simulations",
|
||||
tree: [
|
||||
@@ -675,41 +670,7 @@ export function initOptions({
|
||||
*/
|
||||
function arrayToRecord(id, arr = []) {
|
||||
return (arr || []).reduce((record, blueprint) => {
|
||||
const key = blueprint.key;
|
||||
/** @type {Unit} */
|
||||
let unit;
|
||||
if (key.includes("interval")) {
|
||||
unit = "Seconds";
|
||||
} else if (key.includes("feerate")) {
|
||||
unit = "sat/vB";
|
||||
} else if (key.includes("in-usd")) {
|
||||
unit = "USD";
|
||||
} else if (key.includes("in-btc")) {
|
||||
unit = "BTC";
|
||||
} else if (
|
||||
key.includes("-in-sats") ||
|
||||
key.startsWith("sats-") ||
|
||||
key.includes("input-value") ||
|
||||
key.includes("output-value") ||
|
||||
key.includes("fee") ||
|
||||
key.includes("coinbase") ||
|
||||
key.includes("subsidy")
|
||||
) {
|
||||
unit = "Sats";
|
||||
} else if (key.includes("count")) {
|
||||
unit = "Count";
|
||||
} else if (key.includes("-size")) {
|
||||
unit = "Megabytes";
|
||||
} else if (key.includes("weight")) {
|
||||
unit = "Weight Units";
|
||||
} else if (key.includes("vbytes") || key.includes("vsize")) {
|
||||
unit = "Virtual Bytes";
|
||||
} else if (key.match(/v[1-3]/g)) {
|
||||
unit = "Version";
|
||||
} else {
|
||||
console.log([id, key]);
|
||||
throw Error("Unit not set");
|
||||
}
|
||||
const unit = utils.vecidToUnit(blueprint.key);
|
||||
record[unit] ??= [];
|
||||
record[unit].push(blueprint);
|
||||
return record;
|
||||
@@ -731,7 +692,7 @@ export function initOptions({
|
||||
|
||||
if (option.qrcode) {
|
||||
return utils.dom.createButtonElement({
|
||||
text: option.name,
|
||||
inside: option.name,
|
||||
title: option.title,
|
||||
onClick: () => {
|
||||
qrcode.set(option.url);
|
||||
@@ -916,16 +877,17 @@ export function initOptions({
|
||||
/** @type {Option} */
|
||||
let option;
|
||||
|
||||
/** @type {string} */
|
||||
let id;
|
||||
/** @type {Option["kind"]} */
|
||||
let kind;
|
||||
/** @type {string} */
|
||||
let title;
|
||||
|
||||
if ("kind" in anyPartial && anyPartial.kind === "simulation") {
|
||||
if ("kind" in anyPartial && anyPartial.kind === "table") {
|
||||
option = /** @satisfies {TableOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
id: anyPartial.kind,
|
||||
name: anyPartial.name,
|
||||
path: path || [],
|
||||
title: anyPartial.title,
|
||||
});
|
||||
} else if ("kind" in anyPartial && anyPartial.kind === "simulation") {
|
||||
option = /** @satisfies {SimulationOption} */ ({
|
||||
kind: "simulation",
|
||||
kind: anyPartial.kind,
|
||||
id: anyPartial.kind,
|
||||
name: anyPartial.name,
|
||||
path: path || [],
|
||||
|
||||
@@ -30,6 +30,155 @@ export function init({
|
||||
|
||||
const simulationElement = elements.simulation;
|
||||
|
||||
const dom = {
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} args.title
|
||||
* @param {string} args.placeholder
|
||||
* @param {Signal<number | null>} args.signal
|
||||
* @param {number} args.min
|
||||
* @param {number} args.step
|
||||
* @param {number} [args.max]
|
||||
* @param {{createEffect: typeof CreateEffect}} args.signals
|
||||
*/
|
||||
createInputNumberElement({
|
||||
id,
|
||||
title,
|
||||
signal,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
placeholder,
|
||||
signals,
|
||||
}) {
|
||||
const input = window.document.createElement("input");
|
||||
if (!id || !title || !placeholder) throw Error("input attribute missing");
|
||||
input.id = id;
|
||||
input.title = title;
|
||||
input.placeholder = placeholder;
|
||||
input.type = "number";
|
||||
input.min = String(min);
|
||||
if (max) {
|
||||
input.max = String(max);
|
||||
}
|
||||
input.step = String(step);
|
||||
|
||||
let stateValue = /** @type {string | null} */ (null);
|
||||
|
||||
signals.createEffect(
|
||||
() => {
|
||||
const value = signal();
|
||||
return value ? String(value) : "";
|
||||
},
|
||||
(value) => {
|
||||
if (stateValue !== value) {
|
||||
input.value = value;
|
||||
stateValue = value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
input.addEventListener("input", () => {
|
||||
const valueSer = input.value;
|
||||
stateValue = valueSer;
|
||||
const value = Number(valueSer);
|
||||
if (value >= min && (max ? value <= max : true)) {
|
||||
signal.set(value);
|
||||
}
|
||||
});
|
||||
|
||||
return { input, signal };
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} args.title
|
||||
* @param {Signal<number | null>} args.signal
|
||||
* @param {{createEffect: typeof CreateEffect}} args.signals
|
||||
*/
|
||||
createInputDollar({ id, title, signal, signals }) {
|
||||
return this.createInputNumberElement({
|
||||
id,
|
||||
placeholder: "USD",
|
||||
min: 0,
|
||||
title,
|
||||
signal,
|
||||
signals,
|
||||
step: 1,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} args.title
|
||||
* @param {Signal<Date | null>} args.signal
|
||||
* @param {{createEffect: typeof CreateEffect}} args.signals
|
||||
*/
|
||||
createInputDate({ id, title, signal, signals }) {
|
||||
const input = window.document.createElement("input");
|
||||
input.id = id;
|
||||
input.title = title;
|
||||
input.type = "date";
|
||||
const min = "2011-01-01";
|
||||
const minDate = new Date(min);
|
||||
const maxDate = new Date();
|
||||
const max = utils.date.toString(maxDate);
|
||||
input.min = min;
|
||||
input.max = max;
|
||||
|
||||
let stateValue = /** @type {string | null} */ (null);
|
||||
|
||||
signals.createEffect(
|
||||
() => {
|
||||
const dateSignal = signal();
|
||||
return dateSignal ? utils.date.toString(dateSignal) : "";
|
||||
},
|
||||
(value) => {
|
||||
if (stateValue !== value) {
|
||||
input.value = value;
|
||||
stateValue = value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
input.addEventListener("change", () => {
|
||||
const value = input.value;
|
||||
const date = new Date(value);
|
||||
if (date >= minDate && date <= maxDate) {
|
||||
stateValue = value;
|
||||
signal.set(value ? date : null);
|
||||
}
|
||||
});
|
||||
|
||||
return { input, signal };
|
||||
},
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {Signal<any>} param0.signal
|
||||
* @param {HTMLInputElement} [param0.input]
|
||||
* @param {HTMLSelectElement} [param0.select]
|
||||
*/
|
||||
createResetableInput({ input, select, signal }) {
|
||||
const div = window.document.createElement("div");
|
||||
|
||||
const element = input || select;
|
||||
if (!element) throw "createResetableField element missing";
|
||||
div.append(element);
|
||||
|
||||
const button = utils.dom.createButtonElement({
|
||||
onClick: signal.reset,
|
||||
inside: "Reset",
|
||||
title: "Reset field",
|
||||
});
|
||||
button.type = "reset";
|
||||
|
||||
div.append(button);
|
||||
|
||||
return div;
|
||||
},
|
||||
};
|
||||
|
||||
const parametersElement = window.document.createElement("div");
|
||||
simulationElement.append(parametersElement);
|
||||
const resultsElement = window.document.createElement("div");
|
||||
@@ -276,8 +425,8 @@ export function init({
|
||||
}),
|
||||
description:
|
||||
"The amount of dollars you have ready on the exchange on day one.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputDollar({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputDollar({
|
||||
id: "simulation-dollars-initial",
|
||||
title: "Initial Dollar Amount",
|
||||
signal: settings.dollars.initial.amount,
|
||||
@@ -296,11 +445,12 @@ export function init({
|
||||
}),
|
||||
description:
|
||||
"The frequency at which you'll top up your account at the exchange.",
|
||||
input: utils.dom.createResetableInput(
|
||||
input: dom.createResetableInput(
|
||||
utils.dom.createSelect({
|
||||
id: "top-up-frequency",
|
||||
list: frequencies.list,
|
||||
signal: settings.dollars.topUp.frenquency,
|
||||
deep: true,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
@@ -315,8 +465,8 @@ export function init({
|
||||
}),
|
||||
description:
|
||||
"The recurrent amount of dollars you'll be transfering to said exchange.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputDollar({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputDollar({
|
||||
id: "simulation-dollars-top-up-amount",
|
||||
title: "Top Up Dollar Amount",
|
||||
signal: settings.dollars.topUp.amount,
|
||||
@@ -335,8 +485,8 @@ export function init({
|
||||
}),
|
||||
description:
|
||||
"The amount, if available, of dollars that will be used to buy Bitcoin on day one.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputDollar({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputDollar({
|
||||
id: "simulation-bitcoin-initial-investment",
|
||||
title: "Initial Swap Amount",
|
||||
signal: settings.bitcoin.investment.initial,
|
||||
@@ -354,11 +504,12 @@ export function init({
|
||||
text: "Investment Frequency",
|
||||
}),
|
||||
description: "The frequency at which you'll be buying Bitcoin.",
|
||||
input: utils.dom.createResetableInput(
|
||||
input: dom.createResetableInput(
|
||||
utils.dom.createSelect({
|
||||
id: "investment-frequency",
|
||||
list: frequencies.list,
|
||||
signal: settings.bitcoin.investment.frequency,
|
||||
deep: true,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
@@ -373,8 +524,8 @@ export function init({
|
||||
}),
|
||||
description:
|
||||
"The recurrent amount, if available, of dollars that will be used to buy Bitcoin.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputDollar({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputDollar({
|
||||
id: "simulation-bitcoin-recurrent-investment",
|
||||
title: "Bitcoin Recurrent Investment",
|
||||
signal: settings.bitcoin.investment.recurrent,
|
||||
@@ -392,8 +543,8 @@ export function init({
|
||||
text: "Start",
|
||||
}),
|
||||
description: "The first day of the simulation.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputDate({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputDate({
|
||||
id: "simulation-inverval-start",
|
||||
title: "First Simulation Date",
|
||||
signal: settings.interval.start,
|
||||
@@ -411,8 +562,8 @@ export function init({
|
||||
text: "End",
|
||||
}),
|
||||
description: "The last day of the simulation.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputDate({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputDate({
|
||||
id: "simulation-inverval-end",
|
||||
title: "Last Simulation Day",
|
||||
signal: settings.interval.end,
|
||||
@@ -430,8 +581,8 @@ export function init({
|
||||
text: "Exchange",
|
||||
}),
|
||||
description: "The amount of trading fees (in %) at the exchange.",
|
||||
input: utils.dom.createResetableInput(
|
||||
utils.dom.createInputNumberElement({
|
||||
input: dom.createResetableInput(
|
||||
dom.createInputNumberElement({
|
||||
id: "simulation-fees",
|
||||
title: "Exchange Fees",
|
||||
signal: settings.fees.percentage,
|
||||
@@ -555,6 +706,7 @@ export function init({
|
||||
fitContentOnResize: true,
|
||||
vecsResources,
|
||||
utils,
|
||||
elements,
|
||||
config: [
|
||||
{
|
||||
unit: "USD",
|
||||
@@ -597,6 +749,7 @@ export function init({
|
||||
id: `bitcoin`,
|
||||
fitContentOnResize: true,
|
||||
vecsResources,
|
||||
elements,
|
||||
utils,
|
||||
config: [
|
||||
{
|
||||
@@ -621,6 +774,7 @@ export function init({
|
||||
fitContentOnResize: true,
|
||||
vecsResources,
|
||||
utils,
|
||||
elements,
|
||||
config: [
|
||||
{
|
||||
unit: "USD",
|
||||
@@ -650,6 +804,8 @@ export function init({
|
||||
id: `return-ratio`,
|
||||
fitContentOnResize: true,
|
||||
utils,
|
||||
elements,
|
||||
|
||||
config: [
|
||||
{
|
||||
unit: "USD",
|
||||
@@ -672,10 +828,11 @@ export function init({
|
||||
fitContentOnResize: true,
|
||||
vecsResources,
|
||||
utils,
|
||||
elements,
|
||||
owner,
|
||||
config: [
|
||||
{
|
||||
unit: "Percentage",
|
||||
unit: "%",
|
||||
blueprints: [
|
||||
{
|
||||
title: "Profitable Days Ratio",
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecIdToIndexes} args.vecIdToIndexes
|
||||
* @param {Option} args.option
|
||||
* @param {Utilities} args.utils
|
||||
* @param {Signals} args.signals
|
||||
* @param {VecsResources} args.vecsResources
|
||||
*/
|
||||
function createTable({
|
||||
utils,
|
||||
vecIdToIndexes,
|
||||
signals,
|
||||
option,
|
||||
vecsResources,
|
||||
}) {
|
||||
const indexToVecIds = createIndexToVecIds(vecIdToIndexes);
|
||||
|
||||
const serializedIndexes = createSerializedIndexes();
|
||||
/** @type {SerializedIndex} */
|
||||
const defaultSerializedIndex = "height";
|
||||
const serializedIndex = /** @type {Signal<SerializedIndex>} */ (
|
||||
signals.createSignal(
|
||||
/** @type {SerializedIndex} */ (defaultSerializedIndex),
|
||||
{
|
||||
save: {
|
||||
...utils.serde.string,
|
||||
keyPrefix: "table",
|
||||
key: "index",
|
||||
},
|
||||
},
|
||||
)
|
||||
);
|
||||
const index = signals.createMemo(() =>
|
||||
serializedIndexToIndex(serializedIndex()),
|
||||
);
|
||||
|
||||
const table = window.document.createElement("table");
|
||||
const obj = {
|
||||
element: table,
|
||||
/** @type {VoidFunction | undefined} */
|
||||
addRandomCol: undefined,
|
||||
};
|
||||
|
||||
signals.createEffect(index, (index, prevIndex) => {
|
||||
if (prevIndex !== undefined) {
|
||||
utils.url.resetParams(option);
|
||||
}
|
||||
|
||||
const possibleVecIds = indexToVecIds[index];
|
||||
|
||||
const columns = signals.createSignal(/** @type {VecId[]} */ ([]), {
|
||||
equals: false,
|
||||
save: {
|
||||
...utils.serde.vecIds,
|
||||
keyPrefix: `table-${serializedIndex()}`,
|
||||
key: `columns`,
|
||||
},
|
||||
});
|
||||
columns.set((l) => l.filter((id) => possibleVecIds.includes(id)));
|
||||
|
||||
signals.createEffect(columns, (columns) => {
|
||||
console.log(columns);
|
||||
});
|
||||
|
||||
table.innerHTML = "";
|
||||
const thead = window.document.createElement("thead");
|
||||
table.append(thead);
|
||||
const trHead = window.document.createElement("tr");
|
||||
thead.append(trHead);
|
||||
const tbody = window.document.createElement("tbody");
|
||||
table.append(tbody);
|
||||
|
||||
const rowElements = signals.createSignal(
|
||||
/** @type {HTMLTableRowElement[]} */ ([]),
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {HTMLSelectElement} args.select
|
||||
* @param {Unit} [args.unit]
|
||||
* @param {(event: MouseEvent) => void} [args.onLeft]
|
||||
* @param {(event: MouseEvent) => void} [args.onRight]
|
||||
* @param {(event: MouseEvent) => void} [args.onRemove]
|
||||
*/
|
||||
function addThCol({ select, onLeft, onRight, onRemove, unit: _unit }) {
|
||||
const th = window.document.createElement("th");
|
||||
th.scope = "col";
|
||||
trHead.append(th);
|
||||
const div = window.document.createElement("div");
|
||||
div.append(select);
|
||||
const strip = window.document.createElement("div");
|
||||
const unit = window.document.createElement("span");
|
||||
if (_unit) {
|
||||
unit.innerHTML = _unit;
|
||||
}
|
||||
const moveLeft = utils.dom.createButtonElement({
|
||||
inside: "←",
|
||||
title: "Move column to the left",
|
||||
onClick: onLeft || (() => {}),
|
||||
});
|
||||
const moveRight = utils.dom.createButtonElement({
|
||||
inside: "→",
|
||||
title: "Move column to the right",
|
||||
onClick: onRight || (() => {}),
|
||||
});
|
||||
const remove = utils.dom.createButtonElement({
|
||||
inside: "×",
|
||||
title: "Remove column",
|
||||
onClick: onRemove || (() => {}),
|
||||
});
|
||||
strip.append(unit);
|
||||
strip.append(moveLeft);
|
||||
strip.append(moveRight);
|
||||
strip.append(remove);
|
||||
div.append(strip);
|
||||
th.append(div);
|
||||
return {
|
||||
element: th,
|
||||
/**
|
||||
* @param {Unit} _unit
|
||||
*/
|
||||
setUnit(_unit) {
|
||||
unit.innerHTML = _unit;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
addThCol({
|
||||
...utils.dom.createSelect({
|
||||
list: serializedIndexes,
|
||||
signal: serializedIndex,
|
||||
}),
|
||||
unit: "Index",
|
||||
});
|
||||
|
||||
let from = 0;
|
||||
let to = 0;
|
||||
|
||||
vecsResources
|
||||
.getOrCreate(index, serializedIndex())
|
||||
.fetch()
|
||||
.then((vec) => {
|
||||
if (!vec) return;
|
||||
from = /** @type {number} */ (vec[0]);
|
||||
to = /** @type {number} */ (vec.at(-1)) + 1;
|
||||
const trs = /** @type {HTMLTableRowElement[]} */ ([]);
|
||||
for (let i = vec.length - 1; i >= 0; i--) {
|
||||
const value = vec[i];
|
||||
const tr = window.document.createElement("tr");
|
||||
trs.push(tr);
|
||||
tbody.append(tr);
|
||||
const th = window.document.createElement("th");
|
||||
th.innerHTML = serializeValue({
|
||||
value,
|
||||
unit: "Index",
|
||||
});
|
||||
th.scope = "row";
|
||||
tr.append(th);
|
||||
}
|
||||
rowElements.set(() => trs);
|
||||
});
|
||||
|
||||
const owner = signals.getOwner();
|
||||
|
||||
/**
|
||||
* @param {VecId} vecId
|
||||
* @param {number} [_colIndex]
|
||||
*/
|
||||
function addCol(vecId, _colIndex = columns().length) {
|
||||
signals.runWithOwner(owner, () => {
|
||||
/** @type {VoidFunction | undefined} */
|
||||
let dispose;
|
||||
signals.createRoot((_dispose) => {
|
||||
dispose = _dispose;
|
||||
|
||||
const vecIdOption = signals.createSignal({
|
||||
name: vecId,
|
||||
value: vecId,
|
||||
});
|
||||
const { select } = utils.dom.createSelect({
|
||||
list: possibleVecIds.map((vecId) => ({
|
||||
name: vecId,
|
||||
value: vecId,
|
||||
})),
|
||||
signal: vecIdOption,
|
||||
});
|
||||
|
||||
if (_colIndex === columns().length) {
|
||||
columns.set((l) => {
|
||||
l.push(vecId);
|
||||
return l;
|
||||
});
|
||||
}
|
||||
|
||||
const colIndex = signals.createSignal(_colIndex);
|
||||
|
||||
/**
|
||||
* @param {boolean} right
|
||||
* @returns {(event: MouseEvent) => void}
|
||||
*/
|
||||
function createMoveColumnFunction(right) {
|
||||
return () => {
|
||||
const oldColIndex = colIndex();
|
||||
const newColIndex = oldColIndex + (right ? 1 : -1);
|
||||
|
||||
const currentTh = /** @type {HTMLTableCellElement} */ (
|
||||
trHead.childNodes[oldColIndex + 1]
|
||||
);
|
||||
const oterTh = /** @type {HTMLTableCellElement} */ (
|
||||
trHead.childNodes[newColIndex + 1]
|
||||
);
|
||||
|
||||
if (right) {
|
||||
oterTh.after(currentTh);
|
||||
} else {
|
||||
oterTh.before(currentTh);
|
||||
}
|
||||
|
||||
columns.set((l) => {
|
||||
[l[oldColIndex], l[newColIndex]] = [
|
||||
l[newColIndex],
|
||||
l[oldColIndex],
|
||||
];
|
||||
return l;
|
||||
});
|
||||
|
||||
const rows = rowElements();
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const element = rows[i].childNodes[oldColIndex + 1];
|
||||
const sibling = rows[i].childNodes[newColIndex + 1];
|
||||
const temp = element.textContent;
|
||||
element.textContent = sibling.textContent;
|
||||
sibling.textContent = temp;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const th = addThCol({
|
||||
select,
|
||||
unit: utils.vecidToUnit(vecId),
|
||||
onLeft: createMoveColumnFunction(false),
|
||||
onRight: createMoveColumnFunction(true),
|
||||
onRemove: () => {
|
||||
const ci = colIndex();
|
||||
trHead.childNodes[ci + 1].remove();
|
||||
columns.set((l) => {
|
||||
l.splice(ci, 1);
|
||||
return l;
|
||||
});
|
||||
const rows = rowElements();
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
rows[i].childNodes[ci + 1].remove();
|
||||
}
|
||||
dispose?.();
|
||||
},
|
||||
});
|
||||
|
||||
signals.createEffect(columns, () => {
|
||||
colIndex.set(Array.from(trHead.children).indexOf(th.element) - 1);
|
||||
});
|
||||
|
||||
console.log(colIndex());
|
||||
|
||||
signals.createEffect(rowElements, (rowElements) => {
|
||||
if (!rowElements.length) return;
|
||||
for (let i = 0; i < rowElements.length; i++) {
|
||||
const td = window.document.createElement("td");
|
||||
rowElements[i].append(td);
|
||||
}
|
||||
|
||||
signals.createEffect(
|
||||
() => vecIdOption().name,
|
||||
(vecId, prevVecId) => {
|
||||
const unit = utils.vecidToUnit(vecId);
|
||||
th.setUnit(unit);
|
||||
|
||||
const vec = vecsResources.getOrCreate(index, vecId);
|
||||
|
||||
vec.fetch({ from, to });
|
||||
|
||||
columns.set((l) => {
|
||||
const i = l.indexOf(prevVecId ?? vecId);
|
||||
if (i === -1) {
|
||||
l.push(vecId);
|
||||
} else {
|
||||
l[i] = vecId;
|
||||
}
|
||||
return l;
|
||||
});
|
||||
|
||||
signals.createEffect(vec.fetched, (vec) => {
|
||||
if (!vec) return;
|
||||
|
||||
const thIndex = colIndex() + 1;
|
||||
|
||||
for (let i = 0; i < rowElements.length; i++) {
|
||||
const iRev = vec.length - 1 - i;
|
||||
const value = vec[iRev];
|
||||
// @ts-ignore
|
||||
rowElements[i].childNodes[thIndex].innerHTML =
|
||||
serializeValue({
|
||||
value,
|
||||
unit,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return () => vecId;
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
signals.onCleanup(() => {
|
||||
dispose?.();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
columns().forEach((vecId, colIndex) => addCol(vecId, colIndex));
|
||||
|
||||
obj.addRandomCol = function () {
|
||||
const vecId =
|
||||
possibleVecIds[Math.floor(Math.random() * possibleVecIds.length)];
|
||||
addCol(vecId);
|
||||
};
|
||||
|
||||
return () => index;
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Colors} args.colors
|
||||
* @param {Signals} args.signals
|
||||
* @param {Utilities} args.utils
|
||||
* @param {Option} args.option
|
||||
* @param {Elements} args.elements
|
||||
* @param {VecsResources} args.vecsResources
|
||||
* @param {VecIdToIndexes} args.vecIdToIndexes
|
||||
*/
|
||||
export function init({
|
||||
colors,
|
||||
elements,
|
||||
signals,
|
||||
option,
|
||||
utils,
|
||||
vecsResources,
|
||||
vecIdToIndexes,
|
||||
}) {
|
||||
const parent = elements.table;
|
||||
const { headerElement } = utils.dom.createHeader({
|
||||
title: "Table",
|
||||
});
|
||||
parent.append(headerElement);
|
||||
|
||||
const div = window.document.createElement("div");
|
||||
parent.append(div);
|
||||
|
||||
const table = createTable({
|
||||
signals,
|
||||
utils,
|
||||
vecIdToIndexes,
|
||||
vecsResources,
|
||||
option,
|
||||
});
|
||||
div.append(table.element);
|
||||
|
||||
const span = window.document.createElement("span");
|
||||
span.innerHTML = "Add column";
|
||||
div.append(
|
||||
utils.dom.createButtonElement({
|
||||
onClick: () => {
|
||||
table.addRandomCol?.();
|
||||
},
|
||||
inside: span,
|
||||
title: "Click or tap to add a column to the table",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function createSerializedIndexes() {
|
||||
return /** @type {const} */ ([
|
||||
/** @satisfies {VecId} */ ("height"),
|
||||
/** @satisfies {VecId} */ ("dateindex"),
|
||||
/** @satisfies {VecId} */ ("weekindex"),
|
||||
/** @satisfies {VecId} */ ("difficultyepoch"),
|
||||
/** @satisfies {VecId} */ ("monthindex"),
|
||||
/** @satisfies {VecId} */ ("quarterindex"),
|
||||
/** @satisfies {VecId} */ ("yearindex"),
|
||||
/** @satisfies {VecId} */ ("decadeindex"),
|
||||
/** @satisfies {VecId} */ ("halvingepoch"),
|
||||
/** @satisfies {VecId} */ ("addressindex"),
|
||||
/** @satisfies {VecId} */ ("p2pk33index"),
|
||||
/** @satisfies {VecId} */ ("p2pk65index"),
|
||||
/** @satisfies {VecId} */ ("p2pkhindex"),
|
||||
/** @satisfies {VecId} */ ("p2shindex"),
|
||||
/** @satisfies {VecId} */ ("p2trindex"),
|
||||
/** @satisfies {VecId} */ ("p2wpkhindex"),
|
||||
/** @satisfies {VecId} */ ("p2wshindex"),
|
||||
/** @satisfies {VecId} */ ("txindex"),
|
||||
/** @satisfies {VecId} */ ("txinindex"),
|
||||
/** @satisfies {VecId} */ ("txoutindex"),
|
||||
/** @satisfies {VecId} */ ("emptyindex"),
|
||||
/** @satisfies {VecId} */ ("multisigindex"),
|
||||
/** @satisfies {VecId} */ ("opreturnindex"),
|
||||
/** @satisfies {VecId} */ ("pushonlyindex"),
|
||||
/** @satisfies {VecId} */ ("unknownindex"),
|
||||
]);
|
||||
}
|
||||
/** @typedef {ReturnType<typeof createSerializedIndexes>} SerializedIndexes */
|
||||
/** @typedef {SerializedIndexes[number]} SerializedIndex */
|
||||
|
||||
/**
|
||||
* @param {SerializedIndex} serializedIndex
|
||||
* @returns {Index}
|
||||
*/
|
||||
function serializedIndexToIndex(serializedIndex) {
|
||||
switch (serializedIndex) {
|
||||
case "height":
|
||||
return /** @satisfies {Height} */ (0);
|
||||
case "dateindex":
|
||||
return /** @satisfies {Dateindex} */ (1);
|
||||
case "weekindex":
|
||||
return /** @satisfies {Weekindex} */ (2);
|
||||
case "difficultyepoch":
|
||||
return /** @satisfies {Difficultyepoch} */ (3);
|
||||
case "monthindex":
|
||||
return /** @satisfies {Monthindex} */ (4);
|
||||
case "quarterindex":
|
||||
return /** @satisfies {Quarterindex} */ (5);
|
||||
case "yearindex":
|
||||
return /** @satisfies {Yearindex} */ (6);
|
||||
case "decadeindex":
|
||||
return /** @satisfies {Decadeindex} */ (7);
|
||||
case "halvingepoch":
|
||||
return /** @satisfies {Halvingepoch} */ (8);
|
||||
case "addressindex":
|
||||
return /** @satisfies {Addressindex} */ (9);
|
||||
case "p2pk33index":
|
||||
return /** @satisfies {P2PK33index} */ (10);
|
||||
case "p2pk65index":
|
||||
return /** @satisfies {P2PK65index} */ (11);
|
||||
case "p2pkhindex":
|
||||
return /** @satisfies {P2PKHindex} */ (12);
|
||||
case "p2shindex":
|
||||
return /** @satisfies {P2SHindex} */ (13);
|
||||
case "p2trindex":
|
||||
return /** @satisfies {P2TRindex} */ (14);
|
||||
case "p2wpkhindex":
|
||||
return /** @satisfies {P2WPKHindex} */ (15);
|
||||
case "p2wshindex":
|
||||
return /** @satisfies {P2WSHindex} */ (16);
|
||||
case "txindex":
|
||||
return /** @satisfies {Txindex} */ (17);
|
||||
case "txinindex":
|
||||
return /** @satisfies {Txinindex} */ (18);
|
||||
case "txoutindex":
|
||||
return /** @satisfies {Txoutindex} */ (19);
|
||||
case "emptyindex":
|
||||
return /** @satisfies {Emptyindex} */ (20);
|
||||
case "multisigindex":
|
||||
return /** @satisfies {Multisigindex} */ (21);
|
||||
case "opreturnindex":
|
||||
return /** @satisfies {Opreturnindex} */ (22);
|
||||
case "pushonlyindex":
|
||||
return /** @satisfies {Pushonlyindex} */ (23);
|
||||
case "unknownindex":
|
||||
return /** @satisfies {Unknownindex} */ (24);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VecIdToIndexes} vecIdToIndexes
|
||||
*/
|
||||
function createIndexToVecIds(vecIdToIndexes) {
|
||||
const indexToVecIds = Object.entries(vecIdToIndexes).reduce(
|
||||
(arr, [_id, indexes]) => {
|
||||
const id = /** @type {VecId} */ (_id);
|
||||
indexes.forEach((i) => {
|
||||
arr[i] ??= [];
|
||||
arr[i].push(id);
|
||||
});
|
||||
return arr;
|
||||
},
|
||||
/** @type {VecId[][]} */ (new Array(24)),
|
||||
);
|
||||
indexToVecIds.forEach((arr) => {
|
||||
arr.sort();
|
||||
});
|
||||
return indexToVecIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {number | OHLCTuple} args.value
|
||||
* @param {Unit} args.unit
|
||||
*/
|
||||
function serializeValue({ value, unit }) {
|
||||
if (typeof value !== "number") {
|
||||
return String(value);
|
||||
} else if (value !== 18446744073709552000) {
|
||||
if (unit === "USD" || unit === "Difficulty" || unit === "sat/vB") {
|
||||
return value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
} else if (unit === "BTC") {
|
||||
return value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 8,
|
||||
maximumFractionDigits: 8,
|
||||
});
|
||||
} else {
|
||||
return value.toLocaleString("en-us");
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export function createVecIdToIndexes() {
|
||||
const Unknownindex = /** @satisfies {Unknownindex} */ (24);
|
||||
|
||||
return /** @type {const} */ ({
|
||||
addressindex: [Txoutindex],
|
||||
addressindex: [Addressindex, Txoutindex],
|
||||
addresstype: [Addressindex],
|
||||
addresstypeindex: [Addressindex],
|
||||
"base-size": [Txindex],
|
||||
@@ -114,6 +114,7 @@ export function createVecIdToIndexes() {
|
||||
decadeindex: [Yearindex, Decadeindex],
|
||||
difficulty: [Height],
|
||||
difficultyepoch: [Height, Difficultyepoch],
|
||||
emptyindex: [Emptyindex],
|
||||
fee: [Txindex],
|
||||
"fee-10p": [Height],
|
||||
"fee-25p": [Height],
|
||||
@@ -208,12 +209,14 @@ export function createVecIdToIndexes() {
|
||||
"low-in-cents": [Dateindex, Height],
|
||||
"low-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
monthindex: [Dateindex, Monthindex],
|
||||
multisigindex: [Multisigindex],
|
||||
ohlc: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"ohlc-in-cents": [Dateindex, Height],
|
||||
"ohlc-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
open: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"open-in-cents": [Dateindex, Height],
|
||||
"open-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
opreturnindex: [Opreturnindex],
|
||||
"output-count": [Txindex],
|
||||
"output-count-10p": [Height],
|
||||
"output-count-25p": [Height],
|
||||
@@ -228,12 +231,20 @@ export function createVecIdToIndexes() {
|
||||
"output-value-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-value-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
p2pk33addressbytes: [P2PK33index],
|
||||
p2pk33index: [P2PK33index],
|
||||
p2pk65addressbytes: [P2PK65index],
|
||||
p2pk65index: [P2PK65index],
|
||||
p2pkhaddressbytes: [P2PKHindex],
|
||||
p2pkhindex: [P2PKHindex],
|
||||
p2shaddressbytes: [P2SHindex],
|
||||
p2shindex: [P2SHindex],
|
||||
p2traddressbytes: [P2TRindex],
|
||||
p2trindex: [P2TRindex],
|
||||
p2wpkhaddressbytes: [P2WPKHindex],
|
||||
p2wpkhindex: [P2WPKHindex],
|
||||
p2wshaddressbytes: [P2WSHindex],
|
||||
p2wshindex: [P2WSHindex],
|
||||
pushonlyindex: [Pushonlyindex],
|
||||
quarterindex: [Monthindex, Quarterindex],
|
||||
"real-date": [Height],
|
||||
subsidy: [Height],
|
||||
@@ -322,8 +333,11 @@ export function createVecIdToIndexes() {
|
||||
"tx-weight-median": [Height],
|
||||
"tx-weight-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
txid: [Txindex],
|
||||
txoutindex: [Txinindex],
|
||||
txindex: [Txindex],
|
||||
txinindex: [Txinindex],
|
||||
txoutindex: [Txinindex, Txoutindex],
|
||||
txversion: [Txindex],
|
||||
unknownindex: [Unknownindex],
|
||||
value: [Txinindex, Txoutindex],
|
||||
vbytes: [Height],
|
||||
vsize: [Txindex],
|
||||
|
||||
@@ -27,4 +27,8 @@
|
||||
.chart {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
> * {
|
||||
z-index: 30;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#table {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
padding: var(--main-padding);
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
font-size: var(--font-size-sm);
|
||||
margin-left: var(--negative-main-padding);
|
||||
margin-right: var(--negative-main-padding);
|
||||
|
||||
table {
|
||||
z-index: 10;
|
||||
border-top-width: 1px;
|
||||
border-style: dashed !important;
|
||||
/* width: 100%; */
|
||||
line-height: var(--line-height-sm);
|
||||
text-transform: uppercase;
|
||||
table-layout: auto;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
/* border: 3px solid purple; */
|
||||
/* min-height: 100%; */
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
/* border-top: 1px; */
|
||||
border-right: 1px;
|
||||
border-bottom: 1px;
|
||||
border-color: var(--off-color);
|
||||
border-style: dashed !important;
|
||||
padding: 0.25rem 1rem;
|
||||
}
|
||||
|
||||
td {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
th:first-child {
|
||||
padding-left: var(--main-padding);
|
||||
}
|
||||
|
||||
th[scope="col"] {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: var(--background-color);
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 0.275rem;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
text-transform: lowercase;
|
||||
color: var(--off-color);
|
||||
text-align: left;
|
||||
gap: 1rem;
|
||||
|
||||
> span {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> button {
|
||||
padding: 0 0.25rem;
|
||||
margin: 0 -0.25rem;
|
||||
font-size: 1rem;
|
||||
line-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
button:nth-of-type(1) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
button:nth-of-type(2) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* select {
|
||||
width: 100%;
|
||||
} */
|
||||
|
||||
tbody {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
> button {
|
||||
padding: 1rem;
|
||||
min-width: 10rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
border-top-width: 1px;
|
||||
width: 100%;
|
||||
/* border-right-width: 1px; */
|
||||
border-bottom-width: 1px;
|
||||
border-style: dashed !important;
|
||||
|
||||
> span {
|
||||
text-align: left;
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user