Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
e1db5eb
feat: scaffold the API process with an honest discovery document
TaprootFreak Jul 29, 2026
df3c6f8
feat: add the kernel gRPC client and the §7.5 job surface
TaprootFreak Jul 31, 2026
f4cc16f
feat: add info, readiness and the chain read surface
TaprootFreak Jul 31, 2026
74662d6
feat: verify the ownership proof at the API edge, and add attest and …
TaprootFreak Jul 31, 2026
3bafd5e
feat: add pull, records, coin proofs and the account state read
TaprootFreak Jul 31, 2026
ae0dd78
feat: add the bootstrap endpoints and the publisher hand-off
TaprootFreak Jul 31, 2026
97354ea
docs: name the real prerequisite for grant verification (Nostr profil…
TaprootFreak Jul 31, 2026
1d3747c
feat: serve chain_inscriptions now that the node has a catalogue
TaprootFreak Aug 1, 2026
fa5ba18
feat: serve the Blossom blob store (§7.4)
TaprootFreak Aug 1, 2026
dac7adb
feat: serve GET /v1/receipts/stream — 26 of 29 §7.5 keys
TaprootFreak Aug 1, 2026
f127050
build: containerise the API so the local stack can be complete
TaprootFreak Aug 1, 2026
c2c0ccb
ci: give the API its own gate, paused like the rest of the tree
TaprootFreak Aug 1, 2026
09f04e1
feat: verify GrantProof properly, and stop widening the scope
TaprootFreak Aug 2, 2026
8e51c94
feat: gate the surface by role, and stop turning gaps into successes
TaprootFreak Aug 2, 2026
c6a5c61
feat: accept the delivery credential and carry it untouched
TaprootFreak Aug 2, 2026
53398ca
ci: switch the hosted runner back on
TaprootFreak Aug 2, 2026
704d99b
fix: close the concrete findings a review raised, keep the honest one…
TaprootFreak Aug 2, 2026
bc29548
fix: match the kernel error envelope, stop internal-error leaks, clos…
TaprootFreak Aug 2, 2026
3be9358
fix: accept dependency_not_final as terminal, and bound the per-blob …
TaprootFreak Aug 2, 2026
fbb4432
feat: Data Permanence — Blossom append-only (kein DELETE, kein receipt)
TaprootFreak Aug 3, 2026
a9dbac4
feat(v1): carry the issuance creator_pubkey and re-pin the kernel proto
TaprootFreak Aug 4, 2026
5abb7f6
fix(v1): serialize account-state send_counter as a JSON number
TaprootFreak Aug 4, 2026
2e5f364
feat(v1): carry the genesis-receive Pk0 and re-pin the kernel proto
TaprootFreak Aug 4, 2026
2828af4
feat(v1): bind op_pubkey to subject at bundle-entrust for grant-pull …
TaprootFreak Aug 5, 2026
24011ea
feat(v1): clear subject_ops on bootstrap/revoke so a revoked op-key s…
TaprootFreak Aug 8, 2026
2f91253
feat(v1): add api-local grant revocation (POST /v1/grants/revoke{,/ch…
TaprootFreak Aug 8, 2026
f9f4ad1
api: expose open token provenance — GET /v1/token/<asset_id>/provenance
TaprootFreak Aug 10, 2026
4a6cf18
api: fail-closed on out-of-range token-provenance fields; sync surfac…
TaprootFreak Aug 11, 2026
5aea35e
test(api): cover extract, jobs, and kernel client error paths
TaprootFreak Aug 13, 2026
b3a39a4
test(api): cover pull helpers, chain query edges, and blossom content…
TaprootFreak Aug 13, 2026
46a23c3
test(api): cover publish invariants, info fail-closed, blossom config
TaprootFreak Aug 13, 2026
1846115
test(api): cover info digest/bootstrap edges and config parse errors
TaprootFreak Aug 13, 2026
2f8ed60
test(api): cover job result widths, inscription query edges, empty ops
TaprootFreak Aug 13, 2026
4fbb1f2
test(api): cover blossom auth framing, tags, and decimal parse
TaprootFreak Aug 13, 2026
8c7cd09
test(api): cover ownership scope encode, decimals, and addresses
TaprootFreak Aug 13, 2026
f0b91db
test(api): cover blossom store IO errors and Config::from_env
TaprootFreak Aug 13, 2026
b787c07
refactor(api): move process startup into the library
TaprootFreak Aug 13, 2026
1cebfb3
test(api): close remaining small-file coverage gaps
TaprootFreak Aug 13, 2026
f8351cc
test(api): cover blossom store IO and incomplete-pair refusals
TaprootFreak Aug 13, 2026
b42bcee
fix(api): close REST DTOs and align discovery docs
TaprootFreak Aug 13, 2026
75b98e4
test(api): cover bootstrap challenge reject arms
TaprootFreak Aug 13, 2026
6c1f3d3
test(api): cover pull, revoke, and ownership reject arms
TaprootFreak Aug 13, 2026
9521555
test(api): cover job exclusivity, attestation JSON, and empty ids
TaprootFreak Aug 13, 2026
8254a1f
test(api): cover inscription page peek and grant decode rejects
TaprootFreak Aug 13, 2026
e2b4a02
test(api): reject empty pull session and truncated kernel views
TaprootFreak Aug 13, 2026
f2f96e4
fix(api): consume grant-revoke nonces only after a valid proof
TaprootFreak Aug 13, 2026
c03b38f
test(api): cover grant-revoke peek and challenge_expired
TaprootFreak Aug 13, 2026
0667ea0
test(api): reject a bad pull subject and a raced revoke take
TaprootFreak Aug 13, 2026
5559ba6
test(api): cover receipt SSE happy path and stream breaks
TaprootFreak Aug 13, 2026
ece4508
test(api): reject malformed zkgrant asset lists and tails
TaprootFreak Aug 13, 2026
65743ed
test(api): exercise unused CatalogKernel RPC stubs
TaprootFreak Aug 13, 2026
c334d55
test(api): exercise unused UnreachableKernel RPC stubs
TaprootFreak Aug 13, 2026
76e9955
fix(api): fail-closed store IO, job-id binding, and grant-revoke expiry
TaprootFreak Aug 13, 2026
aa5dbe3
test(api): cover store lock/IO paths, proto identity, and startup errors
TaprootFreak Aug 13, 2026
b5a193c
test(api): cover job validate, sign/cancel, and SSE projection arms
TaprootFreak Aug 13, 2026
802177e
test(api): cover remaining ownership, route, and store error arms
TaprootFreak Aug 14, 2026
f47a73c
docs(api): count three Blossom discovery keys and split API-local rows
TaprootFreak Aug 14, 2026
791d032
fix(api): validate bootstrap op keys before the kernel dial
TaprootFreak Aug 14, 2026
4ae03fc
docs(api): align the ServedSurface gate table with is_active
TaprootFreak Aug 14, 2026
008f4f1
docs(api): document Blossom role gates and drop served LNURL
TaprootFreak Aug 14, 2026
e13a101
docs(api): stop claiming a served LNURL HTTP surface
TaprootFreak Aug 14, 2026
b53e2f5
docs(api): count token provenance in the §7.5 total
TaprootFreak Aug 14, 2026
bd4f4e3
docs(api): name API-local state and drop the rate-limiter claim
TaprootFreak Aug 14, 2026
1dedb83
fix(api): send empty pull action and serialize subject-op updates
TaprootFreak Aug 14, 2026
dee0beb
fix(api): hold the subject lock across grant-pull verify
TaprootFreak Aug 14, 2026
b93948c
fix(api): refuse unknown grant subjects before allocating locks
TaprootFreak Aug 14, 2026
cecaad8
docs(api): pin sha2 and translate remaining German rustdoc
TaprootFreak Aug 14, 2026
bcd6b35
docs(api): translate Dockerfile operator comments to English
TaprootFreak Aug 14, 2026
bcfcdba
chore(api): ignore dotenv variants the image already excludes
TaprootFreak Aug 14, 2026
ab2612f
fix(api): fsync the blossom root before every complete-pair Ok
TaprootFreak Aug 14, 2026
ffdc2b8
docs(api): state that pull accepts GrantProof as well as ownership
TaprootFreak Aug 14, 2026
2ed4777
docs(api): describe lazy kernel dial and local PR workflow
TaprootFreak Aug 14, 2026
2d0c09e
test(api): widen the blossom note-tmp watcher window
TaprootFreak Aug 14, 2026
670abb6
019ffcd1 - Allow any verified blossom op on test nodes (#3)
TaprootFreak Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Build context exclusions for the api image.
# Keep the context small and avoid shipping host build artefacts or stores.

# Rust build output
target/

# VCS
.git/
.gitignore

# Local Blossom content-addressed store (operator path; never bake into image)
# Matches common local paths used with ZKCOINS_BLOSSOM_STORE.
data/
blossom/
**/blossom-store/

# Secrets / local env (if present)
.env
.env.*
*.pem

# Editor / OS noise
.DS_Store
**/.DS_Store
121 changes: 121 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: CI

on:
workflow_dispatch:

# Target-branch gate: every commit that lands on `develop` (direct push
# or merge) gets its own run. Grouped by commit SHA below so a simultaneous
# `pull_request` synchronize on the same SHA is deduplicated rather than
# queued twice.
push:
branches: [develop]

# merge_group: required-check runs for merge queue entries (when enabled).
merge_group:

# CI runs on every pull request regardless of target branch. This
# makes the default safe for stacked PRs (PR-A → PR-B → PR-C where
# each PR's base is the previous PR's branch) and any other workflow
# that opens a PR against a non-`develop` branch — previously such
# PRs were silently skipped because `branches: [develop]` filtered
# them out, and the only fix was to hand-edit ci.yaml on each new
# feature stack.
#
# `ready_for_review` is added so the workflow fires the moment a
# draft PR is marked ready — drafts themselves skip CI via the
# `if:` guard on the job (saves runner time while work is still in
# progress).
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

concurrency:
# Group by commit SHA so:
# - a `push` to develop and a `pull_request` event for the same SHA
# collapse into one in-flight run (`cancel-in-progress`);
# - re-runs of the same commit replace the previous attempt.
# Per-PR "cancel outdated intermediate commits" is not applied: each
# distinct SHA is a separate group (preferred for develop target-branch
# gates and SHA-stable required checks).
group: ci-${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

# Single job on GitHub-hosted Linux: fmt, clippy, build, test.
# No Postgres/testcontainers, no Plonky2 prover, no llvm-cov coverage
# gate, no self-hosted runner — this tree is small enough that the
# local gates fit on `ubuntu-latest` in one job.
#
# No `notify-failure` job: this repository does not hold the Telegram
# bot secrets (`TELEGRAM_BOT_TOKEN` / `TELEGRAM_CHAT_ID`). Add one —
# modelled on the node's `notify-failure` job — once those secrets
# are provisioned here.
jobs:
lint-and-build:
name: Lint & Build
# Skip on draft PRs. Non-PR events (push, merge_group, workflow_dispatch)
# always run: `github.event.pull_request` is absent there, so the
# `event_name != 'pull_request'` arm keeps them enabled.
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4

# The repo pins its toolchain in `rust-toolchain` (a dated nightly,
# with `rustfmt` and `clippy` in `components`). Installing that pin
# keeps a single compiler for format, lint, build and test — nothing
# to drift against a second, explicit channel install. Chosen over
# `dtolnay/rust-toolchain@stable` because the pin file is present;
# without it this step would use the stable action instead of
# inventing a pin.
- name: Install the pinned toolchain (rust-toolchain)
run: |
# `rustup show active-toolchain` installs the pin when the
# directory has a `rust-toolchain` file and no matching
# toolchain is present yet. The `|| rustup toolchain install`
# arm covers the cold case where show exits non-zero before
# the pin is available — install is idempotent; a real failure
# in the subsequent version checks still fails the step.
rustup show active-toolchain || rustup toolchain install
cargo --version
cargo fmt --version
cargo clippy --version

- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

# kernel-proto/build.rs invokes `protoc` (via tonic-build / prost-build)
# to compile proto/kernel/v1/kernel.proto. ubuntu-latest does not ship
# protobuf-compiler by default — without this step, fmt is fine but
# clippy/build/test fail with "Could not find `protoc`".
- name: Install protoc (kernel-proto build.rs)
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler

- name: Check formatting
run: cargo fmt --all --check

# `--all-targets` is intentional: without it clippy lints library
# targets only, so tests and fixture modules are never linted.
# `--all-features` matches the local green suite.
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Build
run: cargo build

- name: Test
run: cargo test --all-features
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ target/

# Environment & secrets
.env
.env.*
!.env.example
*.pem

# OS / editor
Expand Down
27 changes: 13 additions & 14 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
# Contributing to zkCoins API

> **Status: scaffold.** The public API surface is currently served by
> [zk-coins/node](https://github.com/zk-coins/node) directly. This repo will
> hold the standalone API layer — REST + LNURL on top of the node's internal
> kernel RPC ([specification §7.5 / §7.8](https://docs.zkcoins.com/specification)) —
> once the kernel RPC contract stabilises.
This repository **is** the standalone API process (`src/startup.rs` loads
config and connects the kernel). It exposes REST on top of the node's
internal kernel RPC
([specification §7.5 / §7.8](https://docs.zkcoins.com/specification)).

## What belongs here

- The public **REST + LNURL** service layer (multi-tenant, hosted-wallet surface).
- Its own **non-value-bearing** database (LNURL mappings, aliasing, rate limits,
push subscriptions). Coins, proofs, and the nullifier accumulator stay in the
node — this layer never touches the node's database directly.
- The public **REST** service layer (multi-tenant, hosted-wallet surface).
- Planned API-local scope (**not implemented yet**): LNURL mappings, aliasing,
rate limits, push subscriptions. Coins, proofs, and the nullifier accumulator
stay in the node — this layer never touches the node's database directly.
- No SPEND keys, no Bitcoin access — proving, broadcasting, and chain scanning
stay in the node.

API-surface changes that affect the live system today go to
[zk-coins/node](https://github.com/zk-coins/node) instead.

## Workflow

- Default branch is `develop`; open PRs against it.
- Commit messages: English, concise, *what* not *how*.
- House rules (trust model, code style, CI conventions) follow
- House rules for the trust model and Rust style follow
[zk-coins/node/CONTRIBUTING.md](https://github.com/zk-coins/node/blob/develop/CONTRIBUTING.md).
Workflow here differs: PRs target `develop` (this repo has no `staging`),
there is no Node `.githooks` setup, and CI is the single `lint-and-build`
job in `.github/workflows/ci.yaml`.

## Related Repos

- [zk-coins/node](https://github.com/zk-coins/node) — trustless kernel (currently also serves the API).
- [zk-coins/node](https://github.com/zk-coins/node) — trustless kernel.
- [zk-coins/sdk](https://github.com/zk-coins/sdk) — TypeScript client consuming this surface.
- [zk-coins/docs](https://github.com/zk-coins/docs) — specification ([docs.zkcoins.com](https://docs.zkcoins.com)).
Loading
Loading