feat: ZID identity + zigner subscribe flow#6
Merged
Conversation
Rewrite sign approval page with two paths: - Mnemonic wallets: review → password confirmation → sign - Zigner wallets: review → show challenge QR → scan response QR Thread isAirgap flag from sign-request listener through popup request system to the approval component. Detect wallet type by reading the selected vault before opening the popup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…proval UI - Add zafu_sign to delegated types in easteregg listener so it doesn't race with the sign-request listener and return "unknown message type" - Add CAPABILITY_APPROVAL to hidden header/tab routes for clean standalone UI - Remove capability pre-check from sign-request listener — the sign approval itself is the permission check - Auto-grant sign_identity capability on successful signature so sites appear in the identity page - Improve test-zid.html with step-by-step developer documentation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The popup closes (window.close) before the async storage write completes, so the share log was never persisted. Move the zidShareLog write and sign_identity capability grant to the service worker side (sign-request.ts) where it runs to completion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the license was cached in chrome.storage.local and persisted across sessions, so a revoked/expired license would still show as pro until the user manually triggered a refresh. Now the server is always the source of truth: - on wallet unlock (via setSessionPassword, unlock, or init auto-unlock) the license is fetched fresh from the server by ZID pubkey - server pro → show pro, server free → show free - server unreachable → show free (offline treated as no subscription) - no local storage reads/writes for license state Removed loadLicense/setLicense slice methods since state lives only in memory now. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…r pay Rework the subscribe flow so both mnemonic and zigner wallets can pay for pro entirely from within zafu: - Add review step with tx summary (amount, duration, recipient, memo) before broadcasting - Gate confirmation behind the password modal (matches zcash-send pattern) - Show live build/broadcast progress with step-by-step timeline from the worker's zcash-send-progress events - For zigner wallets, route to the existing zcash-send flow with prefilled recipient/amount/memo so they can use the QR signing flow - Unify new-subscribe and extend-subscription into a single UI (same month selector, same review flow, button label changes to "extend +N days" when already pro) - Read ZID pubkey from vault.insensitive['zid'] for zigner wallets (no mnemonic available to derive from) - Fix menu drawer to fall back to any vault's ZID when active wallet doesn't have one imported Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- zigner FVK QRs now carry the device ZID pubkey. UR format uses CBOR key 4 in the account map. - importing the same zigner device for both zcash and penumbra no longer creates two vaults. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…g pro Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
These test vectors are shared with zigner/rust/signer/src/auth.rs (test_zid_pubkey_matches_zafu, test_sign_zid_site_specific_matches_zafu). If either repo's derivation drifts, CI catches it in both places instead of silently producing different pubkeys for the same seed — which would break the "same device across zafu and zigner = same identity" guarantee. Uses @vitest-environment node to bypass the jsdom navigator.locks setup issue that blocks existing state tests.
Cuts max witness replay from 50k blocks to 10k blocks, bounding merkle witness build time to ~5s instead of 70s for old notes. Storage cost: ~150 snapshots per year of chain (~300KB) vs ~15 before. Acceptable tradeoff for 10x faster spend on historical notes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kills the 70s "rebuild merkle paths from a checkpoint" on every spend. Witnesses now live in IDB per note and advance alongside sync. Worker changes: - DecryptedNote gains witness_hex + witness_tree_size. - Sync loop maintains a running frontier (persisted with its height). Each batch calls witness_sync_update once, advancing every tracked witness and seeding new ones for notes decrypted in-range. Bootstrap drops stale witnesses to avoid silent drift when refetching frontier. - buildWitnesses has three tiers: extract stored witnesses (fast), fast-forward over sync->tip gap via witness_sync_update, or one-shot build_witnesses_and_paths for pre-upgrade notes (writes back so the next spend takes the fast path). Witness root cross-checked against the network anchor before every spend. Upgrade cost: first spend on a wallet that existed before this change still replays once to seed witnesses; every subsequent spend is near- instant. New wallets never pay the replay cost. Paired with the zafu-wasm APIs added to zcli (witness_sync_update, witness_extract_path, build_witnesses_and_paths). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hitchho
added a commit
that referenced
this pull request
May 16, 2026
…R, stall, provenance Cross-referenced findings from an 8-reviewer audit (redshiftzero, hdevalence, systems, consensus, wallet-UX, QA, supply-chain, release-mgmt). Tractable high-consensus fixes: #1b merkle anchor TOCTOU (QA, BLOCKING — the hardware bug): buildWitnesses anchored at the live tip, where zidecar replicas diverge and reorgs happen, across 3 unsynchronized RPCs → intermittent "tree root mismatch". Decouple: anchorHeight = tip - ANCHOR_CONFIRMATIONS(3); keep target_height at the live tip for branch_id/expiry. Orchard anchors are historical roots with no max-age, so a slightly-behind anchor is fully valid. #1a merkle filter_map (release-mgmt): both sites decode positionally with a precise `sibling i/j not canonical: <hex>` error instead of a lossy generic count error. (zcli commit 2038eb6e.) #2 UFVK validation (security + redshiftzero, BLOCKING): authoritative zcash_keys decode (new wasm `validate_ufvk`) at the persistence boundary in wallet-entries.ts, before any record is written. Throws loud on a bogus UFVK instead of deferring to first-send and poisoning dedup. @repo/wallet stays structural-only and wasm-free. #3 CBOR signed-shift (UX + security): unwrapCborSinglePczt 4-byte length used signed `<<` → high-bit length went negative, bypassed the bounds guard, returned a silently-truncated PCZT. Rewrote with *256 accumulation, per-byte bounds, exact-consume canonical check. TDD: 3 RED adversarial cases → 12/12 green. #4 wasm-init (UX, HIGH): contacts/index.tsx called address_from_ufvk without awaiting the bindgen default() initializer (same class of bug Al fixed in the scanner) — silently degraded contact-card privacy. Added await default(). #5 UR receive stall (UX): no way to distinguish "need more frames" from "dead/corrupt stream" → unbounded "scanning...". Added a 12s no-new-unique-part watchdog that surfaces a hard error via onError. #6 wasm provenance (systems + release-mgmt, SERIOUS): vendored blobs had zero binding to a zcli source rev. Added BUILD_PROVENANCE.md pinning the exact zcli commit + per-artifact sha256 + reproduction commands. Both single-thread and parallel artifacts rebuilt from zcli 2038eb6e. Not done (documented, needs human decision / hardware, NOT silently shipped): - Behavioral merkle-rejection test — needs notes+path fixture infra that doesn't exist; would be a contorted box-tick. Tracked as the remaining coverage gap (matches QA/redshiftzero). - #7 commit hygiene — branch is shared with Al; rewriting history is a coordination hazard. Disposition: curate the squash message at merge and split the unrelated release commits into their own PR off main. Process instruction, not an autonomous shared-history rewrite. - The #1b anchor fix MUST be re-validated on hardware before the merkle bug is claimed resolved. zafu prod build green (browser + worker). zcli tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hitchho
added a commit
that referenced
this pull request
Jun 4, 2026
…aging tip 686d174) Parallel wasm was still at zcli 2038eb6e from PR #6 merge. Rebuilt against staging tip 686d174 which carries: - chore(staging): cap ur_decode_frames inputs (DoS hardening) - chore(staging): fix sled type-inference errors in wallet.rs Re-applied the LOCAL PATCH to snippets/wasm-bindgen-rayon-*/src/workerHelpers.js (stock await import('../../..') is a directory import Chrome extensions reject). Verified shared-imported memory in the rebuilt blob: (import "./zafu_wasm_bg.js" "memory" (memory $mimport$0 51 32768 shared)) New shas: - single-thread (already updated by 524cc75 on Jun 2): dee6a25b604f27397522bbc3c8e143d96c18cfe24d435c3d2ac97ebbb164dfd3 - parallel (this commit): af3359357739b223804a9836ec00c0d2ef970d787627671e7cf0acb9ab923adf STAGING-ONLY commit; the proper landing path is for a fresh wasm rebuild to ride along with the next zcli master merge. Assisted-by: Claude:claude-opus-4-7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Paired with zcli license-server changes: rotkonetworks/zcli#3
Test plan
🤖 Generated with Claude Code