diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml deleted file mode 100644 index 11b0dd8..0000000 --- a/.github/workflows/backend-ci.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Backend CI - -on: - pull_request: - branches: [main] - paths: - - "backend/**" - - ".github/workflows/backend-ci.yml" - push: - branches: [main] - paths: - - "backend/**" - - ".github/workflows/backend-ci.yml" - -jobs: - backend-ci: - runs-on: ubuntu-latest - defaults: - run: - working-directory: backend - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - - - name: Cache Rust - uses: swatinem/rust-cache@v2 - with: - workspaces: | - backend -> target - - # - name: Format - # run: cargo fmt --all -- --check - - # - name: Lint - # run: cargo clippy --all-targets --all-features -- -D warnings - - - name: Test - run: cargo test --all diff --git a/.github/workflows/frontend-ci.yml b/.github/workflows/frontend-ci.yml index 7a01a32..bbb7892 100644 --- a/.github/workflows/frontend-ci.yml +++ b/.github/workflows/frontend-ci.yml @@ -39,8 +39,14 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Rebuild native deps (better-sqlite3) + run: pnpm rebuild better-sqlite3 + - name: Run typecheck run: pnpm run typecheck - name: Run check - run: pnpm run check \ No newline at end of file + run: pnpm run check + + - name: Run tests + run: pnpm test --run \ No newline at end of file diff --git a/.gitignore b/.gitignore index 48f6730..00c5b29 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,8 @@ Thumbs.db # Logs *.log + +# Tracker SQLite artifacts (tx3-lift sidecar) +tracker.db +tracker.db-wal +tracker.db-shm diff --git a/README.md b/README.md index f9caa13..8501e22 100644 --- a/README.md +++ b/README.md @@ -1,188 +1,74 @@ # tx3 Dashboard -This project provides a backend service that ingests Cardano transactions via the utxorpc service and exposes a read API for a web dashboard. -The dashboard consumes the backend API to present transaction activity, UTxOs, and asset movements in a structured, queryable view. - -## How it works - -1. **Load protocol**: The backend fetches protocol definitions and parameters from the tx3 registry. -2. **Ingest transactions**: utxorpc streams new transactions to the backend. -3. **Persist state**: The backend normalizes transaction data into SQLite tables. -4. **Serve the dashboard**: The dashboard queries the API for aggregated transaction and UTxO views. - -## Project structure (conceptual) - -``` -dashboard/ -├── backend/ # API + ingestion service -└── frontend/ # Frontend UI -``` - -## Architecture at a glance - -- **Frontend dashboard**: Browser UI that queries the backend API. -- **Backend API**: Axum-based service that serves transaction data and aggregates UTxO state. -- **UTxO RPC ingestion**: Real-time transaction stream feeding the backend. -- **Tx3 Registry integration**: Fetches protocol definitions and parameters. -- **SQLite data store**: Persists transactions, UTXOs, and asset amounts. +A monitoring dashboard for [Tx3](https://github.com/tx3-lang)-described dApps. Builders and operators run it alongside `tx3-lift`'s tracker to see their protocol's matched on-chain transactions in real time, with parties and transaction names lifted from the TII. The dashboard is a pure TypeScript app (TanStack Start + Nitro SSR) that observes the SQLite file the tracker writes — no custom backend, no API tier in the middle. ## System context ```mermaid -flowchart LR - Dashboard[Dashboard UI] - API[Backend API] - Utxorpc[UTxO RPC Service] - Registry[Tx3 Registry] - DB[(SQLite)] - - Dashboard -->|HTTP| API - Utxorpc -->|Tx stream| API - Registry -->|Protocol definitions| API - API --> DB -``` +C4Context +title System Context — tx3 Dashboard -## Data flow +Person(operator, "Builder / Operator", "Runs the dashboard for their own dApp") +System(dashboard, "tx3 Dashboard", "Tracker (sidecar) + SSR app that monitor a Tx3-described dApp") +System_Ext(utxorpc, "utxorpc Provider", "Cardano chain stream (v1beta WatchTx)") +System_Ext(registry, "Tx3 Registry", "Source of TII files (queried at vendor time, not runtime)") -```mermaid -sequenceDiagram - participant D as Dashboard UI - participant A as Backend API - participant U as UTxO RPC Service - participant R as Tx3 Registry - participant S as SQLite - - R->>A: Protocol definitions - U->>A: Transaction events - A->>S: Persist txs, utxos, amounts - D->>A: GET /txs, /txs/:hash - A->>S: Query txs + UTXO state - A-->>D: Aggregated transaction view +Rel(operator, dashboard, "Views matched transactions", "HTTPS") +Rel(dashboard, utxorpc, "Subscribes to tx stream", "gRPC / TLS") +Rel(operator, registry, "Pulls TII once at vendor time", "GraphQL") ``` -## Data model +## Quick start -```mermaid -erDiagram - TXS { - text hash PK - text tx_name - datetime created_at - } - - UTXOS { - text tx_hash PK - int output_index PK - text address - text consumed_by_tx - text datum - } - - UTXO_AMOUNT { - text tx_hash PK - int output_index PK - text unit PK - text quantity - } - - TXS ||--o{ UTXOS : "by tx_hash" - UTXOS ||--o{ UTXO_AMOUNT : "by (tx_hash, output_index)" +You need a clone of [`tx3-lang/tx3-lift`](https://github.com/tx3-lang/tx3-lift) as a sibling directory and a Demeter `utxorpc` API key. + +```bash +# Once: clone tx3-lift sibling +git clone https://github.com/tx3-lang/tx3-lift ../tx3-lift ``` -## API surface - -### `GET /txs` - -Returns a list of recent transactions ordered by `created_at` (newest first). Each item includes the protocol transaction name, inputs, outputs, and asset amounts. - -Example response: - -```json -[ - { - "hash": "d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc", - "tx_name": "buy_ticket", - "inputs": [ - { - "address": "addr1wy8ccvgzslpjf9yhrprvmqulpmjpkpxf8c0hvtjwvw8n6pqdcrnp0", - "tx_hash": "31596ecbdcf102c8e5c17e75c65cf9780996285879d18903f035964f3a7499a8", - "output_index": 0, - "amount": [ - { "unit": "lovelace", "quantity": "12507620" } - ], - "datum": null, - "consumed_by_tx": "d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc" - } - ], - "outputs": [ - { - "address": "addr1wywecz65rtwrqrqemhrtn7mrczl7x2c4pqc9hfjmsa3dc7cr5pvqw", - "tx_hash": "d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc", - "output_index": 1, - "amount": [ - { "unit": "lovelace", "quantity": "1124910" }, - { "unit": "e1ddde8138579e255482791d9fba0778cb1f5c7b435be7b3e42069de425549444c45524645535432303236", "quantity": "1" } - ], - "datum": "d87981184b", - "consumed_by_tx": null - } - ] - } -] +```bash +# Terminal A — tracker (sidecar that writes tracker.db) +cd ../tx3-lift +DMTR_API_KEY=dmtr_... cargo run -p tracker -- ../dashboard/tracker.toml ``` -### `GET /txs/:hash` - -Returns a single transaction in the same expanded shape as `/txs`. - -Example response: - -```json -{ - "hash": "d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc", - "tx_name": "buy_ticket", - "inputs": [ - { - "address": "addr1wy8ccvgzslpjf9yhrprvmqulpmjpkpxf8c0hvtjwvw8n6pqdcrnp0", - "tx_hash": "31596ecbdcf102c8e5c17e75c65cf9780996285879d18903f035964f3a7499a8", - "output_index": 0, - "amount": [ - { "unit": "lovelace", "quantity": "12507620" } - ], - "datum": null, - "consumed_by_tx": "d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc" - } - ], - "outputs": [ - { - "address": "addr1wywecz65rtwrqrqemhrtn7mrczl7x2c4pqc9hfjmsa3dc7cr5pvqw", - "tx_hash": "d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc", - "output_index": 1, - "amount": [ - { "unit": "lovelace", "quantity": "1124910" }, - { "unit": "e1ddde8138579e255482791d9fba0778cb1f5c7b435be7b3e42069de425549444c45524645535432303236", "quantity": "1" } - ], - "datum": "d87981184b", - "consumed_by_tx": null - } - ] -} +```bash +# Terminal B — dashboard (TanStack Start SSR app) +cd dashboard/frontend +pnpm install +pnpm dev ``` -## Runtime configuration +Open . See [`docs/running.md`](docs/running.md) for prerequisites, env vars, and troubleshooting. -The backend uses environment variables for configuration (server address, database path, registry URL, and utxorpc connection details). The frontend dashboard only requires the backend base URL to query the API. +## What the demo shows -## Component responsibilities +The committed configuration tracks the [`buidler-fest/ticketing-2026`](protocols/buidler-fest/ticketing-2026.tii) protocol on Cardano preview. It defines a single transaction name (`buy_ticket`) with three parties (`buyer`, `treasury`, `issuer`) and roughly 80 real on-chain matches. The matches list at `/` shows every `buy_ticket` the tracker has seen, newest first; clicking through to `/txs/` shows the parties and their addresses for that transaction. -- **Backend API**: Aggregates transaction data and exposes `/txs` endpoints. -- **UTxO RPC ingestion**: Streams new transactions into the backend. -- **Registry integration**: Supplies protocol definitions and parameters. -- **Dashboard UI**: Presents transaction activity and UTXO state to users. +## Documentation -## Main concepts +- [`docs/architecture.md`](docs/architecture.md) — two-process topology, data flow per page load, why the shape, Postgres outlook. +- [`docs/access-patterns.md`](docs/access-patterns.md) — AP-1 (list) and AP-2 (detail), with type signatures and SQL. +- [`docs/running.md`](docs/running.md) — prerequisites, env vars, first run, troubleshooting, deployment notes. -- **Transaction**: Identified by `hash` and labeled by `tx_name`. -- **UTxO**: A specific output index associated with a transaction hash. -- **Asset amount**: Unit/quantity pairs attached to a UTXO. -- **Protocol tx name**: The protocol-level transaction identifier used for grouping. +## Project structure + +``` +dashboard/ +├── README.md # this file +├── tracker.toml # config consumed by the external tracker +├── docs/ +│ ├── architecture.md +│ ├── access-patterns.md +│ └── running.md +├── protocols/ +│ └── buidler-fest/ +│ └── ticketing-2026.tii # vendored TII for the demo protocol +└── frontend/ # TanStack Start SSR app + ├── package.json + └── src/ + ├── lib/ # db.ts, queries.ts, lifted.ts + ├── components/ # PartyChip, TxNamePill, Header, ... + └── routes/ # / (matches list), /txs/$hash (detail) +``` diff --git a/backend/.env.example b/backend/.env.example deleted file mode 100644 index 48433cf..0000000 --- a/backend/.env.example +++ /dev/null @@ -1,16 +0,0 @@ -SERVER_ADDR="0.0.0.0:3000" - -DATABASE_PATH="./dashboard.db" - -REGISTRY_URL="https://api.tx3.land/graphql" - -U5C_URL="" -U5C_API_KEY="" - -BLOCKFROST_URL="" - -PROTOCOL_SCOPE="buidler-fest" -PROTOCOL_NAME="ticketing-2026" -PROTOCOL_PARAMETERS='{"env":{"issuer_beacon_policy":"e1ddde8138579e255482791d9fba0778cb1f5c7b435be7b3e42069de","issuer_beacon_name":"425549444c45524645535432303236","ticket_policy":"1d9c0b541adc300c19ddc6b9fb63c0bfe32b1508305ba65b8762dc7b","issuer_script_ref":"31596ecbdcf102c8e5c17e75c65cf9780996285879d18903f035964f3a7499a8#0","ticket_price":500000000},"parties":{"treasury":"addr1qx0decp93g2kwym5cz0p68thamd2t9pehlxqe02qae5r6nycv42qmjppm2rr8fj6qlzfhm6ljkd5f0tjlgudtmt5kzyqmy8x82","issuer":"addr1wywecz65rtwrqrqemhrtn7mrczl7x2c4pqc9hfjmsa3dc7cr5pvqw"},"txs":{"buy_ticket":{}}}' - -TXS="d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc,26741de9ee337aa24ebeea078832a901c4deacce261e142a23186b1691513863,31596ecbdcf102c8e5c17e75c65cf9780996285879d18903f035964f3a7499a8" diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index e735f07..0000000 --- a/backend/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Rust build artifacts -/target/ -**/*.rs.bk - -# SQLite database file -dashboard.db \ No newline at end of file diff --git a/backend/Cargo.lock b/backend/Cargo.lock deleted file mode 100644 index 9cdd2b1..0000000 --- a/backend/Cargo.lock +++ /dev/null @@ -1,4646 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "getrandom 0.3.4", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ar_archive_writer" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" -dependencies = [ - "object", -] - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower 0.5.3", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - -[[package]] -name = "base58" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - -[[package]] -name = "bech32" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" - -[[package]] -name = "binary-layout" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5845e3504cf59b9588fff324710f27ee519515b8a8a9f1207042da9a9e64f819" -dependencies = [ - "doc-comment", - "paste", -] - -[[package]] -name = "bitcoin-io" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" - -[[package]] -name = "bitcoin_hashes" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" -dependencies = [ - "bitcoin-io", - "hex-conservative", -] - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -dependencies = [ - "serde_core", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blst" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" -dependencies = [ - "cc", - "glob", - "threadpool", - "zeroize", -] - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "cc" -version = "1.2.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "chumsky" -version = "1.0.0-alpha.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7b80276986f86789dc56ca6542d53bba9cda3c66091ebbe7bd96fc1bdf20f1f" -dependencies = [ - "hashbrown 0.14.5", - "regex-automata 0.3.9", - "serde", - "stacker", - "unicode-ident", -] - -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cryptoxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382ce8820a5bb815055d3553a610e8cb542b2d767bbacea99038afda96cd760d" - -[[package]] -name = "darling" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.117", -] - -[[package]] -name = "darling_macro" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", - "serde_core", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "doc-comment" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -dependencies = [ - "serde", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flume" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" -dependencies = [ - "futures-core", - "futures-sink", - "spin", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasip2", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", - "wasip3", -] - -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "h2" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.13.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-conservative" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls 0.23.37", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots 1.0.6", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ibig" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1fcc7f316b2c079dde77564a1360639c1a956a23fa96122732e416cb10717bb" -dependencies = [ - "cfg-if", - "num-traits", - "static_assertions", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is_ci" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "js-sys" -version = "0.3.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.182" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "libredox" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" -dependencies = [ - "bitflags", - "libc", - "redox_syscall 0.7.2", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata 0.4.14", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "backtrace", - "backtrace-ext", - "cfg-if", - "miette-derive", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "unicode-width 0.1.14", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minicbor" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0452a60c1863c1f50b5f77cd295e8d2786849f35883f0b9e18e7e6e1b5691b0" -dependencies = [ - "minicbor-derive 0.15.3", -] - -[[package]] -name = "minicbor" -version = "0.26.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a309f581ade7597820083bc275075c4c6986e57e53f8d26f88507cfefc8c987" -dependencies = [ - "half", - "minicbor-derive 0.16.2", -] - -[[package]] -name = "minicbor-derive" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd2209fff77f705b00c737016a48e73733d7fbccb8b007194db148f03561fb70" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "minicbor-derive" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9882ef5c56df184b8ffc107fc6c61e33ee3a654b021961d790a78571bb9d67a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "multimap" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" - -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-conv" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl" -version = "0.10.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "openssl-sys" -version = "0.9.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "owo-colors" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" - -[[package]] -name = "pallas" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c593225da7e45c57d209c8315805533ca597c0975ceeaf9c53ca96315c52bbb6" -dependencies = [ - "pallas-addresses", - "pallas-codec", - "pallas-configs", - "pallas-crypto", - "pallas-hardano", - "pallas-network", - "pallas-primitives", - "pallas-traverse", - "pallas-txbuilder", - "pallas-utxorpc", - "pallas-validate", -] - -[[package]] -name = "pallas-addresses" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c0dfee4b45db777d7f0f4c0736e4511bf39681a618ad9896cb18c4565c3c9d7" -dependencies = [ - "base58", - "bech32 0.9.1", - "crc", - "cryptoxide", - "hex", - "pallas-codec", - "pallas-crypto", - "thiserror 1.0.69", -] - -[[package]] -name = "pallas-codec" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65b7e684ceff1877bd7e7af768f87029166fe9c58b85a31f3d3f1ba0d9cc6e3" -dependencies = [ - "hex", - "minicbor 0.26.5", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "pallas-configs" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e995aa8ed6c3a7f6fa75dbb513a62c6619840de7be8e74ef5f283adec528823a" -dependencies = [ - "base64 0.22.1", - "num-rational", - "pallas-addresses", - "pallas-crypto", - "pallas-primitives", - "serde", - "serde_json", - "serde_with", -] - -[[package]] -name = "pallas-crypto" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2e8c4de80742b21581edab58212683a51bca18047cc50ad585c3b2d2009642" -dependencies = [ - "cryptoxide", - "hex", - "pallas-codec", - "rand_core 0.9.5", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "pallas-hardano" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62fe7b454c3b3e175b0cd7deade25a2298972370ed2b06f63ea7ea4ec7fe62ca" -dependencies = [ - "binary-layout", - "hex", - "pallas-addresses", - "pallas-codec", - "pallas-crypto", - "pallas-network", - "pallas-traverse", - "serde", - "serde_json", - "serde_with", - "tap", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "pallas-network" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4605a889fce155df28b5b1cd73b86867275c7bbc587589904e92053682540aa8" -dependencies = [ - "byteorder", - "hex", - "itertools 0.13.0", - "pallas-codec", - "pallas-crypto", - "rand 0.8.5", - "socket2 0.5.10", - "thiserror 1.0.69", - "tokio", - "tracing", -] - -[[package]] -name = "pallas-primitives" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c5cb5c9964f5fd8e14d51f30d2b155c2065f25082c9209de9a6c257c5b54d" -dependencies = [ - "hex", - "pallas-codec", - "pallas-crypto", - "serde", - "serde_json", -] - -[[package]] -name = "pallas-traverse" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc220a19443ba76df3f09ceb43ab303a5cb031b8062beb70d7ed50ced15f09f" -dependencies = [ - "hex", - "itertools 0.13.0", - "pallas-addresses", - "pallas-codec", - "pallas-crypto", - "pallas-primitives", - "paste", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "pallas-txbuilder" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad12eaa6451ff6104c65e980f076763f30ac0dee5612544bc0485a92abdc64da" -dependencies = [ - "hex", - "pallas-addresses", - "pallas-codec", - "pallas-crypto", - "pallas-primitives", - "pallas-traverse", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "pallas-uplc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d17ae8308fa96979da3b2314d0b28e85403448751880582d4f2beafa7d68bb6c" -dependencies = [ - "blst", - "bumpalo", - "chumsky", - "cryptoxide", - "ibig", - "minicbor 0.25.1", - "num-traits", - "once_cell", - "secp256k1", - "thiserror 1.0.69", -] - -[[package]] -name = "pallas-utxorpc" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e61f14013e304cf24eeb5eabcf062f3a2f455d6ccb6e1b33a84810e7488fd3f" -dependencies = [ - "pallas-codec", - "pallas-crypto", - "pallas-primitives", - "pallas-traverse", - "pallas-validate", - "prost-types", - "utxorpc-spec", -] - -[[package]] -name = "pallas-validate" -version = "1.0.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7928e627130c3055a8c0ffea59bbcd28d92689a6608e71bcbf139df9e847f2" -dependencies = [ - "chrono", - "hex", - "itertools 0.14.0", - "pallas-addresses", - "pallas-codec", - "pallas-crypto", - "pallas-primitives", - "pallas-traverse", - "pallas-uplc", - "serde", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.18", - "smallvec", - "windows-link", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pbjson" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" -dependencies = [ - "base64 0.21.7", - "serde", -] - -[[package]] -name = "pbjson-build" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" -dependencies = [ - "heck 0.5.0", - "itertools 0.13.0", - "prost", - "prost-types", -] - -[[package]] -name = "pbjson-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" -dependencies = [ - "bytes", - "chrono", - "pbjson", - "pbjson-build", - "prost", - "prost-build", - "serde", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pest" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" -dependencies = [ - "memchr", - "miette", - "serde", - "serde_json", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "pest_meta" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" -dependencies = [ - "pest", - "sha2", -] - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.13.0", -] - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" -dependencies = [ - "heck 0.5.0", - "itertools 0.14.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.117", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "prost-types" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" -dependencies = [ - "prost", -] - -[[package]] -name = "psm" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8" -dependencies = [ - "ar_archive_writer", - "cc", -] - -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls 0.23.37", - "socket2 0.6.2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" -dependencies = [ - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls 0.23.37", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.6.2", - "tracing", - "windows-sys 0.60.2", -] - -[[package]] -name = "quote" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.14", - "regex-syntax 0.8.10", -] - -[[package]] -name = "regex-automata" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.7.5", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.10", -] - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "reqwest" -version = "0.12.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls 0.23.37", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tokio-rustls", - "tower 0.5.3", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 1.0.6", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rsa" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki 0.103.9", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - -[[package]] -name = "schannel" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "secp256k1" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" -dependencies = [ - "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" -dependencies = [ - "cc", -] - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" -dependencies = [ - "itoa", - "serde", - "serde_core", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.13.0", - "schemars 0.9.0", - "schemars 1.2.1", - "serde_core", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlformat" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" -dependencies = [ - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlx" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" -dependencies = [ - "ahash", - "atoi", - "byteorder", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashlink", - "hex", - "indexmap 2.13.0", - "log", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlformat", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tracing", - "url", - "webpki-roots 0.25.4", -] - -[[package]] -name = "sqlx-macros" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 1.0.109", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" -dependencies = [ - "dotenvy", - "either", - "heck 0.4.1", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 1.0.109", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" -dependencies = [ - "atoi", - "base64 0.21.7", - "bitflags", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand 0.8.5", - "rsa", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 1.0.69", - "tracing", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" -dependencies = [ - "atoi", - "base64 0.21.7", - "bitflags", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "rand 0.8.5", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 1.0.69", - "tracing", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" -dependencies = [ - "atoi", - "chrono", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "sqlx-core", - "tracing", - "url", - "urlencoding", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "stacker" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d74a23609d509411d10e2176dc2a4346e3b4aea2e7b1869f19fdedbc71c013" -dependencies = [ - "cc", - "cfg-if", - "libc", - "psm", - "windows-sys 0.59.0", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "supports-color" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" -dependencies = [ - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" - -[[package]] -name = "supports-unicode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" -dependencies = [ - "fastrand", - "getrandom 0.4.1", - "once_cell", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "terminal_size" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" -dependencies = [ - "rustix", - "windows-sys 0.60.2", -] - -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" -dependencies = [ - "unicode-linebreak", - "unicode-width 0.2.2", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl 2.0.18", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "time" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.49.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.6.2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls 0.23.37", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tonic" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "rustls-native-certs", - "rustls-pemfile 2.2.0", - "socket2 0.5.10", - "tokio", - "tokio-rustls", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower 0.5.3", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata 0.4.14", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tx3-dashboard" -version = "0.1.0" -dependencies = [ - "anyhow", - "axum", - "chrono", - "dotenvy", - "hex", - "pallas", - "reqwest", - "serde", - "serde_json", - "sqlx", - "tokio", - "tracing", - "tracing-subscriber", - "tx3-lang", - "tx3-resolver", - "tx3-tir", - "utxorpc", -] - -[[package]] -name = "tx3-lang" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd202b206b66f6450ebb9f95955daf7ee8085dc241714e0823dcf4e3e03a12a" -dependencies = [ - "ciborium", - "hex", - "miette", - "pest", - "pest_derive", - "serde", - "thiserror 2.0.18", - "trait-variant", - "tx3-tir", -] - -[[package]] -name = "tx3-resolver" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d296895880dff1773795e1b13bf5856bca5caf7a17477ee1bac1f933311a3243" -dependencies = [ - "approx", - "base64 0.22.1", - "bech32 0.11.1", - "hex", - "serde", - "serde_json", - "thiserror 2.0.18", - "trait-variant", - "tx3-tir", -] - -[[package]] -name = "tx3-tir" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deaa2d2699347b0b75f8d06a08714cf68709812145cd50190b49c30bc9945541" -dependencies = [ - "ciborium", - "hex", - "serde", - "thiserror 2.0.18", -] - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-normalization" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utxorpc" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7693fb6cd3db60ea90f87a4445d0fc572dd8bbdb541fc68a32337c0a275e44" -dependencies = [ - "bytes", - "thiserror 2.0.18", - "tokio", - "tonic", - "utxorpc-spec", -] - -[[package]] -name = "utxorpc-spec" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e59de89d0dfd8e594377b53a8f67a10de01bb63b15b169248760188fa06fb92a" -dependencies = [ - "bytes", - "futures-core", - "pbjson", - "pbjson-types", - "prost", - "prost-types", - "serde", - "tonic", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a89f4650b770e4521aa6573724e2aed4704372151bd0de9d16a3bbabb87441a" -dependencies = [ - "cfg-if", - "futures-util", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.117", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.13.0", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.13.0", - "semver", -] - -[[package]] -name = "web-sys" -version = "0.3.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705eceb4ce901230f8625bd1d665128056ccbe4b7408faa625eec1ba80f59a97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "whoami" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.13.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.13.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/backend/Cargo.toml b/backend/Cargo.toml deleted file mode 100644 index a43c663..0000000 --- a/backend/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "tx3-dashboard" -version = "0.1.0" -edition = "2024" - -[dependencies] -anyhow = "1.0" -axum = "0.7" -chrono = { version = "0.4", features = ["serde"] } -dotenvy = "0.15" -hex = "0.4" -reqwest = { version = "0.12", features = ["json", "rustls-tls"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite", "json", "macros", "chrono"] } -tokio = { version = "1", features = ["full"] } -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } -utxorpc = "0.13" -pallas = { version = "1.0.0-alpha.4", features = ["hardano", "phase2"] } -tx3-lang = "0.15.1" -tx3-tir = "0.15.1" -tx3-resolver = "0.15.1" diff --git a/backend/README.md b/backend/README.md deleted file mode 100644 index 2d9d9f3..0000000 --- a/backend/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Backend Service - -This backend ingests Cardano transactions via utxorpc, normalizes them into SQLite, and serves aggregated data to the dashboard through a simple HTTP API. - -## Environment variables - -Use `backend/.env.example` as a starting point. The variables below are required for the backend to run: - -```env -SERVER_ADDR="0.0.0.0:3000" - -DATABASE_PATH="./dashboard.db" - -REGISTRY_URL="https://api.tx3.land/graphql" - -U5C_URL="" -U5C_API_KEY="" - -PROTOCOL_SCOPE="buidler-fest" -PROTOCOL_NAME="ticketing-2026" -PROTOCOL_PARAMETERS='{"env":{"issuer_beacon_policy":"e1ddde8138579e255482791d9fba0778cb1f5c7b435be7b3e42069de","issuer_beacon_name":"425549444c45524645535432303236","ticket_policy":"1d9c0b541adc300c19ddc6b9fb63c0bfe32b1508305ba65b8762dc7b","issuer_script_ref":"31596ecbdcf102c8e5c17e75c65cf9780996285879d18903f035964f3a7499a8#0","ticket_price":500000000},"parties":{"treasury":"addr1qx0decp93g2kwym5cz0p68thamd2t9pehlxqe02qae5r6nycv42qmjppm2rr8fj6qlzfhm6ljkd5f0tjlgudtmt5kzyqmy8x82","issuer":"addr1wywecz65rtwrqrqemhrtn7mrczl7x2c4pqc9hfjmsa3dc7cr5pvqw"},"txs":{"buy_ticket":{}}}' - -TXS="d03abcb194238e97b78fde2ad23965150fdf72b156731759b60f7d493836adbc,26741de9ee337aa24ebeea078832a901c4deacce261e142a23186b1691513863,31596ecbdcf102c8e5c17e75c65cf9780996285879d18903f035964f3a7499a8" -``` - -## Setup - -1. Install Rust (stable toolchain). -2. Copy `.env.example` to `.env` and update values. -3. Ensure `DATABASE_PATH` points to a writable location. - -## Run - -```bash -cargo run -``` - -Optional build only: - -```bash -cargo build -``` diff --git a/backend/src/api.rs b/backend/src/api.rs deleted file mode 100644 index 173e217..0000000 --- a/backend/src/api.rs +++ /dev/null @@ -1,45 +0,0 @@ -use axum::{extract::{Path, Query, State}, http::StatusCode, Json}; -use serde::Deserialize; - -use crate::db; - -#[derive(Clone)] -pub struct ApiState { - pub sqlite_client: sqlx::SqlitePool, -} - -#[derive(Debug, Deserialize)] -pub struct ListParams { - pub limit: Option, -} - -pub async fn list_txs( - State(state): State, - Query(params): Query, -) -> Result>, StatusCode> { - let limit = params.limit.unwrap_or(100).clamp(1, 500); - let rows = db::list_txs(&state.sqlite_client, limit) - .await - .map_err(|error| { - tracing::error!(error = %error, "Failed to list txs"); - StatusCode::INTERNAL_SERVER_ERROR - })?; - Ok(Json(rows)) -} - -pub async fn get_tx( - State(state): State, - Path(tx_hash): Path, -) -> Result, StatusCode> { - let row = db::get_tx(&state.sqlite_client, &tx_hash) - .await - .map_err(|error| { - tracing::error!(error = %error, tx_hash = %tx_hash, "Failed to get tx"); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - match row { - Some(value) => Ok(Json(value)), - None => Err(StatusCode::NOT_FOUND), - } -} diff --git a/backend/src/blockfrost.rs b/backend/src/blockfrost.rs deleted file mode 100644 index e539d38..0000000 --- a/backend/src/blockfrost.rs +++ /dev/null @@ -1,113 +0,0 @@ -use anyhow::Result; -use reqwest::Client; -use serde::Deserialize; - -use crate::db; -use crate::registry::Protocol; -use crate::config::Config; - -#[derive(Debug, Deserialize)] -pub struct BlockfrostResponse { - pub hash: String, - pub inputs: Vec, - pub outputs: Vec, -} - -#[derive(Debug, Deserialize)] -pub struct BlockfrostInput { - pub address: String, - pub tx_hash: String, - pub output_index: u32, - pub amount: Vec, - pub inline_datum: Option, -} - -#[derive(Debug, Deserialize)] -pub struct BlockfrostOutput { - pub address: String, - pub output_index: u32, - pub amount: Vec, - pub inline_datum: Option, - pub consumed_by_tx: Option, -} - -#[derive(Debug, Deserialize)] -pub struct BlockfrostAmount { - pub unit: String, - pub quantity: String, -} - -fn get_matching_protocol_tx(tx: &BlockfrostResponse, protocol: &Protocol) -> Option { - for protocol_tx in &protocol.txs { - let inputs_match = protocol_tx.inputs.iter().all(|input| { - tx.inputs.iter().any(|tx_input| { - tx_input.address == *input - }) - }); - - let outputs_match = protocol_tx.outputs.iter().all(|output| { - tx.outputs.iter().any(|tx_output| { - tx_output.address == *output - }) - }); - - if inputs_match && outputs_match { - return Some(protocol_tx.name.clone()); - } - } - - None -} - -async fn process_tx( - config: &Config, - http_client: &Client, - sqlite_client: &sqlx::SqlitePool, - protocol: &Protocol, - tx_hash: &str -) -> Result<()> { - let url = format!( - "{}/txs/{}/utxos", - config.blockfrost_url, - tx_hash - ); - - let response = http_client - .get(&url) - .send() - .await?; - - if !response.status().is_success() { - let status = response.status(); - let body = response.text().await.unwrap_or_default(); - tracing::error!(status = %status, body = %body, "Blockfrost query failed"); - return Ok(()); - } - - let blockfrost_response: BlockfrostResponse = response.json().await?; - - // TODO: Move the filtering logic to the utxorpc listener - let tx_name = get_matching_protocol_tx(&blockfrost_response, protocol); - if let Some(tx_name) = tx_name { - tracing::info!(tx_hash = %tx_hash, tx_name = %tx_name, "Saving tx"); - db::insert_tx(sqlite_client, &tx_name, &blockfrost_response).await?; - } else { - tracing::info!(tx_hash = %tx_hash, "No matching protocol tx found"); - } - - Ok(()) -} - -pub async fn process_txs( - config: &Config, - sqlite_client: &sqlx::SqlitePool, - protocol: &Protocol, -) -> Result<()> { - let http_client = Client::new(); - - for tx_hash in &config.txs { - process_tx(config, &http_client, sqlite_client, protocol, tx_hash).await?; - } - - Ok(()) -} diff --git a/backend/src/config.rs b/backend/src/config.rs deleted file mode 100644 index 1a36187..0000000 --- a/backend/src/config.rs +++ /dev/null @@ -1,62 +0,0 @@ -use anyhow::{Context, Result}; -use serde_json::Value as JsonValue; - -#[derive(Clone, Debug)] -pub struct Config { - pub registry_url: String, - pub protocol_scope: String, - pub protocol_name: String, - pub protocol_parameters: JsonValue, - pub u5c_url: String, - pub u5c_api_key: Option, - pub database_path: String, - pub txs: Vec, - pub server_addr: String, - pub blockfrost_url: String, -} - -impl Config { - pub fn from_env() -> Result { - dotenvy::dotenv().ok(); - - let registry_url = get_env("REGISTRY_URL")?; - let protocol_scope = get_env("PROTOCOL_SCOPE")?; - let protocol_name = get_env("PROTOCOL_NAME")?; - let protocol_parameters = serde_json::from_str(&get_env_optional("PROTOCOL_PARAMETERS").unwrap_or_else(|| "{}".to_string()))?; - let u5c_url = get_env("U5C_URL")?; - let database_path = get_env("DATABASE_PATH")?; - let u5c_api_key = get_env_optional("U5C_API_KEY"); - let server_addr = get_env_optional("SERVER_ADDR").unwrap_or_else(|| "0.0.0.0:3000".to_string()); - let blockfrost_url = get_env("BLOCKFROST_URL")?; - let txs = get_env_optional("TXS") - .map(|value| { - value - .split(',') - .map(|item| item.trim().to_string()) - .filter(|item| !item.is_empty()) - .collect::>() - }) - .unwrap_or_default(); - - Ok(Self { - registry_url, - protocol_scope, - protocol_name, - protocol_parameters, - u5c_url, - u5c_api_key, - database_path, - txs, - server_addr, - blockfrost_url - }) - } -} - -fn get_env(key: &str) -> Result { - std::env::var(key).with_context(|| format!("Missing env var: {key}")) -} - -fn get_env_optional(key: &str) -> Option { - std::env::var(key).ok().filter(|value| !value.is_empty()) -} diff --git a/backend/src/db.rs b/backend/src/db.rs deleted file mode 100644 index f3a11b3..0000000 --- a/backend/src/db.rs +++ /dev/null @@ -1,365 +0,0 @@ -use anyhow::{Context, Result}; -use sqlx::{QueryBuilder, SqlitePool}; -use std::collections::{HashMap, HashSet}; - -use crate::blockfrost::BlockfrostResponse; - -#[derive(Debug, Clone, serde::Serialize)] -pub struct TxResponse { - pub hash: String, - pub tx_name: String, - pub inputs: Vec, - pub outputs: Vec, -} - -#[derive(Debug, Clone, serde::Serialize)] -pub struct Utxo { - pub address: String, - pub tx_hash: String, - pub output_index: u32, - pub amount: Vec, - pub datum: Option, - pub consumed_by_tx: Option, -} - -#[derive(Debug, Clone, serde::Serialize)] -pub struct Amount { - pub unit: String, - pub quantity: String, -} - -#[derive(Debug, sqlx::FromRow)] -struct TxRow { - pub hash: String, - pub tx_name: String, -} - -#[derive(Debug, sqlx::FromRow)] -struct UtxoRow { - pub tx_hash: String, - pub output_index: i64, - pub address: String, - pub consumed_by_tx: Option, - pub datum: Option, -} - -#[derive(Debug, sqlx::FromRow)] -struct AmountRow { - pub tx_hash: String, - pub output_index: i64, - pub unit: String, - pub quantity: String, -} - -pub async fn init_db(pool: &SqlitePool) -> Result<()> { - sqlx::query( - r#" - CREATE TABLE IF NOT EXISTS txs ( - hash TEXT PRIMARY KEY, - tx_name TEXT NOT NULL, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP - ) - "#, - ) - .execute(pool) - .await?; - - sqlx::query( - r#" - CREATE TABLE IF NOT EXISTS utxos ( - tx_hash TEXT NOT NULL, - output_index INTEGER NOT NULL, - address TEXT NOT NULL, - consumed_by_tx TEXT, - datum TEXT, - PRIMARY KEY (tx_hash, output_index) - ) - "#, - ) - .execute(pool) - .await?; - - sqlx::query( - r#" - CREATE TABLE IF NOT EXISTS utxo_amount ( - tx_hash TEXT NOT NULL, - output_index INTEGER NOT NULL, - unit TEXT NOT NULL, - quantity TEXT NOT NULL, - PRIMARY KEY (tx_hash, output_index, unit) - ) - "#, - ) - .execute(pool) - .await?; - - Ok(()) -} - -pub async fn insert_tx(pool: &SqlitePool, tx_name: &str, response: &BlockfrostResponse) -> Result<()> { - let mut tx = pool.begin().await?; - - sqlx::query( - r#" - INSERT INTO txs (hash, tx_name) - VALUES (?, ?) - ON CONFLICT (hash) DO NOTHING - "#, - ) - .bind(&response.hash) - .bind(tx_name) - .execute(&mut *tx) - .await?; - - for input in &response.inputs { - sqlx::query( - r#" - INSERT INTO utxos (tx_hash, output_index, address, consumed_by_tx, datum) - VALUES (?, ?, ?, ?, ?) - ON CONFLICT (tx_hash, output_index) DO UPDATE SET - address = excluded.address, - consumed_by_tx = COALESCE(utxos.consumed_by_tx, excluded.consumed_by_tx), - datum = COALESCE(utxos.datum, excluded.datum) - "#, - ) - .bind(&input.tx_hash) - .bind(i64::from(input.output_index)) - .bind(&input.address) - .bind(&response.hash) - .bind(&input.inline_datum) - .execute(&mut *tx) - .await?; - - for amount in &input.amount { - sqlx::query( - r#" - INSERT INTO utxo_amount (tx_hash, output_index, unit, quantity) - VALUES (?, ?, ?, ?) - ON CONFLICT (tx_hash, output_index, unit) DO UPDATE SET - quantity = excluded.quantity - "#, - ) - .bind(&input.tx_hash) - .bind(i64::from(input.output_index)) - .bind(&amount.unit) - .bind(&amount.quantity) - .execute(&mut *tx) - .await?; - } - } - - for output in &response.outputs { - sqlx::query( - r#" - INSERT INTO utxos (tx_hash, output_index, address, consumed_by_tx, datum) - VALUES (?, ?, ?, ?, ?) - ON CONFLICT (tx_hash, output_index) DO UPDATE SET - address = excluded.address, - consumed_by_tx = COALESCE(utxos.consumed_by_tx, excluded.consumed_by_tx), - datum = COALESCE(utxos.datum, excluded.datum) - "#, - ) - .bind(&response.hash) - .bind(i64::from(output.output_index)) - .bind(&output.address) - .bind(&output.consumed_by_tx) - .bind(&output.inline_datum) - .execute(&mut *tx) - .await?; - - for amount in &output.amount { - sqlx::query( - r#" - INSERT INTO utxo_amount (tx_hash, output_index, unit, quantity) - VALUES (?, ?, ?, ?) - ON CONFLICT (tx_hash, output_index, unit) DO UPDATE SET - quantity = excluded.quantity - "#, - ) - .bind(&response.hash) - .bind(i64::from(output.output_index)) - .bind(&amount.unit) - .bind(&amount.quantity) - .execute(&mut *tx) - .await?; - } - } - - tx.commit().await?; - - Ok(()) -} - -pub async fn list_txs(pool: &SqlitePool, limit: i64) -> Result> { - let rows: Vec = sqlx::query_as( - r#" - SELECT hash, tx_name - FROM txs - ORDER BY created_at DESC - LIMIT ? - "#, - ) - .bind(limit) - .fetch_all(pool) - .await?; - - if rows.is_empty() { - return Ok(vec![]); - } - - let hashes: Vec = rows.iter().map(|row| row.hash.clone()).collect(); - let utxos = fetch_utxos(pool, &hashes).await?; - let amounts = fetch_amounts(pool, &utxos).await?; - - build_responses(rows, utxos, amounts) -} - -pub async fn get_tx(pool: &SqlitePool, tx_hash: &str) -> Result> { - let row: Option = sqlx::query_as( - r#" - SELECT hash, tx_name - FROM txs - WHERE hash = ? - "#, - ) - .bind(tx_hash) - .fetch_optional(pool) - .await?; - - let Some(row) = row else { - return Ok(None); - }; - - let hashes = vec![row.hash.clone()]; - let utxos = fetch_utxos(pool, &hashes).await?; - let amounts = fetch_amounts(pool, &utxos).await?; - let mut responses = build_responses(vec![row], utxos, amounts)?; - - Ok(responses.pop()) -} - -async fn fetch_utxos(pool: &SqlitePool, hashes: &[String]) -> Result> { - if hashes.is_empty() { - return Ok(vec![]); - } - - let mut rows = fetch_utxos_by_column(pool, "tx_hash", hashes).await?; - rows.extend(fetch_utxos_by_column(pool, "consumed_by_tx", hashes).await?); - - let mut seen = HashSet::new(); - rows.retain(|row| seen.insert((row.tx_hash.clone(), row.output_index))); - - Ok(rows) -} - -async fn fetch_utxos_by_column( - pool: &SqlitePool, - column: &str, - hashes: &[String], -) -> Result> { - let mut builder = QueryBuilder::new( - "SELECT tx_hash, output_index, address, consumed_by_tx, datum FROM utxos WHERE ", - ); - - builder.push(column); - builder.push(" IN ("); - { - let mut separated = builder.separated(", "); - for hash in hashes { - separated.push_bind(hash); - } - } - builder.push(")"); - - let query = builder.build_query_as::(); - let rows = query.fetch_all(pool).await?; - - Ok(rows) -} - -async fn fetch_amounts(pool: &SqlitePool, utxos: &[UtxoRow]) -> Result> { - if utxos.is_empty() { - return Ok(vec![]); - } - - let mut tx_hashes = HashSet::new(); - let mut keys = HashSet::new(); - for utxo in utxos { - tx_hashes.insert(utxo.tx_hash.clone()); - keys.insert((utxo.tx_hash.clone(), utxo.output_index)); - } - - let mut builder = QueryBuilder::new( - "SELECT tx_hash, output_index, unit, quantity FROM utxo_amount WHERE tx_hash IN (", - ); - { - let mut separated = builder.separated(", "); - for tx_hash in &tx_hashes { - separated.push_bind(tx_hash); - } - } - builder.push(")"); - - let query = builder.build_query_as::(); - let rows = query.fetch_all(pool).await?; - - Ok(rows - .into_iter() - .filter(|row| keys.contains(&(row.tx_hash.clone(), row.output_index))) - .collect()) -} - -fn build_responses( - rows: Vec, - utxos: Vec, - amounts: Vec, -) -> Result> { - let mut amount_map: HashMap<(String, i64), Vec> = HashMap::new(); - for row in amounts { - let key = (row.tx_hash, row.output_index); - amount_map.entry(key).or_default().push(Amount { - unit: row.unit, - quantity: row.quantity, - }); - } - - let hash_set: HashSet = rows.iter().map(|row| row.hash.clone()).collect(); - let mut inputs_map: HashMap> = HashMap::new(); - let mut outputs_map: HashMap> = HashMap::new(); - - for row in utxos { - let output_index = u32::try_from(row.output_index) - .context("Invalid output_index value in database")?; - let key = (row.tx_hash.clone(), row.output_index); - let utxo = Utxo { - address: row.address, - tx_hash: row.tx_hash.clone(), - output_index, - amount: amount_map.get(&key).cloned().unwrap_or_default(), - datum: row.datum, - consumed_by_tx: row.consumed_by_tx.clone(), - }; - - if hash_set.contains(&row.tx_hash) { - outputs_map.entry(row.tx_hash.clone()).or_default().push(utxo.clone()); - } - - if let Some(consumed_by_tx) = row.consumed_by_tx { - if hash_set.contains(&consumed_by_tx) { - inputs_map.entry(consumed_by_tx).or_default().push(utxo); - } - } - } - - let responses = rows - .into_iter() - .map(|row| TxResponse { - hash: row.hash.clone(), - tx_name: row.tx_name, - inputs: inputs_map.remove(&row.hash).unwrap_or_default(), - outputs: outputs_map.remove(&row.hash).unwrap_or_default(), - }) - .collect(); - - Ok(responses) -} diff --git a/backend/src/main.rs b/backend/src/main.rs deleted file mode 100644 index 7e5bfa0..0000000 --- a/backend/src/main.rs +++ /dev/null @@ -1,76 +0,0 @@ -mod api; -mod config; -mod db; -mod registry; -mod utxorpc; -mod blockfrost; - -use anyhow::Result; -use axum::{routing::get, Router}; -use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; - -#[tokio::main] -async fn main() -> Result<()> { - tracing_subscriber::fmt() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .init(); - - let config = config::Config::from_env()?; - - let protocol = registry::fetch_protocol( - &config, - &config.protocol_scope, - &config.protocol_name, - ) - .await?; - - dbg!(&protocol); - - let connect_options = SqliteConnectOptions::new() - .filename(&config.database_path) - .create_if_missing(true); - - let sqlite_client = SqlitePoolOptions::new() - .max_connections(5) - .connect_with(connect_options) - .await?; - - db::init_db(&sqlite_client).await?; - - // TODO: Implement listening to blockchain transactions - // let utxorpc_listener = utxorpc::Listener { - // u5c_url: config.u5c_url.clone(), - // u5c_api_key: config.u5c_api_key.clone(), - // }; - // let utxorpc_listener_sqlite_client = sqlite_client.clone(); - // let utxorpc_listener_config = config.clone(); - // tokio::spawn(async move { - // if let Err(error) = utxorpc_listener - // .listen_txs( - // &utxorpc_listener_config, - // &utxorpc_listener_sqlite_client, - // &protocol, - // ) - // .await - // { - // tracing::error!(error = %error, "Listener failed"); - // } - // }); - - // TODO: Remove fixed transactions processing - blockfrost::process_txs(&config, &sqlite_client, &protocol).await?; - - let api_state = api::ApiState { - sqlite_client, - }; - let api_router = Router::new() - .route("/txs", get(api::list_txs)) - .route("/txs/:hash", get(api::get_tx)) - .with_state(api_state); - - let listener = tokio::net::TcpListener::bind(&config.server_addr).await?; - tracing::info!(addr = %config.server_addr, "HTTP server listening"); - axum::serve(listener, api_router).await?; - - Ok(()) -} diff --git a/backend/src/registry.rs b/backend/src/registry.rs deleted file mode 100644 index 601f269..0000000 --- a/backend/src/registry.rs +++ /dev/null @@ -1,252 +0,0 @@ -use anyhow::{Context, Result}; -use pallas::ledger::addresses::Address; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; - -use crate::config::Config; - -#[derive(Debug, Serialize)] -struct RegistryRequest<'a> { - query: &'a str, - variables: RegistryVariables<'a>, -} - -#[derive(Debug, Serialize)] -struct RegistryVariables<'a> { - scope: &'a str, - name: &'a str, -} - -#[derive(Debug, Deserialize)] -struct RegistryResponse { - data: Option, - errors: Option>, -} - -#[derive(Debug, Deserialize)] -struct RegistryResponseData { - protocol: Option, -} - -#[derive(Debug, Deserialize)] -struct RegistryProtocol { - source: String, -} - -#[derive(Debug, Deserialize)] -struct RegistryResponseError { - message: String, -} - -#[derive(Debug, Clone)] -pub struct Protocol { - pub txs: Vec, -} - -#[derive(Debug, Clone)] -pub struct ProtocolTx { - pub name: String, - pub inputs: Vec, - pub outputs: Vec, - pub mints: Vec, -} - - -#[derive(Debug, Clone)] -pub struct ProtocolTxMint { - pub policy: String, -} - -fn parse_type_name(type_name: &str) -> Result { - use tx3_resolver::Type; - - let ty = match type_name { - "Undefined" => Type::Undefined, - "Unit" => Type::Unit, - "Int" => Type::Int, - "Bool" => Type::Bool, - "Bytes" => Type::Bytes, - "Address" => Type::Address, - "Utxo" => Type::Utxo, - "UtxoRef" => Type::UtxoRef, - "AnyAsset" => Type::AnyAsset, - "List" => Type::List, - "Map" => Type::Map, - other => Type::Custom(other.to_string()), - }; - - Ok(ty) -} - -fn map_protocol_tx(config: &Config, env: &tx3_tir::reduce::ArgMap, tx: &tx3_lang::ast::TxDef) -> Result { - let tx_name = tx.name.value.clone(); - - let parameter_types: HashMap = tx - .parameters - .parameters - .iter() - .map(|param| (param.name.value.clone(), param.r#type.to_string())) - .collect(); - - let mut parameters = tx3_tir::reduce::ArgMap::new(); - if let Some(txs) = config.protocol_parameters.get("txs") { - if let Some(tx_params) = txs.get(&tx_name) { - for (key, value) in tx_params.as_object().context("Protocol parameters must be a JSON object")? { - if let Some(type_name) = parameter_types.get(key) { - let arg_value = tx3_resolver::interop::from_json(value.clone(), &parse_type_name(type_name)?)?; - parameters.insert(key.to_string(), arg_value); - } - } - } - } - - let lower = tx3_lang::lowering::lower_tx(tx)?; - - let mut inputs = Vec::new(); - for input in &lower.inputs { - if let tx3_tir::model::v1beta0::Expression::EvalParam(param) = &input.utxos { - if let tx3_tir::model::v1beta0::Param::ExpectInput(_, query) = param.as_ref() { - if let tx3_tir::model::v1beta0::Expression::EvalParam(param) = &query.address { - if let tx3_tir::model::v1beta0::Param::ExpectValue(input_name, _) = param.as_ref() { - if let Some(value) = env.get(input_name) { - if let tx3_tir::reduce::ArgValue::Address(bytes) = value { - let address = Address::from_bytes(bytes)?; - inputs.push(address.to_bech32()?); - } - } else if let Some(value) = parameters.get(input_name) { - if let tx3_tir::reduce::ArgValue::Address(bytes) = value { - let address = Address::from_bytes(bytes)?; - inputs.push(address.to_bech32()?); - } - } - } - } - } - } - } - - let mut outputs = Vec::new(); - for output in &lower.outputs { - if let tx3_tir::model::v1beta0::Expression::EvalParam(param) = &output.address { - if let tx3_tir::model::v1beta0::Param::ExpectValue(output_name, _) = param.as_ref() { - if let Some(value) = env.get(output_name) { - if let tx3_tir::reduce::ArgValue::Address(bytes) = value { - let address = Address::from_bytes(bytes)?; - outputs.push(address.to_bech32()?); - } - } else if let Some(value) = parameters.get(output_name) { - if let tx3_tir::reduce::ArgValue::Address(bytes) = value { - let address = Address::from_bytes(bytes)?; - outputs.push(address.to_bech32()?); - } - } - } - } - } - - let mut mints = Vec::new(); - for mint in &lower.mints { - if let tx3_tir::model::v1beta0::Expression::Assets(assets) = &mint.amount { - for asset in assets { - if let tx3_tir::model::v1beta0::Expression::EvalParam(param) = &asset.policy { - if let tx3_tir::model::v1beta0::Param::ExpectValue(policy_name, _) = param.as_ref() { - if let Some(value) = env.get(policy_name) { - if let tx3_tir::reduce::ArgValue::Bytes(bytes) = value { - mints.push(ProtocolTxMint { policy: hex::encode(bytes) }); - } - } else if let Some(value) = parameters.get(policy_name) { - if let tx3_tir::reduce::ArgValue::Bytes(bytes) = value { - mints.push(ProtocolTxMint { policy: hex::encode(bytes) }); - } - } - } - } - } - } - } - - Ok(ProtocolTx { - name: tx_name, - inputs, - outputs, - mints, - }) -} - -pub async fn fetch_protocol( - config: &Config, - protocol_scope: &str, - protocol_name: &str, -) -> Result { - let client = Client::new(); - - let request = RegistryRequest { - query: "query($scope: String!, $name: String!) { protocol(scope: $scope, name: $name) { source } }", - variables: RegistryVariables { - scope: protocol_scope, - name: protocol_name, - }, - }; - - let response = client - .post(&config.registry_url) - .json(&request) - .send() - .await - .context("Registry request failed")?; - - let payload: RegistryResponse = response.json().await.context("Invalid JSON response")?; - - if let Some(errors) = payload.errors { - let message = errors - .into_iter() - .map(|error| error.message) - .collect::>() - .join("; "); - return Err(anyhow::anyhow!("Registry error: {message}")); - } - - let source = payload - .data - .and_then(|data| data.protocol) - .map(|protocol| protocol.source) - .context("Missing protocol source in registry response")?; - - let mut program = tx3_lang::parsing::parse_string(&source)?; - - tx3_lang::analyzing::analyze(&mut program).ok()?; - - let env = program - .env - .and_then(|env| { - Some(env.fields.iter() - .map(|field| (field.name.clone(), field.r#type.to_string())) - .collect::>()) - }) - .unwrap_or_default(); - - let mut parameters = tx3_tir::reduce::ArgMap::new(); - if let Some(env_params) = config.protocol_parameters.get("env") { - for (key, value) in env_params.as_object().context("Protocol parameters must be a JSON object")? { - if let Some(type_name) = env.get(key) { - let arg_value = tx3_resolver::interop::from_json(value.clone(), &parse_type_name(type_name)?)?; - parameters.insert(key.to_string(), arg_value); - } - } - } - if let Some(parties_values) = config.protocol_parameters.get("parties") { - for (key, value) in parties_values.as_object().context("Protocol parameters must be a JSON object")? { - let arg_value = tx3_resolver::interop::from_json(value.clone(), &tx3_resolver::Type::Address)?; - parameters.insert(key.to_string(), arg_value); - } - } - - let txs = program - .txs - .iter() - .map(|tx| map_protocol_tx(&config, ¶meters, tx)) - .collect::>>()?; - - Ok(Protocol { txs }) -} diff --git a/backend/src/utxorpc.rs b/backend/src/utxorpc.rs deleted file mode 100644 index 9d984ac..0000000 --- a/backend/src/utxorpc.rs +++ /dev/null @@ -1,48 +0,0 @@ -use anyhow::{Context, Result}; -use serde_json::Value as JsonValue; -use pallas::codec::{ - minicbor, - utils::{Bytes, NonEmptySet, KeepRaw}, -}; -use pallas::ledger::{ - addresses::Address, - primitives::{PlutusData, conway::VKeyWitness}, - traverse::MultiEraTx, -}; -use utxorpc::{ - ClientBuilder, - CardanoQueryClient, - CardanoSubmitClient, - NativeBytes, - spec::cardano::{AddressPattern, TxOutputPattern}, -}; - -use crate::db; -use crate::registry::Protocol; -use crate::config::Config; - -pub struct Listener { - pub u5c_url: String, - pub u5c_api_key: Option, -} - -impl Listener { - pub async fn listen_txs( - &self, - config: &Config, - sqlite_client: &sqlx::SqlitePool, - protocol: &Protocol, - ) -> Result<()> { - let mut client_builder = ClientBuilder::new().uri(&self.u5c_url)?; - - if let Some(u5c_api_key) = &self.u5c_api_key { - client_builder = client_builder.metadata("dmtr-api-key", u5c_api_key.clone())?; - } - - let mut client = client_builder.build::().await; - - // TODO: Implement listening to blockchain transactions - - Ok(()) - } -} diff --git a/docs/access-patterns.md b/docs/access-patterns.md new file mode 100644 index 0000000..bebb5cb --- /dev/null +++ b/docs/access-patterns.md @@ -0,0 +1,65 @@ +# Access patterns + +The MVP defines two read-only access patterns against the tracker's `matches` table. Both run inside TanStack Start's `createServerFn` (Nitro side, never in the browser) and return typed rows via Kysely plus a manually-typed view of the parsed `lifted` JSON. + +## Summary + +| ID | Pattern | Function | Used by | SQL | +|----|---------|----------|---------|-----| +| AP-1 | Recent matches list | `listMatches(db, limit)` | `/` (matches list) | `SELECT id, tx_hash, tx_name, block_slot, lifted, matched_at FROM matches ORDER BY id DESC LIMIT ?` | +| AP-2 | Single match detail | `getMatch(db, txHashHex)` | `/txs/$hash` (detail) | `SELECT id, tx_hash, tx_name, block_slot, lifted, matched_at FROM matches WHERE tx_hash = ? LIMIT 1` | + +Both functions live in [`frontend/src/lib/queries.ts`](../frontend/src/lib/queries.ts). The shared `MatchRow` shape returned to the route loader is: + +```ts +export interface MatchRow { + readonly id: number; + readonly hash: string; // hex-encoded tx_hash + readonly txName: string; + readonly protocolName: string; + readonly profileName: string; + readonly blockSlot: number; + readonly matchedAt: Date; + readonly parties: Record; + readonly rawLifted: string; +} +``` + +`LiftedParty` (from `lib/lifted.ts`) carries the named address bytes re-encoded as a hex string and the role (`Input` / `Output`) the lifter recorded. bech32 rendering is intentionally deferred for the MVP. + +## AP-1 — `listMatches` + +Returns the most recent matches across all sources, newest first. Used by the matches list at `/`. + +```ts +async function listMatches( + db: Kysely, + limit: number = 50, +): Promise +``` + +`limit` defaults to 50 and is clamped to `[1, 200]` to keep page sizes bounded. The query selects `id, tx_hash, block_slot, protocol_name, profile_name, tx_name, lifted, matched_at`, orders by `id DESC` (the tracker's monotonic insertion order), and applies `LIMIT ?`. Each row is mapped to a `MatchRow` with `tx_hash` re-encoded as hex and `lifted` parsed into typed parties. + +## AP-2 — `getMatch` + +Returns a single match by its hex-encoded `tx_hash`, or `null` if not found. Used by the detail page at `/txs/$hash`. + +```ts +async function getMatch( + db: Kysely, + txHashHex: string, +): Promise +``` + +The function validates that `txHashHex` is an even-length hex string, decodes it to a `Buffer`, and runs `WHERE tx_hash = ? LIMIT 1`. The `(tx_hash, source_name)` unique index on the tracker side means at most one row per source per hash; for the single-source MVP, one row per hash. + +## Deferred patterns + +These were scoped out of the MVP and are listed here for future iterations: + +- **Activity Overview / time series** — aggregate counts of matches per `tx_name` over time, suitable for a small dashboard chart. +- **Accounts (Address explorer)** — given an address, list every match that involved it as a party. +- **Script Execution Log** — surface decoded script inputs and witnesses from the `lifted` JSON for protocol developers in debug mode. +- **Anomalies / alerts** — surface gaps in the cursor, unexpectedly long matched-at intervals, or matches that fail the lifter post-hoc. + +Each of these is feasible against the same `matches` table without schema changes; they were deferred to keep the M3 surface narrow. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..7c1ec06 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,84 @@ +# Architecture + +The tx3 Dashboard is a pure TypeScript application that observes the output of an external `tx3-lift` tracker. The tracker subscribes to a Cardano `utxorpc` stream, matches incoming transactions against a TII, and writes one row per match into a local SQLite file. The dashboard reads that same file via Kysely + better-sqlite3 from inside Nitro server functions and renders matches in the browser. + +## System context (C4 L1) + +```mermaid +C4Context +title System Context — tx3 Dashboard + +Person(operator, "Builder / Operator", "Runs the dashboard for their own dApp") +System(dashboard, "tx3 Dashboard", "Tracker (sidecar) + SSR app that monitor a Tx3-described dApp") +System_Ext(utxorpc, "utxorpc Provider", "Cardano chain stream (v1beta WatchTx)") +System_Ext(registry, "Tx3 Registry", "Source of TII files (queried at vendor time, not runtime)") + +Rel(operator, dashboard, "Views matched transactions", "HTTPS") +Rel(dashboard, utxorpc, "Subscribes to tx stream", "gRPC / TLS") +Rel(operator, registry, "Pulls TII once at vendor time", "GraphQL") +``` + +## Containers (C4 L2) + +```mermaid +C4Container +title Container Diagram — tx3 Dashboard + +Person(operator, "Builder / Operator") +System_Ext(utxorpc, "utxorpc Provider", "v1beta WatchTx") + +Container_Boundary(c1, "tx3 Dashboard") { + Container(tracker, "Tracker", "Rust binary — tx3-lift", "Subscribes, matches against TII, lifts, persists each match") + ContainerDb(db, "tracker.db", "SQLite + WAL", "matches and cursor tables; tracker writes, dashboard reads") + Container(ssr, "Dashboard SSR", "TanStack Start (Node / Nitro)", "Server-rendered React; queries the DB via Kysely") + Container(browser, "Browser UI", "React + Tailwind + shadcn", "Renders matches list and detail") +} + +Rel(operator, browser, "Uses", "HTTPS") +Rel(browser, ssr, "Loads pages", "HTTPS") +Rel(utxorpc, tracker, "Streams Apply / Undo / Idle", "gRPC") +Rel(tracker, db, "INSERT match, advance cursor") +Rel(ssr, db, "SELECT matches", "Kysely + better-sqlite3") + +UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1") +``` + +The tracker and the dashboard are **decoupled at the SQLite file**. WAL mode (enabled by the tracker on first connect) lets the dashboard's reader run concurrently with the tracker's writer without blocking. + +## Data flow per page load + +```mermaid +sequenceDiagram + participant B as Browser + participant N as Nitro server fn + participant K as Kysely + participant S as SQLite (tracker.db) + + B->>N: GET / (or /txs/) + N->>K: listMatches({ limit }) / getMatch(txHash) + K->>S: SELECT ... FROM matches ... + S-->>K: rows (tx_hash blob, lifted JSON, ...) + K-->>N: typed rows + N-->>B: SSR HTML with matches +``` + +Each server function opens a fresh Kysely instance per request and destroys it in a `finally` block. better-sqlite3 opens the file read-only with no connection-pool overhead, so the per-request lifecycle is cheap; the dashboard never writes. + +## Component responsibilities + +- **Tracker** (Rust binary from [`tx3-lang/tx3-lift`](https://github.com/tx3-lang/tx3-lift), run as a sidecar): subscribes to the configured `utxorpc` stream, applies the `Fingerprint → Match → Lift` pipeline against the TII, and inserts one row into `matches` for each match. Owns the schema and the cursor. +- **Dashboard SSR** (this repo, `frontend/`): a TanStack Start app that opens `tracker.db` read-only inside Nitro server functions. `lib/db.ts` builds a Kysely instance, `lib/queries.ts` exposes `listMatches` and `getMatch`, `lib/lifted.ts` parses the small subset of the `lifted` JSON the MVP needs (parties + addresses). +- **SQLite (`tracker.db`)**: the integration boundary. WAL mode allows the writer (tracker) and the reader (dashboard) to run concurrently. The dashboard does not modify the schema, does not run migrations, and does not write rows. + +## Why this shape + +- **Single-purpose components.** The tracker is already battle-tested in `tx3-lift`. Embedding it as a library would re-litigate that. Running it as a sidecar lets it evolve in its own repo without ABI coupling. +- **Honest authority.** The tracker owns the schema; the dashboard observes. There is no risk of two implementations of the same schema drifting. +- **TanStack SSR is enough.** Nitro server functions can open SQLite directly. There is no use case in the MVP that needs a separate API tier, so we don't add one. +- **Trivial deployment.** Two processes — one is `cargo run`, the other is `pnpm build && node`. Operators can use tmux, systemd, pm2, or whatever else they prefer. + +## Forward-looking: Postgres + +The schema and access patterns are Postgres-portable. A future migration is split between the upstream tracker (1–3 days of upstream PR work to add a Postgres storage backend or replication path) and this repo (~half a day to swap `kysely`'s `SqliteDialect` for `PostgresDialect`, swap `better-sqlite3` for `pg`, and adjust the JSON path syntax in any `sql` template literals — a single helper module). + +See [§4.3 of the M3 design spec](superpowers/specs/2026-05-07-m3-dashboard-design.md#43-postgres-migration-plan-forward-looking-not-implemented) for the migration plan. diff --git a/docs/running.md b/docs/running.md new file mode 100644 index 0000000..d19536f --- /dev/null +++ b/docs/running.md @@ -0,0 +1,104 @@ +# Running the dashboard + +This guide walks you through running the tx3 Dashboard end-to-end against the committed `buidler-fest/ticketing-2026` demo on Cardano preview. + +## Prerequisites + +You'll need: + +- **Rust stable** (for building and running the tracker from `tx3-lang/tx3-lift`). +- **Node 24** (the version Nitro and TanStack Start are tested against in CI). +- **pnpm 10** — install with `npm install -g pnpm@10` or `corepack enable`. +- **A sibling clone of [`tx3-lang/tx3-lift`](https://github.com/tx3-lang/tx3-lift)** at `../tx3-lift` (relative to this repo). The dashboard does not embed the tracker; you run the tracker binary from that clone as a sidecar. +- **A `utxorpc` endpoint and API key.** The committed `tracker.toml` points at Demeter's Cardano preview endpoint; sign up at [demeter.run](https://demeter.run) for a free `dmtr_…` key. + +## Environment variables + +| Variable | Used by | Required | Default | Purpose | +|----------|---------|----------|---------|---------| +| `DMTR_API_KEY` | Tracker | Yes | — | Demeter API key for the configured `utxorpc` endpoint. The tracker fails to start without it. | +| `TRACKER_DB_PATH` | Dashboard | No | `./tracker.db` | Path the dashboard opens read-only. Leave unset to read the file the tracker writes alongside `tracker.toml`. | +| `RUST_LOG` | Tracker | No | (warn) | Log level for the tracker binary. `info` is comfortable for first-run; `debug` for protocol-level debugging. | + +## First run + +You'll need two terminals. From a fresh clone of this repo: + +```bash +# Once: clone the tx3-lift sibling +git clone https://github.com/tx3-lang/tx3-lift ../tx3-lift +``` + +```bash +# Terminal A — tracker +cd ../tx3-lift +DMTR_API_KEY=dmtr_... RUST_LOG=info \ + cargo run -p tracker -- ../dashboard/tracker.toml +``` + +```bash +# Terminal B — dashboard +cd dashboard/frontend +pnpm install +pnpm dev +``` + +Visit . The tracker writes `dashboard/tracker.db` (plus its `-wal` / `-shm` companion files); the dashboard reads from the same file. New matches appear after a page reload. + +## Production build + +For an operator-managed deployment without `vite dev`. From the repo root: + +```bash +cd dashboard/frontend +pnpm install +pnpm build +node .output/server/index.mjs +``` + +Set `TRACKER_DB_PATH` if `tracker.db` lives outside the working directory. The Nitro bundle binds to `:3000` by default; override with `PORT`. + +## Troubleshooting + +### Empty list at `/` + +The dashboard renders "No matches yet — confirm the tracker is running." If you're seeing it indefinitely: + +- Confirm the tracker terminal shows `Apply` events flowing in (or, on preview, that the protocol's policy filter actually matches recent on-chain activity). +- Confirm `tracker.db` exists in the dashboard working directory and is non-empty: `sqlite3 tracker.db 'SELECT COUNT(*) FROM matches;'`. +- Reload the page — the MVP does not auto-refresh. + +### `SQLITE_CANTOPEN` on dashboard startup + +The dashboard opens the DB with `fileMustExist: true`. If you see this error: + +- The tracker hasn't created the file yet. Start the tracker first, wait for it to log its first cursor advance, then start `pnpm dev`. +- `TRACKER_DB_PATH` points at a non-existent path. Unset it and let the default (`./tracker.db` relative to the dashboard CWD) take over, or pass an absolute path. +- The file exists but the dashboard process doesn't have read permission. Check ownership and mode. + +### Native build failure for `better-sqlite3` + +`better-sqlite3` ships with a native binding. On `pnpm install` you may see "Ignored build scripts: better-sqlite3" because the package was added to `pnpm.onlyBuiltDependencies` after first install. Fix it with: + +```bash +pnpm rebuild better-sqlite3 +``` + +If you're on a system without a working `node-gyp` toolchain, install the platform's build tools (`xcode-select --install` on macOS; `build-essential` + `python3` on Debian/Ubuntu). + +### Stale match after a chain rollback + +If the upstream chain rolls back past a slot the tracker had recorded, the tracker emits an `Undo` event and removes the affected rows. Reload the dashboard page — the now-deleted match will return a 404 from `getMatch`. The list view at `/` automatically reflects the rollback on the next request. + +## Tested with + +- `tx3-lang/tx3-lift` tracker commit: `04d0b90` (`docs: add integration test report (#8)`) +- Node 24, pnpm 10, Rust stable. + +## Deferred deployment polish + +These are out of scope for M3 and tracked for follow-up iterations: + +- **Docker compose** stack that runs both the tracker and the dashboard with a shared volume for `tracker.db`. +- **Service-manager units** (systemd / launchd / pm2 templates) committed alongside the repo for one-shot operator install. +- **Postgres backend** for the tracker (1–3 days upstream PR) plus the dashboard-side dialect swap (~half a day) — see [`architecture.md` § Forward-looking](architecture.md#forward-looking-postgres). diff --git a/docs/superpowers/plans/2026-05-07-m3-dashboard-implementation.md b/docs/superpowers/plans/2026-05-07-m3-dashboard-implementation.md new file mode 100644 index 0000000..31eed04 --- /dev/null +++ b/docs/superpowers/plans/2026-05-07-m3-dashboard-implementation.md @@ -0,0 +1,495 @@ +# M3 Dashboard Implementation Plan (v2) + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to execute this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Style:** declarative — each task specifies the public contract, the tests that must pass, and acceptance criteria; the implementer chooses the implementation. Code is shown literally only where it IS the artifact (SQL schema, TOML config, shell commands). + +**Goal:** Replace the M1 backend scaffold with a TanStack Start frontend that reads SQLite produced by the externally-run `tx3-lift` tracker. Ship two views (matches list + match detail) plus the documentation needed for an operator to run the system end-to-end. + +**Architecture:** Two-process topology — the tracker runs as a sidecar (built from `tx3-lang/tx3-lift`) and writes `tracker.db` (SQLite, WAL). The dashboard is a TanStack Start app whose Nitro server functions read that SQLite with Kysely + better-sqlite3. + +**Tech stack:** TypeScript, TanStack Start (Nitro SSR), TanStack Router, Tailwind 4, shadcn, Kysely, better-sqlite3, vitest, Biome, pnpm. + +--- + +## Spec reference + +Implements `docs/superpowers/specs/2026-05-07-m3-dashboard-design.md`. Two access patterns (AP-1 list, AP-2 detail), no Rust on the dashboard side, MVP scope. + +## Pre-conditions + +- Node 24 + pnpm 10 (matches frontend CI). +- `tx3-lang/tx3-lift` cloned at `../tx3-lift/` relative to this repo (used to run the tracker; not a build dependency of the dashboard). +- Rust stable (only needed to run the tracker). + +--- + +## File structure + +### Created + +``` +protocols/buidler-fest/ticketing-2026.tii committed fixture +tracker.toml tracker sidecar config +docs/architecture.md +docs/access-patterns.md +docs/running.md +frontend/src/lib/db.ts +frontend/src/lib/lifted.ts +frontend/src/lib/queries.ts +frontend/src/lib/__tests__/db.test.ts +frontend/src/lib/__tests__/lifted.test.ts +frontend/src/lib/__tests__/queries.test.ts +frontend/src/components/PartyChip.tsx +frontend/src/components/TxNamePill.tsx +``` + +### Modified + +- `README.md` — refreshed with C4 Context diagram + quick start. +- `.gitignore` — `tracker.db*` artifacts. +- `frontend/package.json` — adds Kysely + better-sqlite3. +- `frontend/src/components/Header.tsx` — slimmed. +- `frontend/src/routes/index.tsx` — rewritten as matches list. +- `frontend/src/routes/txs/$hash.tsx` — rewritten as match detail. +- `frontend/README.md` — slimmed. + +### Deleted + +- `backend/` (entire directory). +- `.github/workflows/backend-ci.yml`. +- `frontend/src/routes/txs/index.tsx`. + +--- + +## Tasks + +### Task 1: Remove the M1 backend scaffold + +**Goal:** delete the obsolete Rust backend and its CI; keep tracker artifacts out of git. + +**Files** +- Delete: `backend/`, `.github/workflows/backend-ci.yml` +- Modify: `.gitignore` — append `tracker.db`, `tracker.db-wal`, `tracker.db-shm` + +**Acceptance** +- `git ls-files backend/` and `git ls-files .github/workflows/backend-ci.yml` are empty. +- `(cd frontend && pnpm typecheck)` succeeds. +- A grep for `backend` in the surviving files turns up only documentation references that you've cleaned up (or none). + +**Commit:** `chore: remove M1 backend scaffold and its CI; v2 reads tracker SQLite directly` + +--- + +### Task 2: Vendor the demo TII and ship `tracker.toml` + +**Goal:** commit the buidler-fest TII fixture and the tracker config so an operator runs end-to-end with one extra clone. + +**Files** +- Create: `protocols/buidler-fest/ticketing-2026.tii` +- Create: `tracker.toml` (repo root) + +**TII fetch** (one-time vendor step): + +```bash +mkdir -p protocols/buidler-fest +curl -s -X POST https://api.tx3.land/graphql \ + -H 'content-type: application/json' \ + -d '{"query":"{ protocol(scope:\"buidler-fest\", name:\"ticketing-2026\") { tii } }"}' \ + | jq -r '.data.protocol.tii' \ + > protocols/buidler-fest/ticketing-2026.tii +``` + +If the registry returns the `tii` field as an inline JSON object (not a string), drop the `-r` and use `jq '.data.protocol.tii'`. Confirm: + +```bash +jq '.protocol.name, (.transactions | keys), (.profiles | keys)' protocols/buidler-fest/ticketing-2026.tii +``` +must print `"ticketing-2026"`, `["buy_ticket"]`, and a profile list including `"preview"`. + +**`tracker.toml` content** (literal): + +```toml +[upstream] +endpoint = "https://preview.utxorpc-v0.demeter.run" +intersect = "tip" +# api_key set via DMTR_API_KEY env + +[upstream.filter] +mints_policy_id = "4672f28ce36e492e722392359f71e9a9442646f81d856f92d7e163f1" + +[storage] +database_path = "./tracker.db" + +[[sources]] +name = "ticketing-2026-preview" +tii_path = "./protocols/buidler-fest/ticketing-2026.tii" +profile = "preview" +``` + +**Acceptance** +- `cd ../tx3-lift && cargo run -p tracker -- ../dashboard/tracker.toml` reaches the log line `subscribing to WatchTx endpoint=…` and creates `tracker.db` inside the dashboard repo. (Stop after one minute; full smoke is Task 12.) + +**Commit:** `feat: vendor ticketing-2026 TII and tracker.toml for the M3 demo` + +--- + +### Task 3: Frontend dependencies + +**Goal:** add Kysely + better-sqlite3 with the native build allowance pnpm requires. + +**Files**: `frontend/package.json`, `frontend/pnpm-lock.yaml`. + +**Steps** + +```bash +cd frontend +pnpm add kysely better-sqlite3 +pnpm add -D @types/better-sqlite3 +``` + +In `frontend/package.json`, append `"better-sqlite3"` to the existing `pnpm.onlyBuiltDependencies` array. + +**Acceptance** +- `pnpm install` finishes without `package … is not allowed to run scripts` warnings. +- `pnpm typecheck` succeeds. + +**Commit:** `feat(frontend): add kysely + better-sqlite3 for SSR data access` + +--- + +### Task 4: Database connection module + +**Goal:** typed read-only Kysely instance over `tracker.db`. Abstracts the file-vs-existing-instance choice for tests. + +**Files**: `frontend/src/lib/db.ts`, `frontend/src/lib/__tests__/db.test.ts`. + +**Public contract** + +```ts +interface MatchesRow { + id: number; + tx_hash: Buffer; + block_slot: number; + block_hash: Buffer; + source_name: string; + protocol_name: string; + tx_name: string; + profile_name: string; + lifted: string; + matched_at: number; +} +interface CursorRow { id: number; slot: number; block_hash: Buffer } +interface SchemaVersionRow { name: string; applied_at: number } +interface DashboardDatabase { + matches: MatchesRow; + cursor: CursorRow; + _schema_versions: SchemaVersionRow; +} + +createDb(opts?: { path?: string; existing?: BetterSqlite3.Database }): Kysely +``` + +**Behavior** +- `existing` provided → wrap it; do not open or pragma. Used by tests with `:memory:`. +- `path` provided → open `readonly: true`, `fileMustExist: true`. Set `journal_mode = WAL`. +- Neither → resolve path from `process.env.TRACKER_DB_PATH ?? './tracker.db'`, then open as above. + +**Tests** (`db.test.ts`) +- Build a `:memory:` connection seeded with the matches/cursor schema; pass it via `existing`; run a typed `selectFrom('matches').select('id').execute()`; expect `[]`. + +**Acceptance**: test passes; `pnpm typecheck` clean. + +**Commit:** `feat(frontend): Kysely-backed read-only connection to tracker.db` + +--- + +### Task 5: Lifted JSON types and helpers + +**Goal:** type the subset of `lifted` JSON the MVP renders and re-encode the byte-array fields the lifter writes (e.g. `address: [0x61, ...]`) into hex strings. + +**Files**: `frontend/src/lib/lifted.ts`, `frontend/src/lib/__tests__/lifted.test.ts`. + +**Public contract** + +```ts +interface LiftedParty { address: string; role: string } +interface Lifted { txName: string; parties: Record; raw: string } + +bytesToHex(bytes: number[]): string +truncateHex(hex: string, edge?: number): string // default edge = 6 +parseLifted(json: string): Lifted +``` + +**Behavior** +- `bytesToHex`: lowercase hex without `0x`. `[]` → `''`. Throws on non-integers or values outside `[0, 255]`. Error message contains the word "byte". +- `truncateHex(hex, edge)`: returns `hex` unchanged when `hex.length <= edge * 2`; otherwise `${hex.slice(0, edge)}…${hex.slice(-edge)}`. +- `parseLifted`: + - `JSON.parse` first (re-throws on invalid JSON). + - Reads `tx_name` (defaults to `''`). + - Iterates `parties` if present, skipping entries without an array `address`. Re-encodes `address` via `bytesToHex`. `role` is read as string (default `''`). + - Returns `{ txName, parties, raw: }`. + +**Tests** (`lifted.test.ts`) +- `bytesToHex([0xab, 0x01, 0xff])` → `'ab01ff'`. +- `bytesToHex([])` → `''`. +- `bytesToHex([300])` throws (`/byte/i`). +- `truncateHex('0123456789abcdef0123456789abcdef', 6)` → `'012345…abcdef'`. +- `truncateHex('abcd', 6)` → `'abcd'`. +- `parseLifted` with `tx_name: 'buy_ticket'` and parties `{ buyer: { address: [0x61, 0x12, 0x34], role: 'Input' }, treasury: { address: [0x61, 0xab], role: 'Output' } }` → `{ txName: 'buy_ticket', parties: { buyer: { address: '611234', role: 'Input' }, treasury: { address: '61ab', role: 'Output' } } }`. +- `parseLifted` without parties → `parties === {}`. +- `parseLifted('not json')` throws. + +**Acceptance**: 8 tests pass. + +**Commit:** `feat(frontend): lifted JSON parser + bytes-to-hex helpers` + +--- + +### Task 6: Queries — listMatches and getMatch + +**Goal:** implement AP-1 and AP-2 as typed Kysely queries returning a consumer-friendly shape. + +**Files**: `frontend/src/lib/queries.ts`, `frontend/src/lib/__tests__/queries.test.ts`. + +**Public contract** + +```ts +interface MatchRow { + id: number; + hash: string; // hex + txName: string; + protocolName: string; + profileName: string; + blockSlot: number; + matchedAt: Date; + parties: Record; + rawLifted: string; +} + +listMatches(db: Kysely, limit?: number): Promise +getMatch(db: Kysely, txHashHex: string): Promise +``` + +**Behavior** +- `listMatches`: `SELECT … FROM matches ORDER BY id DESC LIMIT ?`. Default `limit = 50`, clamped to `[1, 200]`. +- `getMatch`: `SELECT … FROM matches WHERE tx_hash = ? LIMIT 1`. Hex input must match `/^[0-9a-fA-F]+$/` and have even length — throw otherwise. Decode to `Buffer` for the bind. +- Both use `parseLifted` (Task 5) to populate `parties` and `rawLifted`. +- Both convert `matched_at` (unix seconds) to `Date`. + +**Tests** (`queries.test.ts`) +- Seed an in-memory SQLite with the schema from Task 4. Insert two rows: tx_hash `[0x01, 0x01]` (slot 100, matched_at 1700000000, lifted with parties `buyer→[0x61,0x01]`, `treasury→[0x61,0x02]`) and tx_hash `[0x02, 0x02]` (slot 110, matched_at 1700000050, parties `buyer→[0x61,0x02]`, `treasury→[0x61,0x03]`). +- `listMatches(db, 10)` → 2 rows newest-first; first row's `hash === '0202'`, `txName === 'buy_ticket'`, `parties.buyer.address === '6102'`, `matchedAt` equals `new Date(1700000050 * 1000)`. +- `listMatches(db, 1)` → 1 row. +- `getMatch(db, '0101')` → match where `parties.treasury.address === '6102'`. +- `getMatch(db, 'deadbeef')` → `null`. + +**Acceptance**: 4 tests pass. + +**Commit:** `feat(frontend): listMatches + getMatch queries` + +--- + +### Task 7: Reusable display components + +**Goal:** two small chip components used by both pages. + +**Files**: `frontend/src/components/PartyChip.tsx`, `frontend/src/components/TxNamePill.tsx`. + +**Public contract** + +```tsx +TxNamePill({ name: string }) +PartyChip({ name: string; address: string; role?: string }) +``` + +**Visual contract** +- `TxNamePill`: rounded pill, `bg-primary/10 text-primary`, small text size (xs), font-semibold. +- `PartyChip`: rounded pill with a 1.5×1.5 primary-color dot leading the row, party name (font-semibold), then address rendered through `truncateHex` in `font-mono text-muted-foreground`, then optional role suffix in tiny uppercase muted text. + +Use the existing palette tokens (`primary`, `muted-foreground`, `border`, `background`) — do not introduce new colors. + +**Acceptance**: `pnpm typecheck` clean. Visual eyeball happens via Tasks 8–9. + +**Commit:** `feat(frontend): PartyChip + TxNamePill display components` + +--- + +### Task 8: Matches list view at `/` + +**Goal:** replace the M1 placeholder with the AP-1 list. + +**Files**: `frontend/src/routes/index.tsx` (replace). + +**Behavior** +- Server function (`createServerFn({ method: 'GET' }).handler(...)`) opens a fresh `createDb()` per call, runs `listMatches(db, 50)`, calls `db.destroy()` in a `finally`. Returns `MatchRow[]` (must be JSON-serializable — `Date` is fine via TanStack Start's serialization). +- `Route.loader` invokes the server fn; component reads via `Route.useLoaderData()`. +- Render header: `

