A small, stateless, view-only Orchard utility for Zcash. It derives UFVKs,
scans the shielded chain for memos (e.g. ZINC
inscriptions) through a lightwalletd endpoint, decodes/validates addresses, and
builds/inspects PCZTs for client-side signing. It holds no state and no spend
keys — point it at your own node and viewing key and run it alongside
zebrad/zcashd + lightwalletd.
It is the companion scanner for the ZINC inscription standard, but nothing here is ZINC-specific: it is a generic Orchard scanner/UFVK tool and works for any shielded-memo use case.
The daemon only ever needs a Unified Full Viewing Key (UFVK). It can see incoming notes and their memos, but it cannot spend. Spending is done elsewhere (e.g. a wallet / FROST signers) against PCZTs this tool builds. Keep spend keys off the scanning host entirely.
Requires a recent stable Rust toolchain. The committed Cargo.lock is
format v4, so Rust ≥ 1.78 is needed (tested with 1.90).
cargo build --release --locked
# binary: ./target/release/zinc-scannerThe Zcash crates come from a librustzcash
fork (branch public-pczt-api,
pinned by commit in Cargo.toml + Cargo.lock) that exposes public PCZT struct
fields for external construction — Cargo fetches it automatically, so there is
no vendoring or submodule step. Build with --locked so the pinned
dependency graph (one transitive crate, core2, is yanked upstream but pinned
here) resolves reproducibly. The first build compiles the Zcash proving stack and
takes a while.
# 1. Generate a view-only sub-account seed (24 words). Keep it offline; only its
# UFVK should ever touch the scanning host.
zinc-scanner generate-mnemonic --words 24
# 2. Derive the UFVK (read the secret from stdin so it stays out of `ps`/proc):
echo "<mnemonic>" | zinc-scanner derive-ufvk --mnemonic-stdin --network mainnet
# 3. Scan Orchard for notes + memos via your lightwalletd (UFVK from stdin):
echo "<ufvk>" | zinc-scanner scan-ufvk --ufvk-stdin \
--server lightwalletd.example.com:9067 --tls --max-blocks 2000All commands emit JSON on stdout, so they compose cleanly with jq and scripts.
| Command | Purpose |
|---|---|
generate-mnemonic |
Generate a fresh BIP-39 mnemonic (12–24 words) for a listings/inbox-only sub-account. |
derive-ufvk |
Derive a UFVK from a mnemonic via ZIP-32 (m/32'/133'/account'). Testing convenience — derive client-side in production. |
scan-ufvk |
Scan Orchard with a UFVK via lightwalletd (view-only); returns notes + memos. |
decode-address |
Decode a unified address into its Orchard/Sapling/transparent receivers (offline). |
ufvk-address |
Derive the Orchard receiver a UFVK owns; with --match-ua, prove a UFVK owns a given UA. |
latest |
Get the latest block height from lightwalletd. |
dump-tree-state |
Dump the TreeState at a height (debug). |
build-pczt |
Build an unsigned PCZT from provided Orchard notes (for client-side signing). |
extract-tx |
Extract the final transaction from a signed PCZT. |
inspect-pczt |
Inspect a PCZT's structure (debug). |
apply-transparent-signatures |
Apply client-generated transparent signatures to a PCZT. |
extract-orchard-sighash |
Extract the Orchard shielded sighash from a PCZT (for FROST co-signing). |
apply-orchard-frost |
Apply FROST Orchard SpendAuth signatures, prove, and finalise. |
extract-sapling-sighash |
Extract the Sapling shielded sighash from a PCZT (no Orchard actions). |
apply-sapling-frost |
Apply FROST Sapling spend-auth signatures, prove Sapling, and finalise. |
Run zinc-scanner <command> --help for the full flag list.
--server host:port selects the endpoint; add --tls for TLS and --tls-name
to set the SNI/domain when it differs from host. You can run your own
lightwalletd in front of zebrad/zcashd, or point at a public instance.
- Secrets via stdin. Pass mnemonics/UFVKs with the
--*-stdinflags so they never appear inps, shell history or/proc/<pid>/cmdline. A mnemonic is a spend secret; only ever move the derived UFVK to a scanning host. - No spend authority. This tool never signs spends. PCZTs it builds are signed by your wallet / FROST signers elsewhere.
- Runtime caches are not source. Decrypted note/witness data derived from a
viewing key is excluded by
.gitignore; treat any such cache as sensitive.
ZINC inscriptions are ordinary ZIP-302 shielded memos; this scanner is one way to read them off-chain from a registry/inbox UFVK. See the ZINC standard for the memo format and profiles, and https://secresea.com for a live deployment.
MIT © FungeLLC