The anon.garden base layer for Zcash Shielded Assets
A full engineering treatment of the three-action asset layer behind anon.garden — issuance, transfer, and burn — over the OrchardZSA protocol, the infrastructure required to run it today on testnet, and a deep catalog of products the layer makes possible.
Executive Summary
Thesis · Feasibility · ApproachThe objective is a thin, reusable base layer exposing three primitives — issuance, transfer, and burn of custom shielded assets — over Zcash's OrchardZSA protocol, on top of which a family of payment, stablecoin, bridge, and capital-markets products can be assembled. This document establishes that the primitives are buildable on testnet today, specifies the architecture and the implementation path, and catalogs the application surface in depth.
0.1What is true today
OrchardZSA — specified across ZIP 226 (transfer & burn), ZIP 227 (issuance), and ZIP 230 (the v6 transaction format) — extends the existing Orchard shielded pool so that any user can mint a custom asset that subsequently moves with the same privacy guarantees as ZEC. A feature-complete implementation is live on a public testnet and is fully exercised by QEDIT's zcash_tx_tool, whose reference scenario performs precisely the loop we need: issue an asset, transfer it to another party, then burn it. The full lifecycle works against a single-node Zebra running in regtest, and atomic swaps between assets have been publicly demonstrated.
0.2The shape of the build
We do not build a node or re-implement the cryptography. We wrap the existing Rust transaction-construction machinery (librustzcash, mirrored by the tx-tool's scenario pattern) behind a stable service API — issue / transfer / burn / balance / asset — and pair it with three supporting subsystems: a key-management module (issuance authority is cryptographically distinct from spend authority), a wallet/sync layer that scans the chain and maintains note state, and an asset registry that solves the protocol's deliberate refusal to let asset names travel on-chain. Everything else — payments, payroll, bridges, launchpad — is an application sitting on that boundary.
ZSA gives transparent issuance over shielded holding: the existence, issuer, and total supply of an asset are public and auditable, while balances and transfers are private. This single property is what makes the entire product space coherent — it is exactly what wrapped/bridged assets need (verifiable supply against reserves) and exactly what payments and payroll need (confidential amounts). Most of the design work downstream is in managing the seams of that public/private boundary.
0.3What to weigh before committing
Three realities frame every decision in this document, and they are treated explicitly in §7. First, the tooling is alpha — APIs and data structures are expected to break, and the reference tool is not a wallet. Second, the consumer wallet/SDK layer is immature: the node and Rust crates support ZSA, but the light-client indexer and end-user wallet are still hardening, which pushes polished mobile/web products later and favors server-side and back-office products first. Third, ZSA is pre-mainnet and contested — its inclusion in NU7 is the subject of an active coinholder vote, so building on it is, in part, a bet on activation.
The ZSA Protocol
What the base layer is standing onA precise mental model of OrchardZSA is a prerequisite for everything that follows. This section condenses the consensus-relevant mechanics into the parts that shape the service design.
1.1Assets, and the identity that makes them unique
An Asset is a type of shielded note. ZEC is simply the default asset; a Custom Asset is anything else. Each asset is named by a globally-unique Asset Identifier, constructed so that two different issuers can never collide. Uniqueness comes from binding the issuer's public key to a hash of a free-form description string, then deriving — through two more steps — the actual group element that a note carries. That derivation pipeline is the single most important diagram in the protocol:
The consequence worth internalizing: the chain stores a hash of the description, not the description. This was a deliberate revision. It lowers bandwidth, allows arbitrarily long descriptions off-chain, and — most importantly — prevents wallets from naively trusting a name that arrived over the wire. A wallet that sees an unknown asset is forced to look its description up out-of-band before showing anything to a user, which blunts the "anyone can mint a token literally described as USDC" spoofing attack. This requirement is the entire reason the base layer needs an asset registry (§4.7).
1.2Issuance authority, separated from spend authority
Issuance introduces its own key pair: an issuance authorizing key (isk) that signs issuance, and an issuance validating key (ik) that the network checks against. These are derived through a dedicated hardened-only ZIP 32 path (purpose = 227'), entirely separate from the keys that spend notes. The signature scheme is BIP-340 Schnorr over secp256k1 — the same curve family as Bitcoin Taproot, chosen for tooling and hardware compatibility rather than the Pallas/Vesta curves Orchard uses internally. The issuer's on-chain identity is just the encoding of ik.
Because issuance authority is cryptographically distinct from spend authority, the base-layer service can hold or delegate minting rights without ever touching the funds wallet. A compromised issuance key cannot move anyone's balances — it can only mint. This separation is what makes a custodial issuance service, a delegated launchpad, or a future threshold-signed treasury tractable.
1.3Supply, finalization, and the global issuance state
Every node maintains a map from each asset's AssetBase to a triple: its circulating balance (issued minus burned), a one-way final flag, and a reference note. Three consensus rules govern it. Balance may never exceed MAX_ISSUE = 2⁶⁴−1; balance may never go negative (burns are checked against it); and once an asset is finalized, no further issuance of it is ever accepted — the flag cannot revert from 1 to 0. The reference note is a mandatory value-0 note to a well-known default address, inserted the first time an asset is issued, giving every asset a canonical anchor.
This is the mechanism that makes supply publicly auditable — the property bridges and stablecoins depend on. A node (and therefore our service) can answer "how much of asset X exists?" deterministically, even though it cannot see who holds it.
1.4Fees, transactions, and a hard coupling
Fees are paid in ZEC, always — there is no mechanism to pay fees in a custom asset, by design (lifting value out of a shielded transaction for fees would leak information about it). Issuance, transfer, and burn all ride inside the v6 transaction format (ZIP 230). One coupling rule is structurally important: an issuance bundle must be accompanied by at least one OrchardZSA action group in the same transaction — both to derive the issue notes' nullifier-seed and to prevent replay of an otherwise-identical issuance. Issuance cannot stand alone in a transaction.
Every actor in every product — issuer, sender, payroll operator, bridge custodian — needs a small ZEC balance to pay fees. "Onboarding a user" therefore always includes seeding them with dust ZEC, or sponsoring fees on their behalf. This is a recurring UX and treasury line item, not an edge case.
System Architecture
The stack, the service, and the data modelThe system is a five-layer stack. We own exactly one layer of it — the base-layer service — and consume the rest. Drawing the boundary cleanly is what keeps the products above it simple and the protocol churn below it contained.
2.1Layered architecture
Reading top to bottom: applications speak only to our service; the service speaks to the node through transaction construction and RPC; the node enforces consensus and holds the global issuance state; the network is whichever chain we are pointed at. The only layer that is bespoke is the second — and even there, the heavy lifting (transaction building, proving) is borrowed from librustzcash.
2.2Deployment & component view
Concretely, the base-layer service is a long-running Rust process (or a Rust core wrapped by a thin gateway in any language) that holds keys, persists wallet and asset state, and talks to a Zebra node over JSON-RPC. Secrets live in a separate store; for treasury-grade operations that store fronts an HSM or a FROST threshold-signing quorum.
2.3The base-layer service & its API surface
The service collapses the protocol's complexity into a small, stable contract. Internally it owns six concerns; externally it exposes a handful of resources. The contract below is the seam every product builds against — it should change far less often than the alpha crates beneath it.
| Method · Endpoint | Action | Notes & consensus touchpoints |
|---|---|---|
| POST /assets | Issue (create) a new asset | Body: description, supply, finalize, recipients. Emits the mandatory value-0 reference note on first issuance. Returns asset_id + txid. |
| POST /assets/{id}/issue | Issue more of an asset | Rejected if the asset is finalized. Must be bundled with an Orchard action group. |
| POST /assets/{id}/finalize | Permanently cap supply | One-way; sets final = 1. Often issued as a final note of value 0. |
| POST /transfers | Transfer asset (shielded) | Body: asset_id, from-account, to-address, amount. Builds an OrchardZSA action; amounts are private. |
| POST /burns | Burn asset | Checked against circulating balance; decrements the global supply. The canonical off-board primitive for bridges. |
| GET /assets/{id} | Asset metadata + supply | Joins on-chain supply (from the issuance state) with registry metadata (name, symbol, decimals). |
| GET /accounts/{id}/balances | Per-asset balances | Derived from the wallet's spendable note set; never leaves the service unencrypted. |
| POST /accounts · GET /addresses | Key & address management | Provisions ZIP-32 accounts; issuance keys on 227', spend keys separate. |
| GET /supply/{id} | Public circulating supply | Read straight from the mirrored issuance state — the proof-of-reserves primitive. |
| GET /tx/{txid} | Transaction status | Pending / confirmed / depth; drives webhooks. |
2.4Data model
Five core tables carry the service's state. The note store is the wallet; the registry is the off-chain name layer the protocol forces on us; the supply mirror is a local cache of the chain's authoritative issuance map, kept for fast reads and reorg-safe.
-- on-chain asset identity + cached supply CREATE TABLE assets ( asset_id BYTES PRIMARY KEY, -- (issuer, assetDescHash) asset_base BYTES UNIQUE, -- Pallas point used in notes issuer BYTES, -- 0x00 ‖ ik (BIP-340) finalized BOOL DEFAULT false, supply_cached U128, -- mirror of issued − burned created_height U64 ); -- the wallet: every note we can detect / spend CREATE TABLE notes ( commitment BYTES PRIMARY KEY, asset_base BYTES REFERENCES assets, value U64, rho BYTES, rseed BYTES, diversifier BYTES, account_id U64, position U64, -- leaf index in note commitment tree spent BOOL DEFAULT false, height U64 ); -- the off-chain name layer the protocol mandates (§4.7) CREATE TABLE registry ( asset_id BYTES PRIMARY KEY REFERENCES assets, name TEXT, symbol TEXT, decimals U8, metadata_url TEXT, verified BOOL DEFAULT false ); CREATE TABLE accounts ( account_id U64 PRIMARY KEY, key_ref TEXT, issuance_path TEXT ); -- secrets live in Key Store CREATE TABLE txs ( txid BYTES PRIMARY KEY, kind TEXT, status TEXT, height U64 ); -- issue|transfer|burn
2.5Synchronization & state integrity
The wallet/sync module follows the model proven in the reference tx-tool: it records block hashes and the serialized note-commitment tree, validates on each run that its stored chain head still matches the node, and resumes from the last synced height. Its reorg policy is deliberately blunt and therefore safe — on any detected reorganization or wallet/block inconsistency it wipes derived state (block data, wallet state, notes, tree) and resynchronizes from scratch rather than attempting a partial rewind. On regtest and the ZSA testnet this is cheap; the same code path scales to mainnet, where block-data is bounded by block count (not size) and wallet state grows only with wallet activity.
The supply mirror (assets.supply_cached) is a convenience cache, never a source of truth. Any product that gates value on supply — a bridge proving reserves, a stablecoin reporting circulation — must read the authoritative figure from the node's issuance state at confirmation depth, and must treat the mirror as invalidated across reorgs.
Protocol Operations
Issuance · Transfer · Burn · LifecycleEach of the three primitives is a v6 transaction with a distinct shape. The sequence flows below trace a request from the application down to consensus and back, naming the checks the node performs — the rules our service must respect or the transaction is rejected.
3.1Issuance
Issuance creates new units of a custom asset. On the very first issuance of an asset, the service must prepend the mandatory value-0 reference note; the issuance bundle must travel with at least one Orchard action group; and the bundle is signed by the issuance authorizing key over the transaction's sighash. Validators verify the signature, refuse any issuance of a finalized asset, enforce the supply ceiling, then compute the note commitments themselves and update the global issuance state.
3.2Transfer
Transfer moves existing units between shielded addresses. It is an ordinary OrchardZSA action group: the service selects input notes of the right asset, constructs outputs, computes a per-asset value commitment (the value base is a private input to the proof, which is how a single circuit handles both ZEC and custom assets), produces the halo2 proof, and reveals only nullifiers and output commitments. Amounts, asset type, sender, and receiver are all hidden on-chain.
3.3Burn
Burn destroys units and reduces the asset's public circulating supply. It is the canonical off-board primitive: a bridge releases value on the origin chain only after observing a confirmed burn of the wrapped asset on Zcash. The node checks that the burned amount does not exceed the asset's circulating balance, then decrements the global issuance state. Because supply is public, anyone — including a bridge relayer or an auditor — can verify the burn without seeing who burned it.
3.4Asset lifecycle
An asset moves through three consensus states. Issuance brings it to life; further issuance, transfer, and burn keep it active; finalization permanently seals supply while still permitting movement and burning. Two invariants hold throughout and can never be violated.
Implementation
Repos · environments · service wiring · keysThis section is the build manual: the exact components to pull, how to stand up a node locally and in the cloud, how the service wraps the reference tooling, and how the supporting subsystems (keys, registry, supply accounting) are realized.
4.1Components & version pinning
The entire stack is a set of QEDIT forks maintained for NU7. Because everything is alpha and under active, breaking-change review, the single most important operational rule is to pin exact commit hashes, not branches. An unpinned cargo update against these crates will eat days.
| Component | Ref to pin | Role in the build |
|---|---|---|
| QED-it/orchard | branch zsa1 → SHA | Core OrchardZSA crate: note structure, per-asset value commitment, halo2 circuit. |
| QED-it/librustzcash | ZSA fork → SHA | Transaction construction & serialization; the builder our service calls. |
| QED-it/zebra | zsa-integration-demo | ZSA-enabled node; ships the regtest Docker image we run. |
| QED-it/zcash_tx_tool | tag v0.5.0 | Reference tx generator; its scenarios are our copy-paste starting point for issue/transfer/burn. |
| QED-it/zcash-test-vectors | fork → SHA | v6/ZSA test vectors for validating our serialization against the reference. |
4.2Local development environment
Two terminals. The first builds and runs a self-contained ZSA Zebra node in regtest (it mines deterministically, so there is no waiting for blocks and no dependence on a public network). The second runs the transaction tool against it. This is the exact path the reference documents, reproduced here as the baseline.
# 1 — build & run the ZSA Zebra node (regtest, RPC on :18232) git clone -b zsa-integration-demo --single-branch --depth=1 \ https://github.com/QED-it/zebra.git cd zebra docker build -t qedit/zebra-regtest-txv6 \ -f testnet-single-node-deploy/dockerfile . docker run -p 18232:18232 qedit/zebra-regtest-txv6
# 2 — one-time setup cargo install diesel_cli --no-default-features --features sqlite DATABASE_URL=walletdb.sqlite diesel setup ./zcutil/fetch-params.sh # Sapling params # 3 — run the full lifecycle: issue → transfer → burn (×2) cargo run --release --bin zcash_tx_tool test-orchard-zsa # other ready-made scenarios: # test-issue-one minimal: issue a single asset # test-three-party issue → transfer → transfer → burn # NOTE: reset the node (restart the container) between runs
The tx-tool is explicitly not a wallet and not for production — but its scenario files (src/commands/test_orchard_zsa.rs) are the cleanest worked examples of constructing each transaction type. The documented "create your own scenario" path — copy a scenario, register a new command variant — is exactly the seam from which to lift transaction-building logic into the service.
4.3Wrapping the builder behind the service
The service's three write paths are thin functions over the librustzcash builder, encoding the consensus obligations from §3 so callers never have to. The sketch below is illustrative — APIs in the alpha crates will differ — but it captures the required moves: derive the asset, attach the reference note on first issuance, bundle an Orchard action group alongside any issuance, sign with the issuance key, and broadcast.
pub async fn issue(req: IssueReq, ctx: &Ctx) -> Result<IssueResp> { // 1. deterministic identity from issuer key + description let asset = AssetId::derive(&ctx.issuer_ik, &req.description); let mut b = TxBuilder::new(ctx.network, ctx.anchor()); // 2. first issuance MUST carry the value-0 reference note if !ctx.state.exists(&asset) { b.add_reference_note(&asset); // default addr, v=0 } for r in req.recipients { b.add_issue_note(&asset, r.addr, r.amount); } b.set_finalize(&asset, req.finalize); // 3. issuance cannot stand alone — bundle an Orchard action group b.add_orchard_action_group(ctx.dust_input()?); // 4. sign issuance with isk (BIP-340), spends with spend keys let tx = b.build_and_sign(&ctx.isk, &ctx.spend_auth)?; let txid = ctx.node.send_raw_transaction(tx).await?; Ok(IssueResp { asset_id: asset.encode(), txid }) }
4.4The API contract
Above that core sits the language-agnostic boundary every product consumes. Issuance carries both the on-chain parameters and the registry metadata (which is stored off-chain — see §4.7).
// request { "description": "Acme Payroll USD · series 2026-Q3", "supply": 1000000000000, // 1,000,000.000000 @ 6 dp "decimals": 6, "finalize": false, "recipients": [{ "address": "u1acme…", "amount": 1000000000000 }], "registry": { "name": "Acme USD", "symbol": "aUSD" } } // response 200 { "asset_id": "0x00b91f…c2", "asset_base": "0x7e…a1", "txid": "d41c…9f", "reference_note": true, "status": "pending" }
4.5Key management
The service provisions ZIP-32 accounts and derives issuance keys on the dedicated hardened path m / 227' / coin' / 0', kept structurally apart from the spend keys. Three operating postures, escalating with the value at stake:
- Dev / hot — keys in the service's encrypted key store. Acceptable on regtest and testnet; never for material mainnet value.
- HSM-backed — the issuance authorizing key (a BIP-340 secp256k1 key) lives in an HSM or enclave; the service requests signatures over the sighash but never holds the secret.
- Threshold — issuance and/or treasury spend authority split across a FROST quorum (the Foundation's threshold-Schnorr work), so no single operator can mint or move funds. This is the recommended posture for a stablecoin issuer or bridge custodian.
The protocol does not support rotating an asset's issuance key. If an issuer key is compromised the only remedy is to finalize every asset under it and migrate to a new issuer identity (and thus new asset IDs). Treat the issuance key as a long-lived root of trust and protect it accordingly from day one — retrofitting custody after launch is far harder.
4.6The shared cloud testnet
Two complementary targets, and the team should use both in sequence. Begin on a shared regtest node in the cloud for development velocity; add the public ZSA testnet for integration testing under realistic conditions before anything is user-facing.
| Target | Strengths | Trade-offs · use when |
|---|---|---|
| Shared regtest qedit/zebra-regtest-txv6 | Deterministic; mines on demand (no block-time wait); resettable at will; full control over issuance and chain state; ideal for CI. | Not representative of network conditions or other participants. Use for early dev, fixtures, and CI. |
| Public ZSA testnet | Shared, realistic, multi-party; closest proxy to mainnet behavior; surfaces sync, fee, and reorg realities. | Less control; subject to testnet stability and resets. Use before user-facing milestones. |
For CI and self-contained deployments, the tx-tool ships a Docker workflow with a documented persistence-volume layout and a host-network example, plus a multi-container recipe in its CI configuration and a prebuilt image on a public registry (gallery.ecr.aws/j7v0v6n9/tx-tool). A practical shared-testnet topology: one cloud-hosted Zebra regtest node, the base-layer service alongside it, and both developers pointing their local app builds at that service's API — with the exact same commit pins baked into the image.
4.7The asset registry & petname service
Because the chain stores only a hash of an asset's description and the protocol forbids wallets from displaying raw description bytes as a name, a name layer is mandatory infrastructure, not a nicety. The registry maps each asset_id to human metadata and an issuer attestation, and is consumed by wallets to resolve unknown assets safely.
- Curated default list — a signed, versioned catalog of well-known assets (name, symbol, decimals, logo, issuer signature), shipped as a starting point and verifiable against each asset's issuer key.
- Petname overlay — clients may add or rename entries locally, so a user's chosen label never silently collides with someone else's asset.
- Verification gate — when a wallet receives an unknown asset, it resolves the description out-of-band and surfaces a clear "unverified asset" state until the user or a trusted registry confirms it. This is the anti-spoofing behavior the protocol is engineered to force.
4.8Observability & supply accounting
The supply indexer mirrors the node's global issuance state and exposes it via GET /supply/{id}. For products that gate value on supply, this becomes a proof-of-reserves surface: a bridge can publish, continuously and trustlessly, that the wrapped supply minted on Zcash never exceeds the collateral locked on the origin chain. The authoritative figure is always read from the node at a safe confirmation depth and treated as invalidated across reorgs; the mirror exists only to make reads fast.
Application Catalog
What the three primitives make possibleEverything below reduces to issuing an asset, moving it privately, and burning it — composed with off-chain logic, custody, and UX. This catalog spans ten domains and forty-plus concrete products, each annotated with why ZSA is the right substrate, the components a build needs, and an honest read on difficulty and risk.
Why ZSA states the specific property that makes Zcash shielded assets a better fit than a transparent chain. Build lists the components beyond the base layer. The buildlow / buildmed / buildhigh pill rates engineering effort over the base layer; the RISK pill rates execution, trust, security, and regulatory exposure combined. A ★ near-term tag marks the most realistic early products given today's tooling.
Payments & Money Movement
The flagship use case: moving value with confidential amounts. The protocol is push-based and every send costs a small ZEC fee, which shapes what is and isn't practical.
Stablecoins & Real-World Assets
Here the protocol is the easy part and the off-chain layer is the whole game. ZSA gives you mint, supply control, finalization, and auditable circulation; it gives you nothing about reserves, redemption, or legal standing. The rails are not the dollars.
Bridges & Interoperability
Bridging is where ZSA's design intent and its sharpest risks meet. The issue/burn pair maps perfectly onto on-board/off-board, and public supply gives trustless proof-of-reserves. But bridges are the most-exploited primitive in crypto, and the public/private boundary needs deliberate handling.
Two structural issues deserve explicit design attention. Custody is the dominant risk: a lock-and-mint bridge concentrates value in the origin-chain contract, and history shows this is where catastrophic losses occur — mitigate with threshold custody (FROST), conservative mint limits, continuous proof-of-reserves, and circuit breakers, and prefer bridging into Zcash (where supply is auditable) over designs that obscure reserves.
Privacy interacts with redemption: mints and burns are public events while transfers are private, so the operator sees on/off-board flow but not what happens in between. Redemption flows must be designed so that proving "I burned, release my funds" does not force users to deanonymize their entire holding. Note the protocol's own caution against issuance schemes that demand redemption to a single fixed address — that pattern leaks linkage and should be avoided.
Payroll & Treasury
The most realistic first product class, because these are back-office flows that run server-side and do not depend on a polished consumer wallet. Privacy is a genuine feature here — salaries and vendor terms are sensitive by default.
Issuance & Capital Markets
These products lean directly on issuance, finalization, and the registry — and inherit the heaviest regulatory exposure of any category. The protocol mechanics are tractable; securities law is the constraint.
Trading & DeFi
Atomic swaps are already working end-to-end, which makes private trading the most tractable DeFi surface. Pooled/AMM designs are far harder under shielding; order-book and OTC models that settle atomically are the pragmatic path.
NFTs, Collectibles & Ticketing
An asset issued with supply 1 and then finalized is effectively a unique token; small finite editions extend the idea. The reference note can anchor a metadata pointer. The wrinkle: once issued, ZSA units transfer permissionlessly, so "non-transferable" credentials need explicit design.
Loyalty, Rewards & Vouchers
Closed-loop value where a single issuer mints, users hold, and redemption burns. Low protocol complexity makes this a friendly proving ground, with regulation rising as stored value starts to look like money.
Compliance & Enterprise
Zcash's viewing keys turn "private" into "private with selective transparency," which is exactly what regulated institutions need: confidential by default, disclosable to an auditor or counterparty on demand.
Niche & Emerging
A long tail where private, finite, auditable tokens unlock something specific. Several of these are strong differentiators precisely because privacy is the point.
Prioritization & Roadmap
What to build, in what order, and whyForty products is a menu, not a plan. Plotting them by strategic value against build complexity sorts the menu into quick wins worth doing now and big bets worth sequencing later — and the dependency structure dictates the order regardless of appetite.
6.1Value vs. complexity
6.2Dependency structure
Order is not purely a matter of preference — products depend on one another. The chain is:
- Everything depends on the base layer. Issue/transfer/burn, key management, sync, and the registry are prerequisites for every single product in §5.
- Payments, payroll, and loyalty depend on an asset existing. For payroll and payments that means a stablecoin (even a test one); for loyalty it can be a self-issued points asset, which is why loyalty is buildable earliest.
- The launchpad depends on the registry and atomic swaps. It is mostly issuance UX plus the naming layer plus a sale mechanism — all of which the base layer already needs.
- Bridges depend on custody and a relayer, and unlock the wrapped-asset family. Once a bridge exists, wrapped BTC/ETH/USDC and everything built on them becomes possible.
- Compliance tooling (viewing-key disclosure, proof-of-reserves) is reusable across all of the above and is worth building early as shared infrastructure rather than per-product.
6.3Phased roadmap
Stand up the environment
Pin the QEDIT stack, run the regtest node locally and in the cloud, reproduce the issue→transfer→burn scenario, and establish CI against a shared regtest. Exit criterion: both developers can transact ZSAs against the same node.
Build the service & the registry
Wrap the builder behind the issue/transfer/burn API; implement key management, wallet/sync, the supply indexer, and the asset registry. Add the viewing-key disclosure service as shared infrastructure. Exit criterion: a stable API other code can build on.
Ship a real, narrow product
Pick one upper-left-quadrant product — private payroll or a private-stablecoin payment demo — and take it end-to-end. Back-office scope avoids the consumer-wallet gap. Exit criterion: a working product a design partner can use on testnet.
Bring in external value
Build a custodial lock-and-mint bridge with FROST custody and continuous proof-of-reserves, unlocking wrapped assets. Highest-risk phase — gate it behind security review and conservative limits. Exit criterion: an audited bridge moving a wrapped asset on testnet.
Open the platform
With assets, a stablecoin, and a bridge in place, build the launchpad and a private DEX/OTC layer on the now-mature base. Exit criterion: third parties issuing and trading assets through the platform.
Concerns & Risk
The honest columnThree of these dominate and deserve naming up front: the tooling is alpha, the consumer wallet layer is immature, and mainnet activation is not guaranteed. None is disqualifying for building now — but each shapes what to build, how to insulate against it, and what to promise.
Activation uncertainty
ZSA's inclusion in NU7 is contested and subject to an active coinholder vote. Building on testnet is sound regardless, but anything that requires mainnet ZSA should be treated as gated on an external decision. Keep the base-layer abstraction portable so the products above it are insulated from how that decision lands.
The wallet / SDK gap
The node and Rust crates support ZSA; the light-client indexer and consumer wallet are still hardening. This is why the roadmap front-loads back-office products (payroll, treasury, settlement) that run server-side and defers polished consumer mobile/web wallets until the client stack matures.
Privacy is a boundary, not a blanket
Issuance, finalization, supply, and burns are public; balances and transfers are private. Most leakage risk lives at that seam — especially in bridge redemption and any flow that correlates a public mint/burn with a private holding. Design redemption to avoid fixed-address patterns, batch where possible, and minimize metadata.
Irreversibility of issuer keys
There is no issuance-key rotation and finalization is permanent. Custody decisions made at launch are effectively unchangeable, so threshold/HSM custody belongs in the design from the first mainnet asset, not as a later retrofit.
7.1Risk register
| Risk | Likely | Impact | Mitigation |
|---|---|---|---|
| NU7 activation slips or ZSA is excluded | Med | High | Build on testnet; keep the service boundary portable; track the coinholder vote; treat mainnet as an optional milestone, not a dependency. |
| Alpha crates introduce breaking changes | High | Med | Pin exact commit SHAs; isolate crate churn behind the service; run integration tests against the reference test vectors. |
| Consumer wallet / light-client immaturity | High | Med | Sequence back-office products first; contribute to / track Zallet + Zaino; build bespoke scanning only where required. |
| Issuance-key compromise (no rotation) | Low | High | FROST / HSM custody from day one; documented finalize-and-migrate runbook; least-privilege key access. |
| Public/private boundary leakage | Med | Med | Avoid fixed-redemption-address patterns; batch mints/burns; minimize on-chain metadata; user education. |
| Asset-name spoofing | Med | Med | Mandatory registry + verification gate; never render raw asset_desc; clear unverified-asset UX. |
| Bridge exploit / custody loss | Med | High | Threshold custody; mint caps + circuit breakers; continuous proof-of-reserves; external audit; prefer bridging into Zcash. |
| Regulatory action (stablecoin / securities) | Med | High | Jurisdictional legal review; compliance hooks (allowlist, screening, viewing-key disclosure); avoid unregistered securities. |
| Fee / ZEC onboarding friction | High | Low | Fee sponsorship; seed dust ZEC at onboarding; abstract fees away from the end user. |
| Off-chain logic bugs (relayer / scheduler) | Med | Med | Audit critical paths; monitoring and alerting; conservative timeouts and idempotency. |
| Proving cost / throughput at scale | Med | Med | Batch transactions; async construction; capacity planning; benchmark early on representative loads. |
Conclusion & Next Steps
Where this leaves usThe three primitives we need are not speculative — they run end-to-end on testnet today, exercised by the reference tooling. The work is to wrap them in a durable service, solve the naming layer the protocol forces on us, and choose a first product that plays to the stack's current strengths rather than its gaps.
The strategic shape is clear from the value/complexity map and the dependency chain: build the base layer and registry first; ship a narrow, high-value, back-office product — private payroll is the strongest candidate — to prove the whole pipeline with a design partner; then sequence the higher-complexity, higher-value bets (bridges and the wrapped-asset family, then the launchpad and private trading) onto a foundation that has already earned trust. Throughout, treat custody, the public/private boundary, and mainnet-activation uncertainty as first-class design inputs, not afterthoughts.
1. Stand up the qedit/zebra-regtest-txv6 node locally and on a shared cloud host; pin every crate to a commit SHA. 2. Reproduce test-orchard-zsa against it to confirm the issue→transfer→burn loop. 3. Scaffold the base-layer service API and lift transaction-building from the scenario pattern. 4. Decide the custody model (FROST vs HSM) before any mainnet asset. 5. Build the asset registry. 6. Choose and scope the first product.
Appendix & References
Glossary · constants · sourcesA.1Glossary
| Term | Meaning |
|---|---|
| OrchardZSA | The protocol (ZIP 226 + 227) extending the Orchard shielded pool to support custom shielded assets. |
| AssetId | An asset's identity: the pair (issuer key, hash of description). The on-chain identifier. |
| AssetDigest | A 64-byte BLAKE2b digest of the encoded AssetId; an intermediate in deriving the AssetBase. |
| AssetBase | The Pallas-curve point derived from the AssetDigest and carried inside every note of that asset. |
| isk / ik | Issuance authorizing key / issuance validating key — BIP-340 Schnorr over secp256k1, on ZIP-32 path 227'. |
| Reference note | A mandatory value-0 note emitted on an asset's first issuance, providing a canonical anchor. |
| Finalization | A one-way flag that permanently forbids any further issuance of an asset. |
| Action group | The OrchardZSA transaction component carrying shielded spends/outputs; required alongside issuance. |
| Burn | Destruction of asset units, reducing the public circulating supply; the off-board primitive. |
| Viewing key | A key permitting read-only visibility into transactions — the basis for selective disclosure. |
| FROST | Flexible Round-Optimized Schnorr Threshold signatures — for splitting issuance/spend authority across a quorum. |
| regtest | A local, deterministic single-node chain mode used for development and CI. |
A.2Key constants
A.3References
- ZIP 226 — Transfer and Burn of Zcash Shielded Assets · zips.z.cash/zip-0226
- ZIP 227 — Issuance of Zcash Shielded Assets · zips.z.cash/zip-0227
- ZIP 230 — Version 6 Transaction Format · zips.z.cash/zip-0230
- ZIP 317 — Proportional Transfer Fee Mechanism · zips.z.cash/zip-0317
- QED-it/orchard (branch zsa1) — core OrchardZSA crate · github.com/QED-it/orchard
- QED-it/librustzcash — ZSA transaction construction fork · github.com/QED-it/librustzcash
- QED-it/zebra (branch zsa-integration-demo) — ZSA node · github.com/QED-it/zebra
- QED-it/zcash_tx_tool (v0.5.0) — reference tx generation & scenarios · github.com/QED-it/zcash_tx_tool
- QED-it/zcash-test-vectors — v6 / ZSA test vectors · github.com/QED-it/zcash-test-vectors