Matches

` + caption "N most recent" (right-aligned, `text-sm text-muted-foreground`). +- When `matches.length === 0`: empty-state card with the message *"No matches yet — confirm the tracker is running. See `docs/running.md`."* in a dashed-border box. +- Otherwise: a table with columns Tx (TxNamePill) · Hash (clickable `Link to /txs/$hash` with truncated hex) · Slot (`toLocaleString()`, monospace muted) · Parties (row of `PartyChip`s) · When (`matchedAt.toISOString().replace('T', ' ').slice(0, 19)`). + +**Acceptance** +- `pnpm dev` boots; `/` renders. +- Empty `tracker.db` → empty state. +- Populated `tracker.db` → rows display; clicking a hash navigates to `/txs/$hash`. + +**Commit:** `feat(frontend): matches list view at /` + +--- + +### Task 9: Match detail view at `/txs/$hash` + +**Goal:** replace the M1 placeholder with the AP-2 detail; remove the obsolete `/txs` index. + +**Files** +- Modify: `frontend/src/routes/txs/$hash.tsx` +- Delete: `frontend/src/routes/txs/index.tsx` + +**Behavior** +- Server function declared with `.validator((hash: string) => hash)` and `.handler(async ({ data: hash }) => {...})`. Body opens `createDb()`, runs `getMatch(db, hash)`, destroys in `finally`. Returns `MatchRow | null`. +- `Route.loader` calls the server fn passing `params.hash`; if result is `null`, throw TanStack Router's `notFound()`. +- Component renders: + - Header: TxNamePill + caption `${protocol_name} · ${profile_name} · slot ${block_slot.toLocaleString()}`, then the full hash in `font-mono text-sm break-all`, then `matched_at` (ISO, sliced to seconds) and a "back to list" `Link to "/"`. + - Parties section: heading `Parties (${count})`, then either a paragraph "No parties annotated for this match." (when empty) or a wrapped row of ``s for each entry of `parties`, passing `role`. + - Collapsible `
` titled "Raw lifted JSON (debug)" containing `JSON.stringify(JSON.parse(rawLifted), null, 2)` in a `
`.
+
+**Acceptance**
+- Following a row from `/` lands on the detail with parties filled.
+- Hitting an unknown hash returns 404 (TanStack Router handles `notFound()`).
+- The "Raw lifted JSON" accordion expands to valid pretty JSON.
+
+**Commit:** `feat(frontend): match detail view; remove /txs index`
+
+---
+
+### Task 10: Slim the Header
+
+**Goal:** drop the now-irrelevant Transactions nav link.
+
+**Files**: `frontend/src/components/Header.tsx`.
+
+**Final shape**: brand `Link to "/"`, a small "Matches view" caption (`text-xs text-muted-foreground`), `` pushed right via `ml-auto`. No `