From 032354a4e519e1d10b26ec0a25a36d4662f7ddbe Mon Sep 17 00:00:00 2001 From: blocknodes Date: Sat, 11 Jul 2026 08:08:28 +0000 Subject: [PATCH 1/8] Bump patched shardtree past the 'Tree state inconsistent' scan panic Syncing panicked in a tokio worker at shardtree prunable.rs: 'Tree state inconsistent with checkpoints.' scan_cached_blocks runs on the sync critical path, so this aborted the sync -- the wallet could not finish scanning. Root cause is upstream: the fork pinned incrementalmerkletree at decefc4 (2026-07-06), which panics in clear_flags when it reaches a folded leaf. Commit a59d6ce (2026-07-08), 'shardtree: clear flags across a folded leaf instead of panicking', fixes exactly this. Move the [patch.crates-io] pin to a59d6ce -- the last 0.6.x commit before the shardtree 0.7.0 release, so it carries the fix without the version bump that would break the fork's ^0.6 requirement. Verified the bare panic is gone from the fetched source and the workspace still resolves shardtree 0.6.2 / incrementalmerkletree 0.8.2. Co-Authored-By: Claude Opus 4.8 --- src-tauri/Cargo.lock | 4 ++-- src-tauri/Cargo.toml | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 1a9ea0e..4af35f3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2663,7 +2663,7 @@ dependencies = [ [[package]] name = "incrementalmerkletree" version = "0.8.2" -source = "git+https://github.com/zcash/incrementalmerkletree?rev=decefc469dbf1e686b20b7e7dcaa7cb4f122125b#decefc469dbf1e686b20b7e7dcaa7cb4f122125b" +source = "git+https://github.com/zcash/incrementalmerkletree?rev=a59d6cead254cc5ee90b2143e56fe7258cb8d8a7#a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" dependencies = [ "either", ] @@ -5115,7 +5115,7 @@ dependencies = [ [[package]] name = "shardtree" version = "0.6.2" -source = "git+https://github.com/zcash/incrementalmerkletree?rev=decefc469dbf1e686b20b7e7dcaa7cb4f122125b#decefc469dbf1e686b20b7e7dcaa7cb4f122125b" +source = "git+https://github.com/zcash/incrementalmerkletree?rev=a59d6cead254cc5ee90b2143e56fe7258cb8d8a7#a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" dependencies = [ "bitflags 2.13.0", "either", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c2095e9..85a61a3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -72,7 +72,14 @@ base64 = "0.22" # IRONWOOD/NU6.3 TESTNET SPIKE: the zecrocks librustzcash `ironwood-scan-model` # fork depends on explicit checkpoint-retention shardtree/incrementalmerkletree # (zcash/incrementalmerkletree main, not yet published), so a downstream consumer -# must replicate the fork's patch. Remove once a published shardtree release cut. +# must replicate the fork's patch. +# +# Pinned to a59d6ce ("shardtree: clear flags across a folded leaf instead of +# panicking"), NOT the fork's original decefc4: decefc4 panics with "Tree state +# inconsistent with checkpoints" (prunable.rs) while scanning. a59d6ce is the +# last 0.6.x commit before the shardtree 0.7.0 release, so it carries the fix +# without the version bump that would break the fork's `^0.6` requirement. +# Remove this whole section once the fork moves to a published shardtree. [patch.crates-io] -shardtree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "decefc469dbf1e686b20b7e7dcaa7cb4f122125b" } -incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "decefc469dbf1e686b20b7e7dcaa7cb4f122125b" } +shardtree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" } +incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" } From bc50d978361e4b6e443d3f3bcdcbdd8ac6cc01eb Mon Sep 17 00:00:00 2001 From: blocknodes Date: Fri, 31 Jul 2026 19:05:38 +0000 Subject: [PATCH 2/8] Migrate to published Ironwood crates.io cohort; enable shielded sends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the whole zcash_* cohort off the zecrocks git fork onto published crates, and enable Ironwood/V6 shielded sends now that the upstream PCZT gate is fixed. Dependencies (src-tauri): - orchard 0.15.4, zcash_protocol 0.10.3, zcash_primitives 0.30.0, zcash_keys 0.16.1, zcash_address 0.13, pczt 0.9.1 (all stable); zcash_client_backend 0.24.0-rc.6, zcash_client_sqlite 0.22.0-rc.6 (RCs). - Delete the [patch.crates-io] incrementalmerkletree hack: shardtree 0.7.1 is published and carries the folded-leaf panic fix. Send path (create_pczt_from_proposal now builds V6 with an Ironwood bundle from NU6.3 onward, per zcash_client_backend 0.24.0-rc.2): - Pass proposed_version=None so the backend picks V5/V6 by target height; this is what unblocks shielded sends. Add the new lock_inputs (None) and orchard_pool_padding (BundlePadding::DEFAULT) args. Drop the now-dead ProposalNotSupported / OrchardReceiverRequiresIronwood handling. Pool-aware signing (a post-NU6.3 send can carry both bundles at once — spends in Orchard, payment via Ironwood — so signing can no longer assume one pool): - SpendToSign gains a SpendPool tag; spends_to_sign walks both the Orchard and Ironwood bundles (sign_orchard_with + sign_ironwood_with). - apply_signatures splits signatures by pool and applies each to its bundle. - broadcast_signed proves each present bundle (create_orchard_proof and/or create_ironwood_proof), gated on bundle_presence so an empty bundle's anchor check can't fail the send. Both pools share the PostNu6_3 circuit, so one proving/verifying key serves both (as the extractor already assumes). - Thread the pool tag through the multi-note ceremony and the frontend SpendToSign type. All 30 core tests pass; frontend builds; backend compiles warning-free. Co-Authored-By: Claude Opus 4.8 --- src-tauri/Cargo.lock | 1115 +++++++++++++----------------- src-tauri/Cargo.toml | 15 - src-tauri/core/Cargo.toml | 36 +- src-tauri/core/src/wallet.rs | 266 ++++--- src-tauri/src/commands/wallet.rs | 19 +- src/ipc/commands.ts | 3 + 6 files changed, 688 insertions(+), 766 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 4af35f3..0ddd137 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -75,9 +75,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" dependencies = [ "alloc-no-stdlib", ] @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "argon2" @@ -167,19 +167,19 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -336,9 +336,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitcoin_hashes" -version = "0.14.100" +version = "0.14.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9901a56e133a1fc86eeb1113e2591f45f4682451ca893bff494d2f88918e3f" +checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" dependencies = [ "hex-conservative", ] @@ -351,18 +351,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" dependencies = [ "serde_core", ] [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -447,14 +447,14 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dc0086e469182132244e9b8d313a0742e1132da43a08c24b9dd3c18e0faf3a" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "brotli" -version = "8.0.3" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -463,9 +463,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.1" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -489,9 +489,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -501,9 +501,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" dependencies = [ "serde", ] @@ -514,7 +514,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cairo-sys-rs", "glib", "libc", @@ -535,9 +535,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.2" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" dependencies = [ "serde_core", ] @@ -562,7 +562,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.63" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "shlex", @@ -629,9 +629,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" @@ -646,9 +646,9 @@ dependencies = [ [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", "cpufeatures 0.3.0", @@ -693,9 +693,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "301b56658598e48f3648647ac6fc887be7e7108eddfa4e9b63fcf3ec58c0cadf" dependencies = [ "clap_builder", "clap_derive", @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "94a65403d1a1bd28f7dc68eb8506e8874808ee5eecb59298de588e2e1407a078" dependencies = [ "anstream", "anstyle", @@ -715,14 +715,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -737,7 +737,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -806,7 +806,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation", "core-graphics-types", "foreign-types", @@ -819,7 +819,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation", "libc", ] @@ -865,18 +865,18 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -884,18 +884,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" @@ -943,7 +943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -996,7 +996,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1010,9 +1010,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ "darling_core", "darling_macro", @@ -1020,27 +1020,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1051,9 +1050,9 @@ checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "dbus" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" dependencies = [ "libc", "libdbus-sys", @@ -1078,12 +1077,11 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1094,7 +1092,7 @@ checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1105,7 +1103,7 @@ checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1126,7 +1124,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1199,7 +1197,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "libc", "objc2", @@ -1207,13 +1205,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -1236,7 +1234,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1340,20 +1338,20 @@ dependencies = [ [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" [[package]] name = "embed-resource" -version = "3.0.9" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" dependencies = [ "cc", "memchr", "rustc_version", - "toml 1.1.2+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", "vswhom", "winreg", ] @@ -1388,7 +1386,8 @@ dependencies = [ [[package]] name = "equihash" version = "0.3.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306286e8dcc39ab3dfceb74c792ce8baffdab90591321d3ffaae64829734c37f" dependencies = [ "blake2b_simd", "corez", @@ -1434,7 +1433,8 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.1" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d42773cb15447644d170be20231a3268600e0c4cea8987d013b93ac973d3cf7" dependencies = [ "blake2b_simd", ] @@ -1453,9 +1453,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fdeflate" @@ -1557,13 +1557,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -1607,7 +1607,7 @@ dependencies = [ "frost-rerandomized 2.2.0", "hex", "postcard", - "rand 0.8.6", + "rand 0.8.7", "reddsa 0.5.1", "serde", "serde_json", @@ -1615,7 +1615,7 @@ dependencies = [ "tauri-build", "tauri-plugin-shell", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tracing", @@ -1645,7 +1645,7 @@ dependencies = [ "pczt", "postcard", "prost", - "rand 0.8.6", + "rand 0.8.7", "rcgen", "reddsa 0.5.1", "reqwest 0.12.28", @@ -1654,7 +1654,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "toml 0.8.23", @@ -1688,7 +1688,7 @@ dependencies = [ "itertools", "message-io", "postcard", - "rand 0.8.6", + "rand 0.8.7", "reddsa 0.5.1", "reqwest 0.12.28", "rpassword", @@ -1698,7 +1698,7 @@ dependencies = [ "snow", "stable-eyre", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "toml 0.8.23", "uuid", @@ -1723,7 +1723,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "serdect 0.2.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "visibility", "zeroize", ] @@ -1744,7 +1744,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "serdect 0.2.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "visibility", "zeroize", "zeroize_derive", @@ -1798,24 +1798,24 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" dependencies = [ "futures-core", "futures-task", @@ -1824,38 +1824,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-core", "futures-io", @@ -1996,25 +1996,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", - "wasip2", - "wasip3", + "wasm-bindgen", ] [[package]] @@ -2025,7 +2023,7 @@ checksum = "6cf442baaabe4213ce7d1239afc26c039180b6456da2cededa316ae2c8a77a77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2082,7 +2080,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "futures-channel", "futures-core", "futures-executor", @@ -2110,7 +2108,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2125,9 +2123,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "gobject-sys" @@ -2201,7 +2199,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2237,7 +2235,7 @@ dependencies = [ "halo2_proofs", "lazy_static", "pasta_curves", - "rand 0.8.6", + "rand 0.8.7", "sinsemilla", "subtle", "uint", @@ -2263,9 +2261,9 @@ dependencies = [ [[package]] name = "halo2_proofs" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05713f117155643ce10975e0bee44a274bcda2f4bb5ef29a999ad67c1fa8d4d3" +checksum = "5f63a999d9223fa9d3b9db3031fedc316e6039a0ae0f67394408b16ef670c69f" dependencies = [ "blake2b_simd", "ff", @@ -2385,9 +2383,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -2395,9 +2393,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http", @@ -2405,9 +2403,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" dependencies = [ "bytes", "futures-core", @@ -2439,9 +2437,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" dependencies = [ "atomic-waker", "bytes", @@ -2505,7 +2503,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.4", + "socket2 0.6.5", "tokio", "tower-service", "tracing", @@ -2627,12 +2625,6 @@ dependencies = [ "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" @@ -2663,7 +2655,8 @@ dependencies = [ [[package]] name = "incrementalmerkletree" version = "0.8.2" -source = "git+https://github.com/zcash/incrementalmerkletree?rev=a59d6cead254cc5ee90b2143e56fe7258cb8d8a7#a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30821f91f0fa8660edca547918dc59812893b497d07c1144f326f07fdd94aba9" dependencies = [ "either", ] @@ -2831,14 +2824,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "js-sys" -version = "0.3.100" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2025f20d7a4fa7785846e7b63d10a76d3f1cee98ee5cb79ea59703f95e42162" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", @@ -2887,7 +2880,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "serde", "unicode-segmentation", ] @@ -2901,12 +2894,6 @@ dependencies = [ "spin", ] -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libappindicator" version = "0.9.0" @@ -2933,9 +2920,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libdbus-sys" @@ -2964,9 +2951,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "libc", ] @@ -3012,9 +2999,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru-slab" @@ -3045,9 +3032,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memoffset" @@ -3139,9 +3126,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "wasi", @@ -3150,9 +3137,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.19.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a2e3dff89cd322c66647942668faee0a2b1f88ea6cbb4d374b4a8d7e92528c" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" dependencies = [ "crossbeam-channel", "dpi", @@ -3165,7 +3152,7 @@ dependencies = [ "once_cell", "png 0.18.1", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows-sys 0.61.2", ] @@ -3190,7 +3177,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -3244,9 +3231,9 @@ checksum = "549e471b99ccaf2f89101bec68f4d244457d5a95a9c3d0672e9564124397741d" [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -3254,9 +3241,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -3306,7 +3293,7 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -3325,7 +3312,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-core-foundation", @@ -3338,7 +3325,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-foundation", ] @@ -3359,7 +3346,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "objc2", ] @@ -3370,7 +3357,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "objc2", "objc2-core-foundation", @@ -3403,7 +3390,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", "objc2-core-graphics", @@ -3430,7 +3417,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-core-foundation", @@ -3442,7 +3429,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", ] @@ -3453,7 +3440,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -3465,7 +3452,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-cloud-kit", @@ -3496,7 +3483,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-app-kit", @@ -3533,14 +3520,13 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open" -version = "5.3.5" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fbaa89d2ddc8473c78a3adf69eea8cffa28c483b8e02a971ef31527cd0fc92c" +checksum = "a0b3d059e795d52b8a72fef45658620edd4d9c359b338564aa14391ffa511ed5" dependencies = [ "dunce", "is-wsl", "libc", - "pathdiff", ] [[package]] @@ -3560,9 +3546,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -3579,9 +3565,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orchard" -version = "0.15.0-pre.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77752de9c2865ca4a0d962b201b473d60bbe438d53a964a8707ec4bd401d631" +checksum = "793e2e8c2323f35f082d1b3467ca8f576d646f9c93aef8c5168809d099245af8" dependencies = [ "aes", "bitvec", @@ -3600,7 +3586,7 @@ dependencies = [ "memuse", "nonempty", "pasta_curves", - "rand 0.8.6", + "rand 0.8.7", "rand_core 0.6.4", "reddsa 0.5.2", "serde", @@ -3693,29 +3679,24 @@ dependencies = [ [[package]] name = "pasta_curves" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +checksum = "3437083215c505e867eea5478371feba43d7689d6d15ec0a209eb46fb0d4cda6" dependencies = [ "blake2b_simd", "ff", "group", "lazy_static", - "rand 0.8.6", + "rand 0.8.7", "static_assertions", "subtle", ] -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "pczt" -version = "0.7.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d4693dcb3d72f30064e0fdab122292d803bd9325a95b25df08679cf895452f" dependencies = [ "blake2b_simd", "bls12_381", @@ -3818,7 +3799,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -3847,7 +3828,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -3874,9 +3855,9 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plist" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" dependencies = [ "base64 0.22.1", "indexmap 2.14.0", @@ -3904,7 +3885,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crc32fast", "fdeflate", "flate2", @@ -3984,7 +3965,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4012,7 +3993,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.12+spec-1.1.0", + "toml_edit 0.25.13+spec-1.1.0", ] [[package]] @@ -4041,9 +4022,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -4073,7 +4054,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.117", + "syn 2.0.119", "tempfile", ] @@ -4087,7 +4068,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4101,18 +4082,18 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", @@ -4121,8 +4102,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.4", - "thiserror 2.0.18", + "socket2 0.6.5", + "thiserror 2.0.19", "tokio", "tracing", "web-time", @@ -4130,20 +4111,21 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", - "rand 0.9.4", + "rand 0.10.2", + "rand_pcg", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "web-time", @@ -4151,23 +4133,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.4", + "socket2 0.6.5", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -4192,33 +4174,23 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "libc", - "rand_chacha 0.3.1", + "rand_chacha", "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ - "chacha20 0.10.0", - "getrandom 0.4.2", + "chacha20 0.10.1", + "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -4232,16 +4204,6 @@ dependencies = [ "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" @@ -4251,15 +4213,6 @@ 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 = "rand_core" version = "0.10.1" @@ -4273,7 +4226,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.7", +] + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", ] [[package]] @@ -4348,7 +4310,7 @@ dependencies = [ "pasta_curves", "rand_core 0.6.4", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "zeroize", ] @@ -4370,7 +4332,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -4392,34 +4354,34 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "regex" -version = "1.12.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -4429,9 +4391,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" dependencies = [ "aho-corasick", "memchr", @@ -4575,7 +4537,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -4587,15 +4549,15 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -4612,7 +4574,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys", @@ -4621,9 +4583,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "log", "once_cell", @@ -4648,9 +4610,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "web-time", "zeroize", @@ -4669,9 +4631,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -4711,7 +4673,7 @@ dependencies = [ "jubjub", "lazy_static", "memuse", - "rand 0.8.6", + "rand 0.8.7", "rand_core 0.6.4", "redjubjub", "subtle", @@ -4759,9 +4721,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" dependencies = [ "dyn-clone", "ref-cast", @@ -4778,7 +4740,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4844,7 +4806,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation", "core-foundation-sys", "libc", @@ -4867,7 +4829,7 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cssparser", "derive_more 2.1.1", "log", @@ -4892,9 +4854,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -4914,22 +4876,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -4940,14 +4902,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -4958,13 +4920,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -4999,17 +4961,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.17.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64 0.22.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.0", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.2", "serde_core", "serde_json", "serde_with_macros", @@ -5018,14 +4981,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.17.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5067,7 +5030,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5081,9 +5044,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", @@ -5114,10 +5077,11 @@ dependencies = [ [[package]] name = "shardtree" -version = "0.6.2" -source = "git+https://github.com/zcash/incrementalmerkletree?rev=a59d6cead254cc5ee90b2143e56fe7258cb8d8a7#a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8147447aed7be4736e271825b8c3a4432efb7182e71363169b572371ddef452e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "either", "incrementalmerkletree", "tracing", @@ -5182,9 +5146,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "sinsemilla" @@ -5243,9 +5207,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -5301,9 +5265,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" dependencies = [ "lock_api", ] @@ -5423,9 +5387,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -5449,7 +5424,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5471,7 +5446,7 @@ version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "core-foundation", "core-graphics", @@ -5507,13 +5482,13 @@ dependencies = [ [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5530,9 +5505,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.11.2" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437404997acf375d85f1177afa7e11bb971f274ed6a7b83a2a3e339015f4cc28" +checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" dependencies = [ "anyhow", "bytes", @@ -5569,7 +5544,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tray-icon", "url", @@ -5581,9 +5556,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa1f9055fc23919a54e4e125052bed16ed04aef0487086e758fe01a67b451c7" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" dependencies = [ "anyhow", "cargo_toml", @@ -5602,9 +5577,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a0319528a025a38c4078e7dae2c446f4e63620ddb0659a643ede1cb38f90e9" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" dependencies = [ "base64 0.22.1", "brotli", @@ -5618,9 +5593,9 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "syn 2.0.117", + "syn 2.0.119", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "url", "uuid", @@ -5629,23 +5604,23 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6cb4e3896c21d2f6da5b31251d2faea0153bba56ed0e970f918115dbee4924" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e126abc9e84e35cdfd01596140a73a1850cdb0df0a23acf0185776c30b469a6e" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" dependencies = [ "anyhow", "glob", @@ -5674,15 +5649,15 @@ dependencies = [ "shared_child", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", ] [[package]] name = "tauri-runtime" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48222d7116c8807eaa6fe2f372e023fae125084e61e6eca6d70b7961cdf129ef" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" dependencies = [ "cookie", "dpi", @@ -5696,7 +5671,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "webkit2gtk", "webview2-com", @@ -5705,9 +5680,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.11.2" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" dependencies = [ "gtk", "http", @@ -5731,9 +5706,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092379df9a707631978e6c56b1bc2401d387f01e2d4a3c123360d167bbb9aa95" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "brotli", @@ -5759,8 +5734,8 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.19", + "toml 1.1.4+spec-1.1.0", "url", "urlpattern", "uuid", @@ -5775,7 +5750,7 @@ checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ "dunce", "embed-resource", - "toml 1.1.2+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", ] [[package]] @@ -5785,7 +5760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -5793,12 +5768,11 @@ dependencies = [ [[package]] name = "tendril" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ "new_debug_unreachable", - "utf-8", ] [[package]] @@ -5812,11 +5786,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.19", ] [[package]] @@ -5827,46 +5801,45 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "time" -version = "0.3.37" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -5884,9 +5857,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" dependencies = [ "tinyvec_macros", ] @@ -5899,30 +5872,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.52.3" +version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ "bytes", "libc", - "mio 1.2.1", + "mio 1.2.2", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.4", + "socket2 0.6.5", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -5937,9 +5910,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" dependencies = [ "futures-core", "pin-project-lite", @@ -5948,13 +5921,14 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" dependencies = [ "bytes", "futures-core", "futures-sink", + "libc", "pin-project-lite", "tokio", ] @@ -5988,9 +5962,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap 2.14.0", "serde_core", @@ -5998,7 +5972,7 @@ dependencies = [ "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -6066,23 +6040,23 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap 2.14.0", "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -6093,9 +6067,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tonic" @@ -6115,7 +6089,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.4", + "socket2 0.6.5", "sync_wrapper", "tokio", "tokio-rustls", @@ -6136,7 +6110,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6161,7 +6135,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.117", + "syn 2.0.119", "tempfile", "tonic-build", ] @@ -6191,7 +6165,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bytes", "futures-util", "http", @@ -6234,7 +6208,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6248,9 +6222,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.23.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773" +checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" dependencies = [ "crossbeam-channel", "dirs 6.0.0", @@ -6264,7 +6238,7 @@ dependencies = [ "once_cell", "png 0.18.1", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows-sys 0.61.2", ] @@ -6286,7 +6260,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.8.6", + "rand 0.8.7", "sha1", "thiserror 1.0.69", "url", @@ -6379,12 +6353,6 @@ version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "universal-hash" version = "0.5.1" @@ -6446,13 +6414,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.3" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.4.3", "js-sys", - "rand 0.10.1", + "rand 0.10.2", "serde_core", "wasm-bindgen", ] @@ -6483,7 +6451,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6533,27 +6501,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "wit-bindgen 0.57.1", -] - -[[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 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.123" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a254a4b10c19a76f09a27640e7ffbf9bc30bf67e16a3bf28aaefa4920fe81563" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -6564,9 +6523,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.73" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54568702fabf5d4849ce2b90fadfa64168a097eaf4b351ce9df8b687a0086aaf" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ "js-sys", "wasm-bindgen", @@ -6574,9 +6533,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.123" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a40fc75b0ec6f3746ceb10d36f53a93dcd68a93b11b6445983945d79eba0dc" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6584,48 +6543,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.123" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "908f34bd9b9ce3d4caf07b72dfab63d61504d156856c6bd3cd87fa350cf3985b" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.123" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acbf7616c27b194bbb550bf77ed0c2c3e5b7fd1260a93082b95fb7f47959b92" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" 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.14.0", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.5.0" @@ -6639,23 +6576,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.13.0", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver", -] - [[package]] name = "web-sys" -version = "0.3.100" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0871acf327f283dc6da28a1696cdc64fb355ba9f935d052021fa77f35cce69" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -6673,9 +6598,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" dependencies = [ "phf", "phf_codegen", @@ -6729,9 +6654,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -6758,7 +6683,7 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6767,16 +6692,16 @@ version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", "windows", "windows-core 0.61.2", ] [[package]] name = "which" -version = "8.0.4" +version = "8.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" +checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" dependencies = [ "libc", ] @@ -6894,7 +6819,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6905,7 +6830,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -7301,9 +7226,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -7318,100 +7243,12 @@ dependencies = [ "windows-sys 0.59.0", ] -[[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" version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" -[[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.14.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 2.13.0", - "indexmap 2.14.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.14.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - [[package]] name = "writeable" version = "0.6.3" @@ -7451,7 +7288,7 @@ dependencies = [ "sha2 0.10.9", "soup3", "tao-macros", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "webkit2gtk", "webkit2gtk-sys", @@ -7514,7 +7351,7 @@ dependencies = [ "derive_more 0.99.20", "ed25519", "ed25519-dalek", - "rand 0.8.6", + "rand 0.8.7", "sha2 0.10.9", "x25519-dalek", "zeroize", @@ -7548,14 +7385,15 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "synstructure", ] [[package]] name = "zcash_address" -version = "0.13.0-pre.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a854b28c07dba372f4410ea8ad62b4bf7d5c2bf8be32fc4b31bc0db6521a975" dependencies = [ "bech32", "bs58", @@ -7567,8 +7405,9 @@ dependencies = [ [[package]] name = "zcash_client_backend" -version = "0.23.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.24.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832ace878c125814bb9e82228d3661499124c6f2936e60fc1df3c6876eb54624" dependencies = [ "async-trait", "base64 0.22.1", @@ -7602,7 +7441,6 @@ dependencies = [ "shardtree", "subtle", "time", - "time-core", "tonic", "tonic-prost", "tonic-prost-build", @@ -7622,11 +7460,12 @@ dependencies = [ [[package]] name = "zcash_client_sqlite" -version = "0.21.1" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.22.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a789c0038359968f93bfe3952d2b942e3bae5582f79c2f31137c6fd736a225" dependencies = [ "bip32", - "bitflags 2.13.0", + "bitflags 2.13.1", "bs58", "byteorder", "document-features", @@ -7638,7 +7477,7 @@ dependencies = [ "nonempty", "orchard", "prost", - "rand 0.8.6", + "rand 0.8.7", "rand_core 0.6.4", "rand_distr", "regex", @@ -7659,6 +7498,7 @@ dependencies = [ "zcash_client_backend", "zcash_encoding", "zcash_keys", + "zcash_pool_migration", "zcash_primitives", "zcash_protocol", "zcash_script", @@ -7669,7 +7509,8 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.4.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1440921903cdb86133fb9e2fe800be488015db2939a30bedb413078a1acb0306" dependencies = [ "corez", "hex", @@ -7678,8 +7519,9 @@ dependencies = [ [[package]] name = "zcash_keys" -version = "0.15.0-pre.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def800f128e459eedebc900f36f408eaf0687634128dcf64ecfeaeebc3e16c14" dependencies = [ "bech32", "bip32", @@ -7707,9 +7549,9 @@ dependencies = [ [[package]] name = "zcash_note_encryption" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77efec759c3798b6e4d829fcc762070d9b229b0f13338c40bf993b7b609c2272" +checksum = "e1cb1b9170c94370e3d66c5cc0877661db743337588b64de7711239eed462198" dependencies = [ "chacha20 0.9.1", "chacha20poly1305", @@ -7718,10 +7560,32 @@ dependencies = [ "subtle", ] +[[package]] +name = "zcash_pool_migration" +version = "0.1.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9010904169a92805128b3a8eab0dd4ff79fd164dd416af68aaeac5c7ebbd2522" +dependencies = [ + "corez", + "getset", + "incrementalmerkletree", + "libm", + "orchard", + "pczt", + "rand_core 0.6.4", + "shardtree", + "zcash_client_backend", + "zcash_keys", + "zcash_primitives", + "zcash_protocol", + "zip32", +] + [[package]] name = "zcash_primitives" -version = "0.29.0-pre.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ca4de11896f704ffe6319c2cd7bc8fc6ab31a55cec80d26def15c009d83678" dependencies = [ "blake2b_simd", "block-buffer 0.11.0-rc.3", @@ -7750,8 +7614,9 @@ dependencies = [ [[package]] name = "zcash_protocol" -version = "0.10.0-pre.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f074493fff337207e28bcfa5bbdf0e2a125c4203a4bdd07e72067eea81e9e7b" dependencies = [ "corez", "document-features", @@ -7767,14 +7632,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f872800287d118be71bdf6fe8c869c6a6ff6fb0a5762f68fb2af54c97edf0f2" dependencies = [ "bip32", - "bitflags 2.13.0", + "bitflags 2.13.1", "bounded-vec", "hex", "ripemd 0.1.3", "secp256k1", "sha1", "sha2 0.10.9", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -7788,8 +7653,9 @@ dependencies = [ [[package]] name = "zcash_transparent" -version = "0.9.0-pre.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "547c012778bae17f58007731af074d638aa146ab0ecfc120adebf23d049aff6c" dependencies = [ "bip32", "bs58", @@ -7812,22 +7678,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -7847,15 +7713,15 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "serde", "zeroize_derive", @@ -7863,13 +7729,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -7902,7 +7768,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -7920,8 +7786,9 @@ dependencies = [ [[package]] name = "zip321" -version = "0.8.0" -source = "git+https://github.com/zecrocks/librustzcash?branch=ironwood-scan-model#71da9dddc194f8adf003b14c7957d03a4836c3cd" +version = "0.9.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb464491970d9b61889e4f2b7b00fb9f471a33692e5c0de3122fdc575d8067ab" dependencies = [ "base64 0.22.1", "nom", @@ -7932,6 +7799,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 85a61a3..ec56688 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -68,18 +68,3 @@ dirs = "5" tracing = "0.1" sha2 = "0.10" base64 = "0.22" - -# IRONWOOD/NU6.3 TESTNET SPIKE: the zecrocks librustzcash `ironwood-scan-model` -# fork depends on explicit checkpoint-retention shardtree/incrementalmerkletree -# (zcash/incrementalmerkletree main, not yet published), so a downstream consumer -# must replicate the fork's patch. -# -# Pinned to a59d6ce ("shardtree: clear flags across a folded leaf instead of -# panicking"), NOT the fork's original decefc4: decefc4 panics with "Tree state -# inconsistent with checkpoints" (prunable.rs) while scanning. a59d6ce is the -# last 0.6.x commit before the shardtree 0.7.0 release, so it carries the fix -# without the version bump that would break the fork's `^0.6` requirement. -# Remove this whole section once the fork moves to a published shardtree. -[patch.crates-io] -shardtree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" } -incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "a59d6cead254cc5ee90b2143e56fe7258cb8d8a7" } diff --git a/src-tauri/core/Cargo.toml b/src-tauri/core/Cargo.toml index b8c2d8e..108f655 100644 --- a/src-tauri/core/Cargo.toml +++ b/src-tauri/core/Cargo.toml @@ -35,24 +35,24 @@ base64 = { workspace = true } # which breaks against xeddsa 1.1 (rand_core trait changes). xeddsa = "=1.0.2" -# Optional Zcash key/address derivation (spike). Behind a feature so the heavy +# Optional Zcash key/address derivation. Behind a feature so the heavy # orchard/halo2 dependency tree stays out of the default build. # -# IRONWOOD/NU6.3 TESTNET SPIKE: the zcash_* cohort is pinned to zecrocks' -# librustzcash fork branch `ironwood-scan-model`, which carries the real testnet -# NU6.3 branch id (0x37a5165b) plus the Ironwood send path + turnstile -# enforcement. orchard moves to 0.15.0-pre.2 (still ships `unstable-frost`). -# These are PRE-RELEASE deps appropriate for a testnet build only. See -# src-tauri/Cargo.toml for the required [patch.crates-io] incrementalmerkletree -# pin the fork depends on. -orchard = { version = "0.15.0-pre.2", optional = true, features = ["unstable-frost"] } -zcash_address = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true } +# IRONWOOD/NU6.3: the zcash_* cohort tracks the PUBLISHED crates.io release wave +# (no git fork, no [patch.crates-io]). These carry the real NU6.3 branch id +# (0x37a5165b) and, crucially, Ironwood/V6 PCZT construction +# (zcash_client_backend 0.24 builds a version-6 tx with an Ironwood bundle from +# NU6.3 onward). orchard stays on the `unstable-frost` feature Cyze's threshold +# signing needs. zcash_client_backend/sqlite are release candidates; the rest +# are stable. +orchard = { version = "0.15.4", optional = true, features = ["unstable-frost"] } +zcash_address = { version = "0.13", optional = true } pasta_curves = { version = "0.5", optional = true } ff = { version = "0.13", optional = true } -# Wallet/light-client stack (feature `wallet`, spike 5.0). Heavy: pulls the -# zcash light-client backend, lightwalletd gRPC, PCZT builder, and sqlite. -zcash_client_backend = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true, default-features = false, features = [ +# Wallet/light-client stack (feature `wallet`). Heavy: pulls the zcash +# light-client backend, lightwalletd gRPC, PCZT builder, and sqlite. +zcash_client_backend = { version = "=0.24.0-rc.6", optional = true, default-features = false, features = [ "orchard", "sync", "lightwalletd-tonic", @@ -60,10 +60,10 @@ zcash_client_backend = { git = "https://github.com/zecrocks/librustzcash", branc "lightwalletd-tonic-tls-webpki-roots", "pczt", ] } -zcash_client_sqlite = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true, features = ["orchard", "transparent-inputs", "unstable", "serde"] } -pczt = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true, features = ["signer"] } -zcash_keys = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true, features = ["orchard"] } -zcash_protocol = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true } +zcash_client_sqlite = { version = "=0.22.0-rc.6", optional = true, features = ["orchard", "transparent-inputs", "unstable", "serde"] } +pczt = { version = "0.9.1", optional = true, features = ["signer"] } +zcash_keys = { version = "0.16.1", optional = true, features = ["orchard"] } +zcash_protocol = { version = "0.10.3", optional = true } tonic = { version = "0.14", optional = true, default-features = false, features = ["transport", "tls-webpki-roots"] } # SQLCipher (bundled amalgamation) so the per-group wallet database is encrypted # at rest. Feature-unifies with zcash_client_sqlite's `bundled` rusqlite: the @@ -73,7 +73,7 @@ tonic = { version = "0.14", optional = true, default-features = false, features rusqlite = { version = "0.37", optional = true, features = ["bundled-sqlcipher-vendored-openssl"] } prost = { version = "0.14", optional = true } async-trait = { version = "0.1", optional = true } -zcash_primitives = { git = "https://github.com/zecrocks/librustzcash", branch = "ironwood-scan-model", optional = true } +zcash_primitives = { version = "0.30.0", optional = true } [features] # Orchard FVK / unified-address derivation from group key material. diff --git a/src-tauri/core/src/wallet.rs b/src-tauri/core/src/wallet.rs index 3949024..ea08145 100644 --- a/src-tauri/core/src/wallet.rs +++ b/src-tauri/core/src/wallet.rs @@ -823,11 +823,26 @@ pub async fn sync_group( Ok(()) } -/// One Orchard spend that the group must FROST-sign: its action index and the -/// per-spend re-randomization value α (hex of the canonical scalar encoding), -/// which becomes the FROST coordinator's `randomizer` for that signature. +/// Which shielded pool an action belongs to. Post-NU6.3 a single transaction can +/// carry both bundles at once — e.g. a turnstile send spends Orchard notes (an +/// Orchard-bundle action) while delivering the payment through the Ironwood +/// bundle — so every spend must record which bundle holds it. The two bundles +/// use the same `orchard::pczt` types, so signing differs only in which +/// low-level-signer method reaches the bundle. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum SpendPool { + Orchard, + Ironwood, +} + +/// One shielded spend the group must FROST-sign: which pool's bundle holds it, +/// its action index within that bundle, and the per-spend re-randomization value +/// α (hex of the canonical scalar encoding), which becomes the FROST +/// coordinator's `randomizer` for that signature. #[derive(Debug, Clone, Serialize)] pub struct SpendToSign { + pub pool: SpendPool, pub index: usize, pub alpha_hex: String, } @@ -878,9 +893,8 @@ pub async fn prepare_send( db_key: &[u8], ) -> Result { use zcash_keys::address::Address; - use zcash_primitives::transaction::TxVersion; use zcash_protocol::value::Zatoshis; - use zcash_protocol::ShieldedProtocol; + use zcash_protocol::ShieldedPool; let params = network.params(); let (db_path, _) = wallet_paths(data_dir, group_id); @@ -934,17 +948,13 @@ pub async fn prepare_send( }) }; - // Constrain the proposal to a version-5 transaction so it matches what the - // PCZT builder can actually construct. - // - // `create_pczt_from_proposal` hardcodes TxVersion::V5 and rejects any step - // that touches the Ironwood pool ("PCZT construction cannot yet produce an - // Ironwood bundle"). Left unconstrained (`None`), the proposal is free to - // route the payment or its change through Ironwood — which post-NU6.3 it - // will, since the Orchard pool is sealed — and the PCZT builder then fails - // with the opaque `ProposalNotSupported`. Passing the version here makes the - // proposal itself avoid Ironwood, so an unbuildable plan is rejected during - // proposal (with a specific reason) rather than after input selection. + // Let the backend choose the transaction version from the target height: + // version 6 (carrying an Ironwood bundle) once NU6.3 is active, version 5 + // before it. Passing `None` is what enables Ironwood sends — post-NU6.3 the + // Orchard pool is sealed, so a shielded payment to a unified address is + // delivered through the Ironwood bundle of a V6 transaction. `lock_inputs` + // is None: Cyze builds and signs one transaction at a time, so there is no + // need to reserve inputs across concurrent proposals. let proposal = propose_standard_transfer_to_address::<_, _, std::convert::Infallible>( &mut db, ¶ms, @@ -955,8 +965,9 @@ pub async fn prepare_send( amount, memo_bytes, None, // change memo - ShieldedProtocol::Orchard, - Some(TxVersion::V5), + ShieldedPool::Orchard, + None, // lock_inputs + None, // proposed_version: derive V5/V6 from the target height ) .map_err(|e| CoreError::Ceremony(format!("propose transfer: {e:?}")))?; @@ -968,23 +979,12 @@ pub async fn prepare_send( account_id, OvkPolicy::Sender, &proposal, - None, // target_expiry_height: use the proposal's default expiry + None, // expiry_height: use the proposal's default expiry + // Orchard-bundle padding; the Ironwood bundle derives its own from the + // proposal so it matches the action count the fee was computed from. + zcash_primitives::transaction::builder::BundlePadding::DEFAULT, ) - .map_err(|e| match e { - // The PCZT builder only emits version-5 transactions, so it refuses any - // plan that moves value through the Ironwood pool. Cyze signs via PCZT - // (FROST needs it to expose each spend's α and to apply the group's - // signature), so there is no fallback path until the Zcash crates can - // build Ironwood PCZTs. - zcash_client_backend::data_api::error::Error::ProposalNotSupported => CoreError::Ceremony( - "this transaction needs the Ironwood pool, which the Zcash PCZT builder \ - cannot construct yet (it only builds version-5 transactions). Since \ - NU6.3 sealed the Orchard pool, shielded sends and shielded change now \ - require Ironwood. Unshielding to a transparent address may still work." - .to_string(), - ), - other => CoreError::Ceremony(format!("create pczt: {other:?}")), - })?; + .map_err(|e| CoreError::Ceremony(format!("create pczt: {e:?}")))?; // Ironwood cohort: Pczt::serialize now consumes self and returns Result // (postcard EncodingError). Serialize a clone since `pczt` is still needed @@ -999,9 +999,9 @@ pub async fn prepare_send( .map_err(|e| CoreError::Ceremony(format!("signer: {e:?}")))? .shielded_sighash(); - // Read each real Orchard spend's α (the re-randomization the FROST signers - // must use). Dummy padding actions have zero value and are skipped. - let spends = orchard_spends_to_sign(pczt)?; + // Read each real spend's α (the re-randomization the FROST signers must + // use), across both the Orchard and Ironwood bundles. + let spends = spends_to_sign(pczt)?; Ok(DraftTransaction { pczt_hex, @@ -1015,47 +1015,81 @@ pub async fn prepare_send( }) } -/// Extract the (index, α) of each real Orchard spend in a PCZT. Requires -/// orchard's `unstable-frost` feature (which exposes `spend().alpha()`). -fn orchard_spends_to_sign(pczt: pczt::Pczt) -> Result, CoreError> { +/// Collect every real spend the group must sign, across both the Orchard and +/// Ironwood bundles, tagged with its pool and α. Requires orchard's +/// `unstable-frost` feature (which exposes `spend().alpha()`). Dummy padding +/// actions (zero value) are skipped. Orchard spends are listed first, then +/// Ironwood; the order only needs to be stable, since each spend carries its own +/// pool + index for application. +fn spends_to_sign(pczt: pczt::Pczt) -> Result, CoreError> { use ff::PrimeField; use orchard::value::NoteValue; - use pczt::roles::low_level_signer::OrchardParseError; + use pczt::roles::low_level_signer::{OrchardParseError, Signer}; + + // Append the real spends of one already-parsed bundle, tagging their pool. + fn collect(bundle: &orchard::pczt::Bundle, pool: SpendPool, out: &mut Vec) { + for (index, action) in bundle.actions().iter().enumerate() { + let is_real = action.spend().value().is_some_and(|v| v != NoteValue::default()); + if let (true, Some(alpha)) = (is_real, action.spend().alpha()) { + out.push(SpendToSign { + pool, + index, + alpha_hex: hex::encode(alpha.to_repr()), + }); + } + } + } let mut spends = Vec::new(); - let mut parse_err: Option = None; - pczt::roles::low_level_signer::Signer::new(pczt) + let signer = Signer::new(pczt) .sign_orchard_with(|_pczt, bundle, _| { - for (index, action) in bundle.actions().iter().enumerate() { - let is_real = action.spend().value().is_some_and(|v| v != NoteValue::default()); - if let (true, Some(alpha)) = (is_real, action.spend().alpha()) { - spends.push(SpendToSign { - index, - alpha_hex: hex::encode(alpha.to_repr()), - }); - } - } + collect(bundle, SpendPool::Orchard, &mut spends); Ok::<_, OrchardParseError>(()) }) - .map_err(|e: OrchardParseError| { - parse_err = Some(format!("{e:?}")); + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("read orchard spends: {e:?}")))?; + signer + .sign_ironwood_with(|_pczt, bundle, _| { + collect(bundle, SpendPool::Ironwood, &mut spends); + Ok::<_, OrchardParseError>(()) }) - .ok(); - if let Some(e) = parse_err { - return Err(CoreError::Ceremony(format!("read orchard spends: {e}"))); - } + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("read ironwood spends: {e:?}")))?; Ok(spends) } -/// Apply FROST-produced Orchard spend-auth signatures to a draft PCZT, returning -/// the signed PCZT (hex). `signatures` are (spend index, 64-byte sig hex). -pub fn apply_orchard_signatures( +/// Whether the PCZT carries any actions in each pool's bundle, as +/// `(orchard, ironwood)`. Used to prove only the bundles a transaction actually +/// has — proving an empty bundle fails its anchor check. +fn bundle_presence(pczt: &pczt::Pczt) -> Result<(bool, bool), CoreError> { + use pczt::roles::low_level_signer::{OrchardParseError, Signer}; + + let mut has_orchard = false; + let mut has_ironwood = false; + let signer = Signer::new(pczt.clone()) + .sign_orchard_with(|_pczt, bundle, _| { + has_orchard = !bundle.actions().is_empty(); + Ok::<_, OrchardParseError>(()) + }) + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("read orchard bundle: {e:?}")))?; + signer + .sign_ironwood_with(|_pczt, bundle, _| { + has_ironwood = !bundle.actions().is_empty(); + Ok::<_, OrchardParseError>(()) + }) + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("read ironwood bundle: {e:?}")))?; + Ok((has_orchard, has_ironwood)) +} + +/// Apply FROST-produced spend-auth signatures to a draft PCZT, returning the +/// signed PCZT (hex). Each entry is `(pool, action index, 64-byte sig hex)`; the +/// pool selects which bundle the signature is applied to, so a turnstile +/// transaction that spends from both pools is signed correctly. +pub fn apply_signatures( pczt_hex: &str, sighash_hex: &str, - signatures: Vec<(usize, String)>, + signatures: Vec<(SpendPool, usize, String)>, ) -> Result { use orchard::primitives::redpallas::{Signature, SpendAuth}; - use pczt::roles::low_level_signer::OrchardParseError; + use pczt::roles::low_level_signer::{OrchardParseError, Signer}; let pczt = pczt::Pczt::parse( &hex::decode(pczt_hex.trim()).map_err(|e| CoreError::Ceremony(format!("pczt hex: {e}")))?, @@ -1066,33 +1100,52 @@ pub fn apply_orchard_signatures( .and_then(|b| b.try_into().ok()) .ok_or_else(|| CoreError::Ceremony("sighash must be 32 bytes hex".into()))?; - let sigs: Vec<(usize, Signature)> = signatures - .into_iter() - .map(|(idx, sig_hex)| { - let bytes: [u8; 64] = hex::decode(sig_hex.trim()) - .ok() - .and_then(|b| b.try_into().ok()) - .ok_or_else(|| CoreError::Ceremony("signature must be 64 bytes hex".into()))?; - Ok((idx, Signature::::from(bytes))) - }) - .collect::>()?; + // Decode and split the signatures by pool. + let mut orchard_sigs: Vec<(usize, Signature)> = Vec::new(); + let mut ironwood_sigs: Vec<(usize, Signature)> = Vec::new(); + for (pool, idx, sig_hex) in signatures { + let bytes: [u8; 64] = hex::decode(sig_hex.trim()) + .ok() + .and_then(|b| b.try_into().ok()) + .ok_or_else(|| CoreError::Ceremony("signature must be 64 bytes hex".into()))?; + let sig = Signature::::from(bytes); + match pool { + SpendPool::Orchard => orchard_sigs.push((idx, sig)), + SpendPool::Ironwood => ironwood_sigs.push((idx, sig)), + } + } + // Applying a signature to the wrong action index is a hard error rather than + // a bad-signature rejection at broadcast, so surface it precisely. let mut apply_err: Option = None; - let signer = pczt::roles::low_level_signer::Signer::new(pczt) - .sign_orchard_with(|_pczt, bundle, _| { - for (idx, sig) in sigs { - if let Err(e) = bundle.actions_mut()[idx].apply_signature(sighash, sig) { - apply_err = Some(format!("spend {idx}: {e:?}")); - break; - } + let apply = |bundle: &mut orchard::pczt::Bundle, + sigs: &[(usize, Signature)], + pool: &str, + err: &mut Option| { + for (idx, sig) in sigs { + if let Err(e) = bundle.actions_mut()[*idx].apply_signature(sighash, sig.clone()) { + *err = Some(format!("{pool} spend {idx}: {e:?}")); + break; } + } + }; + + let signer = Signer::new(pczt) + .sign_orchard_with(|_pczt, bundle, _| { + apply(bundle, &orchard_sigs, "orchard", &mut apply_err); Ok::<_, OrchardParseError>(()) }) - .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("apply: {e:?}")))?; + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("apply orchard: {e:?}")))?; + let signer = signer + .sign_ironwood_with(|_pczt, bundle, _| { + apply(bundle, &ironwood_sigs, "ironwood", &mut apply_err); + Ok::<_, OrchardParseError>(()) + }) + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("apply ironwood: {e:?}")))?; if let Some(e) = apply_err { return Err(CoreError::Ceremony(format!("invalid signature for {e}"))); } - // Ironwood cohort: Pczt::serialize now returns Result (postcard EncodingError). + // Pczt::serialize consumes self and returns Result (postcard EncodingError). Ok(hex::encode(signer.finish().serialize().map_err(|e| { CoreError::Ceremony(format!("serialize pczt: {e:?}")) })?)) @@ -1103,7 +1156,7 @@ pub fn apply_orchard_signatures( /// key takes several seconds), so it runs on a blocking thread. /// /// This is the final leg of the send pipeline: the group has already applied -/// its threshold signature to every spend ([`apply_orchard_signatures`]); here +/// its threshold signature to every spend ([`apply_signatures`]); here /// we attach the zero-knowledge proof, finalize, extract the transaction (which /// creates the binding signature), and submit it to lightwalletd. pub async fn broadcast_signed( @@ -1117,6 +1170,12 @@ pub async fn broadcast_signed( ) .map_err(|e| CoreError::Ceremony(format!("parse pczt: {e:?}")))?; + // Prove only the bundles this transaction actually carries: a turnstile send + // has both an Orchard bundle (the spends) and an Ironwood bundle (the + // outputs); a pure Ironwood send has only Ironwood; a legacy unshield only + // Orchard. Proving an empty bundle fails its anchor check, so gate on it. + let (has_orchard, has_ironwood) = bundle_presence(&pczt)?; + // Proving + finalize + extract is synchronous, CPU-bound work; keep it off // the async runtime so progress events and other tasks stay responsive. let (raw, txid) = tokio::task::spawn_blocking(move || -> Result<(Vec, String), CoreError> { @@ -1125,32 +1184,37 @@ pub async fn broadcast_signed( prover::Prover, spend_finalizer::SpendFinalizer, tx_extractor::TransactionExtractor, }; - // Ironwood cohort: ProvingKey/VerifyingKey::build now take an - // OrchardCircuitVersion. Testnet has activated NU6.3, so Orchard-pool - // actions prove/verify against the post-NU6.3 circuit (ProtocolVersion - // V3 → PostNu6_3, the fixed circuit plus the disableCrossAddress - // constraint). A fully network-agnostic build would derive this from the - // PCZT's consensus branch id (as pczt's tx_extractor does via - // `bundle.bundle_version().circuit_version()`); pinned here for the - // testnet spike. - // TODO(ironwood-phase3): turnstile sends also populate an *Ironwood* - // output bundle that needs `Prover::create_ironwood_proof` with an - // ironwood_v3 ProvingKey; wire that once the send path targets Ironwood. + // Both the Orchard and Ironwood pools use the post-NU6.3 Action circuit + // (ProtocolVersion V3 → PostNu6_3), so one proving/verifying key serves + // both bundles — which is exactly why the extractor takes a single + // orchard vk for both. Both testnet and mainnet have activated NU6.3, so + // PostNu6_3 is correct for every live send; a pre-activation (regtest) + // build would need to derive this from the PCZT's branch id. let circuit_version = OrchardCircuitVersion::PostNu6_3; - - // 1. Orchard zero-knowledge proof. let pk = ProvingKey::build(circuit_version); - let pczt = Prover::new(pczt) - .create_orchard_proof(&pk) - .map_err(|e| CoreError::Ceremony(format!("orchard proof: {e:?}")))? - .finish(); + + // 1. Zero-knowledge proof for each present bundle. + let mut prover = Prover::new(pczt); + if has_orchard { + prover = prover + .create_orchard_proof(&pk) + .map_err(|e| CoreError::Ceremony(format!("orchard proof: {e:?}")))?; + } + if has_ironwood { + prover = prover + .create_ironwood_proof(&pk) + .map_err(|e| CoreError::Ceremony(format!("ironwood proof: {e:?}")))?; + } + let pczt = prover.finish(); // 2. Finalize spends (spend-auth signatures are already applied). let pczt = SpendFinalizer::new(pczt) .finalize_spends() .map_err(|e| CoreError::Ceremony(format!("finalize spends: {e:?}")))?; - // 3. Extract the final transaction (creates the binding signature). + // 3. Extract the final transaction (creates the binding signature). The + // extractor verifies both the Orchard and Ironwood bundles with this one + // vk, since they share the PostNu6_3 circuit. let vk = VerifyingKey::build(circuit_version); let tx = TransactionExtractor::new(pczt) .with_orchard(&vk) diff --git a/src-tauri/src/commands/wallet.rs b/src-tauri/src/commands/wallet.rs index 7e1b442..c791afe 100644 --- a/src-tauri/src/commands/wallet.rs +++ b/src-tauri/src/commands/wallet.rs @@ -369,7 +369,7 @@ pub async fn wallet_send( if draft.spends.is_empty() { return Err(AppError::new( "wallet", - "the transaction has no Orchard spends to sign", + "the transaction has no shielded spends to sign", )); } let message = hex::decode(draft.sighash_hex.trim()) @@ -382,9 +382,9 @@ pub async fn wallet_send( .map(|s| { let alpha = hex::decode(s.alpha_hex.trim()) .map_err(|e| AppError::new("wallet", format!("alpha: {e}")))?; - Ok((s.index, alpha)) + Ok((s.pool, s.index, alpha)) }) - .collect::)>>>()?; + .collect::)>>>()?; // 2. Shared coordinator inputs (everything but the per-spend randomizer). let (group, server_url) = @@ -473,7 +473,7 @@ pub async fn wallet_send( // Multi-spend transactions use this same total budget across all spends. const SIGNING_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(35 * 60); - let signing_result: Result, String> = { + let signing_result: Result, String> = { let total = spends.len(); // Sign each note in its own re-randomized FROST session, one note at @@ -487,8 +487,9 @@ pub async fn wallet_send( // Atomic: the first note to fail/reject returns Err before any // broadcast, so a partially-signed transaction is never produced. let signing_fut = async { - let mut signatures: Vec<(usize, String)> = Vec::with_capacity(total); - for (i, (index, alpha)) in spends.into_iter().enumerate() { + let mut signatures: Vec<(wallet::SpendPool, usize, String)> = + Vec::with_capacity(total); + for (i, (pool, index, alpha)) in spends.into_iter().enumerate() { // Tell the UI which note is being signed; each is a separate // approval in signers' inboxes. let _ = task_app.emit( @@ -524,7 +525,9 @@ pub async fn wallet_send( send_context, }; match run_coordinator(suite, params, tx.clone(), cancel.clone()).await { - Ok(output) => signatures.push((index, hex::encode(&output.signature))), + Ok(output) => { + signatures.push((pool, index, hex::encode(&output.signature))) + } Err(e) => return Err(e.to_string()), // abort remaining notes } } @@ -558,7 +561,7 @@ pub async fn wallet_send( }; let signed_pczt_hex = - match wallet::apply_orchard_signatures(&pczt_hex, &sighash_hex, signatures) { + match wallet::apply_signatures(&pczt_hex, &sighash_hex, signatures) { Ok(hex) => hex, Err(e) => return fail(e.to_string()), }; diff --git a/src/ipc/commands.ts b/src/ipc/commands.ts index 2972ff4..824c605 100644 --- a/src/ipc/commands.ts +++ b/src/ipc/commands.ts @@ -195,6 +195,9 @@ export const walletNewReceiveAddress = (groupId: string) => invoke("wallet_new_receive_address", { groupId }); export interface SpendToSign { + /** Which pool's bundle holds this spend. Post-NU6.3 one transaction can carry + * both (a turnstile send spends Orchard notes but delivers via Ironwood). */ + pool: "orchard" | "ironwood"; index: number; alpha_hex: string; } From 5bc0f79115b6a3c8cdc864f06ee78bdc1fa84bd4 Mon Sep 17 00:00:00 2001 From: blocknodes Date: Fri, 31 Jul 2026 21:44:05 +0000 Subject: [PATCH 3/8] perf(wallet): start new wallets at chain tip; make sync batch size configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The core auto-substituted a 3,800,000 birthday for every new testnet wallet, forcing ~350k blocks of pre-creation trial-decryption before reaching the tip — the dominant cause of slow first syncs. A brand-new group holds no funds mined before it existed, so it now starts at the chain tip and syncs in seconds. - default_birthday_height returns None (tip) on both networks; new wallets no longer scan empty history. Wiped-wallet recovery is unaffected: it uses the birthday persisted in settings (wallet_birthdays), supplied by the command layer. DEFAULT_TESTNET_BIRTHDAY (3.8M) is retained and made pub as an explicit opt-in deep-rescan floor for the rare double-loss case. - sync_group takes a batch_size (None -> DEFAULT_SYNC_BATCH_SIZE = 5000, clamped to [500, 25000]); bigger batches amortize per-batch gRPC round-trip and DB transaction overhead. Exposed as a per-install setting (sync_batch_size). Spend-before-sync early-balance surfacing already works (upstream scans priority-ordered ranges, UI polls balance every 5s) and needs no change. Co-Authored-By: Claude Opus 4.8 --- src-tauri/core/src/wallet.rs | 92 +++++++++++++++++++++++--------- src-tauri/src/commands/wallet.rs | 3 +- src-tauri/src/state.rs | 5 ++ 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src-tauri/core/src/wallet.rs b/src-tauri/core/src/wallet.rs index 9708617..05e1ad1 100644 --- a/src-tauri/core/src/wallet.rs +++ b/src-tauri/core/src/wallet.rs @@ -688,25 +688,30 @@ fn pool_balance(b: &zcash_client_backend::data_api::Balance) -> PoolBalance { } } -/// First block a new testnet group's wallet scans when no birthday is recorded -/// or supplied. Sits comfortably before the NU6.3/Ironwood activation -/// (4,134,000), so a group funded any time during Ironwood testing is found by -/// a rebuilt wallet without the user having to supply a height. -const DEFAULT_TESTNET_BIRTHDAY: u64 = 3_800_000; +/// A deep-rescan floor for testnet: sits comfortably before the NU6.3/Ironwood +/// activation (4,134,000), so scanning from here finds a group funded any time +/// during Ironwood testing. +/// +/// This is NOT applied automatically. A brand-new group has no prior funds, so +/// it starts at the chain tip and syncs in seconds; scanning ~350k blocks of +/// pre-creation history was the single largest source of slow first syncs. +/// Recovery of a wiped wallet uses the birthday persisted in settings instead +/// (see the command layer). This constant is only for an *explicit* deep rescan +/// — a user who lost both the wallet db and the recorded birthday and wants to +/// re-discover funds — supplied through `birthday_height`, never as a default. +pub const DEFAULT_TESTNET_BIRTHDAY: u64 = 3_800_000; /// The birthday a brand-new wallet starts from when the caller gives no height -/// and none was recorded for the group. +/// and none was recorded for the group: the chain tip, on both networks. /// -/// Mainnet deliberately has no constant: its chain tip is around 3.4M (NU6.2 -/// activated at 3,364,600), so any fixed height chosen for testnet would sit in -/// mainnet's *future* — the treestate would not exist and the wallet would scan -/// nothing. Mainnet therefore starts at the chain tip, which is correct for a -/// newly created group that cannot hold prior funds. -pub fn default_birthday_height(network: WalletNetwork) -> Option { - match network { - WalletNetwork::Test => Some(DEFAULT_TESTNET_BIRTHDAY), - WalletNetwork::Main => None, - } +/// A newly created group cannot hold funds mined before it existed, so there is +/// nothing to find below the tip — scanning earlier is pure cost. Returning +/// `None` lets [`resolve_scan_from`] resolve the start to the current tip. To +/// recover funds that predate a rebuilt wallet, pass an explicit +/// `birthday_height` (the command layer supplies the persisted one); for a +/// from-scratch testnet rescan, pass [`DEFAULT_TESTNET_BIRTHDAY`]. +pub fn default_birthday_height(_network: WalletNetwork) -> Option { + None } /// Pick the first block to scan: the requested birthday held inside @@ -727,9 +732,11 @@ fn resolve_scan_from(requested: Option, nu5: u64, tip: u64) -> u64 { /// scanning starts from. Idempotent: returns 0 if the account already exists. /// Touches the network (fetches the tip and a treestate). /// -/// `birthday_height` is the first block to scan. Pass `Some(h)` to recover a -/// group whose funds arrived at or after `h` — for example after rebuilding a -/// wiped wallet database. Pass `None` to use [`default_birthday_height`]. +/// `birthday_height` is the first block to scan. Pass `None` for a brand-new +/// group: it holds no prior funds, so it starts at the chain tip and syncs in +/// seconds. Pass `Some(h)` to recover a group whose funds arrived at or after +/// `h` — after rebuilding a wiped wallet database (the command layer supplies +/// the persisted birthday), or [`DEFAULT_TESTNET_BIRTHDAY`] for a full rescan. /// /// Blocks before the birthday are never scanned, so a birthday set too late /// makes existing funds invisible. The height is clamped into @@ -771,6 +778,8 @@ pub async fn init_group_account( let nu5 = params .activation_height(NetworkUpgrade::Nu5) .map_or(0, |a| u64::from(u32::from(a))); + // No requested birthday means a brand-new group: start at the tip. Recovery + // passes an explicit height (persisted birthday or a deep-rescan floor). let scan_from = resolve_scan_from( birthday_height.or_else(|| default_birthday_height(network)), nu5, @@ -904,16 +913,38 @@ impl BlockCache for FsCache { } } +/// How many blocks each sync batch downloads and scans at once when the caller +/// gives no override. Larger batches amortize the per-batch gRPC round-trip and +/// database-transaction overhead across more blocks, which is the dominant cost +/// once trial decryption finds nothing (the common case for a wallet catching up +/// over empty history). Compact blocks are small, so a few thousand per batch is +/// comfortable in memory. Tunable per-install via settings; see [`sync_group`]. +pub const DEFAULT_SYNC_BATCH_SIZE: u32 = 5_000; + +/// Clamp bounds for a caller-supplied batch size. Below the floor the round-trip +/// overhead dominates; above the ceiling a batch's worth of compact blocks can +/// spike memory (they are all held in a `Vec` while the batch is scanned). +pub const MIN_SYNC_BATCH_SIZE: u32 = 500; +pub const MAX_SYNC_BATCH_SIZE: u32 = 25_000; + /// Sync the group's wallet: download and trial-decrypt compact blocks from /// lightwalletd into the local db. Long-running; touches the network. +/// +/// `batch_size` is how many blocks to download and scan per batch; `None` uses +/// [`DEFAULT_SYNC_BATCH_SIZE`]. Any value is clamped into +/// `[MIN_SYNC_BATCH_SIZE, MAX_SYNC_BATCH_SIZE]`. pub async fn sync_group( data_dir: &Path, group_id: &str, network: WalletNetwork, lightwalletd_url: &str, db_key: &[u8], + batch_size: Option, cancel: &tokio_util::sync::CancellationToken, ) -> Result<(), CoreError> { + let batch_size = batch_size + .unwrap_or(DEFAULT_SYNC_BATCH_SIZE) + .clamp(MIN_SYNC_BATCH_SIZE, MAX_SYNC_BATCH_SIZE); let (db_path, blocks_dir) = wallet_paths(data_dir, group_id, network); std::fs::create_dir_all(&blocks_dir)?; let mut db = open_db(&db_path, network, db_key)?; @@ -940,7 +971,7 @@ pub async fn sync_group( biased; _ = cancel.cancelled() => Err(CoreError::Cancelled), res = zcash_client_backend::sync::run( - &mut client, ¶ms, &cache, &mut db, 1000, + &mut client, ¶ms, &cache, &mut db, batch_size, ) => res.map_err(|e| CoreError::Connection(format!("sync: {e}"))), } } @@ -1813,12 +1844,23 @@ mod tests { } #[test] - fn default_birthday_is_testnet_only() { + fn new_wallets_start_at_the_tip_on_both_networks() { + // A brand-new group holds no pre-creation funds, so with no requested or + // recorded birthday it starts at the chain tip (None -> tip) rather than + // scanning hundreds of thousands of blocks of empty history. The testnet + // deep-rescan floor is opt-in via `birthday_height`, never a default. + assert_eq!(default_birthday_height(WalletNetwork::Test), None); + assert_eq!(default_birthday_height(WalletNetwork::Main), None); + assert_eq!(resolve_scan_from(None, TEST_NU5, 4_200_000), 4_200_000); + } + + #[test] + fn explicit_deep_rescan_floor_is_honoured_when_requested() { + // Passing DEFAULT_TESTNET_BIRTHDAY explicitly (an opt-in deep rescan) + // still scans from that floor when it sits inside [NU5, tip]. assert_eq!( - default_birthday_height(WalletNetwork::Test), - Some(DEFAULT_TESTNET_BIRTHDAY) + resolve_scan_from(Some(DEFAULT_TESTNET_BIRTHDAY), TEST_NU5, 4_200_000), + DEFAULT_TESTNET_BIRTHDAY ); - // A fixed height would be in mainnet's future; it starts at the tip. - assert_eq!(default_birthday_height(WalletNetwork::Main), None); } } diff --git a/src-tauri/src/commands/wallet.rs b/src-tauri/src/commands/wallet.rs index 2cf3359..f01d119 100644 --- a/src-tauri/src/commands/wallet.rs +++ b/src-tauri/src/commands/wallet.rs @@ -225,8 +225,9 @@ pub async fn wallet_sync(state: State<'_, AppState>, group_id: String) -> AppRes } } + let batch_size = state.load_settings().sync_batch_size; let result = wallet::sync_group( - &state.data_dir, &group_id, network, &url, db_key.as_ref(), &cancel, + &state.data_dir, &group_id, network, &url, db_key.as_ref(), batch_size, &cancel, ) .await; diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index 74e73f9..d4e4d6e 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -65,6 +65,11 @@ pub struct Settings { /// scans the blocks that funded the group, so the balance reads zero. #[serde(default)] pub wallet_birthdays: HashMap, + /// Blocks downloaded and scanned per sync batch. `None` uses the core + /// default; larger values reduce per-batch overhead on slow links at the + /// cost of memory. Clamped by the core to a sane range. + #[serde(default)] + pub sync_batch_size: Option, /// Active session profile: "coordinator" or "participant". Toggled by the /// sidebar profile switch; drives which saved configuration is in use. #[serde(default)] From e2e79ce5d10b1510f1684370f424eac8e8911095 Mon Sep 17 00:00:00 2001 From: blocknodes Date: Sat, 1 Aug 2026 16:46:11 +0000 Subject: [PATCH 4/8] update signing for ironwood --- TODO.md | 11 +++++ src-tauri/core/src/wallet.rs | 88 +++++++++++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/TODO.md b/TODO.md index 9606aaf..4a5d6e5 100644 --- a/TODO.md +++ b/TODO.md @@ -29,6 +29,17 @@ current build depends on them. - [ ] **Tailscale `serve` as a fourth hosting option** — alongside Direct URL, Cloudflare Tunnel, and NGINX in Session Configuration. + **Feasibility/impact (2026-08-01):** effort Med, impact Med–High, not gated + by the testnet-send validation. Slots in as a fourth `coordinator_exposure` + variant reusing the existing exposure plumbing + a status probe; no crypto + change (frostd's Noise layer still authenticates end-to-end). Structural + difference from cloudflared: **detect-and-drive a system `tailscale` CLI, + do NOT bundle** — it needs the `tailscaled` daemon (privileged) and a + logged-in tailnet, so the sidecar-spawn pattern doesn't apply. Read the + stable MagicDNS hostname back via `tailscale status --json` as the saved + server URL. Verdict: **do** — best fix for the disposable-quick-tunnel URL + pain (stable, savable, auto-TLS, tailnet-scoped). + Why it is attractive: `tailscale serve https / http://127.0.0.1:` exposes the loopback frostd over the tailnet with a **stable** MagicDNS hostname and an automatically-provisioned, publicly-valid TLS certificate. diff --git a/src-tauri/core/src/wallet.rs b/src-tauri/core/src/wallet.rs index 05e1ad1..0eb5b17 100644 --- a/src-tauri/core/src/wallet.rs +++ b/src-tauri/core/src/wallet.rs @@ -106,21 +106,22 @@ pub fn branch_id_for_height(network: WalletNetwork, height: u64) -> String { /// The NU6.3 / Ironwood consensus branch id (little-endian u32, printed as /// 8-digit hex). Orchard actions mined under this upgrade prove against the /// `PostNu6_3` circuit (the fixed circuit plus the `disableCrossAddress` -/// constraint). Testnet activated it at 4,134,000; mainnet has not (yet). +/// constraint). Activated on testnet at 4,134,000 and on mainnet at 3,428,143 +/// (see `zcash_protocol` activation tables), so both live networks are past it. const NU6_3_BRANCH_ID: &str = "37a5165b"; /// The Orchard proving/verifying circuit version to use for a transaction mined /// at `height` on `network`. This MUST match the consensus branch active at that /// height, or the proof is rejected by the network: /// -/// - Post-NU6.3 (Ironwood, currently testnet only) → `PostNu6_3`. -/// - Post-NU6.2 (mainnet's current activation) → `FixedPostNu6_2`. +/// - Post-NU6.3 (Ironwood; both testnet and mainnet are past it) → `PostNu6_3`. +/// - Post-NU6.2 but pre-NU6.3 → `FixedPostNu6_2`. /// /// Deriving it from the live branch id — rather than hardcoding one network's /// value — is what lets the same build produce valid transactions on both -/// networks, and automatically switches mainnet over once it activates NU6.3. -/// Both live networks are past NU6.2, so `FixedPostNu6_2` is the correct floor; -/// the historical `InsecurePreNu6_2` circuit is never used for new sends. +/// networks, each picking the circuit for the upgrade active at that height. +/// `FixedPostNu6_2` is the pre-Ironwood floor; the historical `InsecurePreNu6_2` +/// circuit is never used for new sends. #[cfg(feature = "wallet")] fn orchard_circuit_version_for_height( network: WalletNetwork, @@ -1232,6 +1233,61 @@ fn bundle_presence(pczt: &pczt::Pczt) -> Result<(bool, bool), CoreError> { Ok((has_orchard, has_ironwood)) } +/// Find every shielded spend that still lacks a spend-authorization signature, +/// across both Orchard-protocol bundles, described precisely. +/// +/// The `TransactionExtractor` requires a `spend_auth_sig` on *every* action and +/// otherwise fails late and opaquely with `MissingSpendAuthSig`. By the time we +/// reach it, dummy padding spends have been signed by the IO Finalizer (it +/// consumes their `dummy_sk`) and real spends have been FROST-signed and applied +/// ([`apply_signatures`]). Anything still unsigned is a bug in *this* signing +/// path — most likely a real spend that [`spends_to_sign`] failed to enumerate, +/// or a dummy the IO Finalizer skipped — and we want to surface it here, before +/// the expensive proving/broadcast, with enough detail to fix it. The returned +/// strings distinguish the two cases (a real spend still carrying `value`/`alpha` +/// vs. a dummy whose `dummy_sk` was never consumed). +fn find_unsigned_spends(pczt: &pczt::Pczt) -> Result, CoreError> { + use orchard::value::NoteValue; + use pczt::roles::low_level_signer::{OrchardParseError, Signer}; + + fn scan(bundle: &orchard::pczt::Bundle, pool: &str, out: &mut Vec) { + for (index, action) in bundle.actions().iter().enumerate() { + let spend = action.spend(); + if spend.spend_auth_sig().is_some() { + continue; // already authorized + } + let is_real = spend.value().is_some_and(|v| v != NoteValue::default()); + let has_alpha = spend.alpha().is_some(); + let has_dummy_sk = spend.dummy_sk().is_some(); + let kind = if is_real { + "REAL spend never FROST-signed (spends_to_sign missed it?)" + } else if has_dummy_sk { + "dummy with unconsumed dummy_sk (IO Finalizer skipped it?)" + } else { + "zero-value spend left unsigned" + }; + out.push(format!( + "{pool} bundle action {index}: {kind} [alpha_present={has_alpha}]" + )); + } + } + + let mut unsigned = Vec::new(); + let signer = Signer::new(pczt.clone()) + .sign_orchard_with(|_pczt, bundle, _| { + scan(bundle, "orchard", &mut unsigned); + Ok::<_, OrchardParseError>(()) + }) + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("read orchard bundle: {e:?}")))?; + signer + .sign_ironwood_with(|_pczt, bundle, _| { + scan(bundle, "ironwood", &mut unsigned); + Ok::<_, OrchardParseError>(()) + }) + .map_err(|e: OrchardParseError| CoreError::Ceremony(format!("read ironwood bundle: {e:?}")))?; + Ok(unsigned) +} + /// Apply FROST-produced spend-auth signatures to a draft PCZT, returning the /// signed PCZT (hex). Each entry is `(pool, action index, 64-byte sig hex)`; the /// pool selects which bundle the signature is applied to, so a turnstile @@ -1298,8 +1354,26 @@ pub fn apply_signatures( if let Some(e) = apply_err { return Err(CoreError::Ceremony(format!("invalid signature for {e}"))); } + let signed = signer.finish(); + + // Completeness guard: every shielded spend must now be authorized, or the + // TransactionExtractor fails late and opaquely with `MissingSpendAuthSig` + // (and only after the expensive proving step). Catch it here instead, naming + // the exact unsigned action(s), so a signing-path gap surfaces early and + // actionably rather than as a doomed broadcast. No transaction is built. + let unsigned = find_unsigned_spends(&signed)?; + if !unsigned.is_empty() { + return Err(CoreError::Ceremony(format!( + "not all spends were authorized, so this transaction would be rejected at \ + broadcast (MissingSpendAuthSig). Unsigned: {}. No transaction was built or \ + sent. This is a bug in the pool-aware signing path — please report it with \ + this message.", + unsigned.join("; ") + ))); + } + // Pczt::serialize consumes self and returns Result (postcard EncodingError). - Ok(hex::encode(signer.finish().serialize().map_err(|e| { + Ok(hex::encode(signed.serialize().map_err(|e| { CoreError::Ceremony(format!("serialize pczt: {e:?}")) })?)) } From f1121012f6eefeb31f9cadca0197b1cda9574c39 Mon Sep 17 00:00:00 2001 From: blocknodes Date: Sat, 1 Aug 2026 19:12:41 +0000 Subject: [PATCH 5/8] fix(wallet): FROST-sign zero-value split-note spends (MissingSpendAuthSig) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A post-Ironwood turnstile-out pads the Orchard bundle with a split note — a zero-value note derived from the group's own spending key (orchard uses these instead of random dummies so the real spend count doesn't leak). A split note carries no dummy_sk, so the IO Finalizer never signs it, and it has zero value, so spends_to_sign's `value != 0` filter treated it as a dummy and skipped it. It therefore needed the group's spend-auth signature but received none, and the TransactionExtractor rejected the transaction with Orchard(Extract( MissingSpendAuthSig)) — reproduced on a live send. Enumerate a spend for FROST signing by whether it still lacks a spend_auth_sig after create_pczt_from_proposal's IO Finalizer has run (which already signs every dummy from its dummy_sk), rather than by value. That selects exactly the wallet's own notes — real and zero-value split notes alike — and excludes the already- signed dummies. Sends with a split note now authorize both actions (one FROST ceremony each). The completeness guard added in the prior commit backstops this. Co-Authored-By: Claude Opus 4.8 --- src-tauri/core/src/wallet.rs | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src-tauri/core/src/wallet.rs b/src-tauri/core/src/wallet.rs index 0eb5b17..7b6a584 100644 --- a/src-tauri/core/src/wallet.rs +++ b/src-tauri/core/src/wallet.rs @@ -1169,27 +1169,38 @@ pub async fn prepare_send( }) } -/// Collect every real spend the group must sign, across both the Orchard and +/// Collect every spend the group must FROST-sign, across both the Orchard and /// Ironwood bundles, tagged with its pool and α. Requires orchard's -/// `unstable-frost` feature (which exposes `spend().alpha()`). Dummy padding -/// actions (zero value) are skipped. Orchard spends are listed first, then -/// Ironwood; the order only needs to be stable, since each spend carries its own -/// pool + index for application. +/// `unstable-frost` feature (which exposes `spend().alpha()`). Orchard spends are +/// listed first, then Ironwood; the order only needs to be stable, since each +/// spend carries its own pool + index for application. +/// +/// A spend needs the group's signature iff it still lacks a `spend_auth_sig`: +/// this runs after `create_pczt_from_proposal`, whose IO Finalizer has already +/// signed every dummy padding spend from its `dummy_sk`, so the only spends left +/// unsigned are the wallet's own notes. Each carries an α to sign with. The old +/// heuristic keyed on `value != 0`, which wrongly skipped the **zero-value real +/// spend** the turnstile-out construction adds to the Orchard bundle — leaving it +/// unauthorized and failing extraction with `MissingSpendAuthSig`. fn spends_to_sign(pczt: pczt::Pczt) -> Result, CoreError> { use ff::PrimeField; - use orchard::value::NoteValue; use pczt::roles::low_level_signer::{OrchardParseError, Signer}; - // Append the real spends of one already-parsed bundle, tagging their pool. + // Append every not-yet-signed spend of one already-parsed bundle, tagging + // its pool. `spend_auth_sig().is_none()` selects exactly the spends the group + // must authorize (dummies were already signed by the IO Finalizer); `alpha` + // is the re-randomization those signatures must use. fn collect(bundle: &orchard::pczt::Bundle, pool: SpendPool, out: &mut Vec) { for (index, action) in bundle.actions().iter().enumerate() { - let is_real = action.spend().value().is_some_and(|v| v != NoteValue::default()); - if let (true, Some(alpha)) = (is_real, action.spend().alpha()) { - out.push(SpendToSign { - pool, - index, - alpha_hex: hex::encode(alpha.to_repr()), - }); + let spend = action.spend(); + if spend.spend_auth_sig().is_none() { + if let Some(alpha) = spend.alpha() { + out.push(SpendToSign { + pool, + index, + alpha_hex: hex::encode(alpha.to_repr()), + }); + } } } } From 0231c6031d62806d4eccbc340d8bef808e4ca936 Mon Sep 17 00:00:00 2001 From: blocknodes Date: Sat, 1 Aug 2026 20:36:44 +0000 Subject: [PATCH 6/8] =?UTF-8?q?feat(wallet):=20show=20Ironwood=20balance?= =?UTF-8?q?=20and=20add=20Orchard=E2=86=92Ironwood=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-NU6.3 a group's funds split between the sealed Orchard pool and the new Ironwood pool, but the wallet only ever read/showed the Orchard pool — so funds moved across the turnstile were invisible in the balance summary AND treated as unspendable by the send form (it gated on orchard.spendable_zatoshis). The account total already includes Ironwood; only the app's surfacing lagged. Balance: - WalletStatus/group_status gain an `ironwood: PoolBalance` (from AccountBalance::ironwood_balance); the stale "total == Orchard pool" comment is corrected (total/spendable already sum every pool). - The balance summary now shows total/spendable across all pools as the headline, with an "Orchard (sealed) · Ironwood" per-pool breakdown line. - The send form gates on the account-wide spendable/pending, so migrated Ironwood funds are spendable and visible. Migration: - A "Migrate Orchard → Ironwood" action self-sends the spendable Orchard balance to the group's own address; because every post-NU6.3 shielded output lands in Ironwood, this sweeps the sealed pool across the turnstile. It reuses the self-send review + ceremony path, with distinct migration labelling. - A prompt appears whenever a group still holds a spendable Orchard balance, since that pool can never receive again. cargo test (32 core) + tsc + vite build + full backend build all green. Co-Authored-By: Claude Opus 4.8 --- src-tauri/core/src/wallet.rs | 26 +++++-- src/ipc/commands.ts | 9 ++- src/screens/Groups.tsx | 129 +++++++++++++++++++++++++++++------ 3 files changed, 135 insertions(+), 29 deletions(-) diff --git a/src-tauri/core/src/wallet.rs b/src-tauri/core/src/wallet.rs index 7b6a584..5254cad 100644 --- a/src-tauri/core/src/wallet.rs +++ b/src-tauri/core/src/wallet.rs @@ -562,13 +562,18 @@ pub struct WalletStatus { pub initialized: bool, /// Receiving unified address (from the UFVK), for the configured network. pub address: Option, - /// Aggregate totals (kept for back-compat; equal to the Orchard pool since - /// the group's UFVK is Orchard-only). + /// Aggregate totals across *all* pools the account holds. Post-Ironwood a + /// group's funds are split between the sealed `orchard` pool and the new + /// `ironwood` pool (a turnstile send moves value from the former to the + /// latter), so this is the sum of both — not the Orchard pool alone. pub total_zatoshis: u64, pub spendable_zatoshis: u64, - /// Per-pool breakdown. With an Orchard-only group UFVK, `sapling` and - /// `transparent` are zero — the group cannot hold/spend those pools. + /// Per-pool breakdown. `orchard` is the sealed legacy pool (can be spent but + /// never received into again); `ironwood` is the pool all new shielded value + /// lands in post-NU6.3. `sapling` and `transparent` are zero for an + /// Orchard/Ironwood group UFVK. pub orchard: PoolBalance, + pub ironwood: PoolBalance, pub sapling: PoolBalance, pub transparent: PoolBalance, /// Highest fully-scanned block, and the chain tip the wallet knows about. @@ -593,6 +598,7 @@ pub fn group_status( total_zatoshis: 0, spendable_zatoshis: 0, orchard: PoolBalance::default(), + ironwood: PoolBalance::default(), sapling: PoolBalance::default(), transparent: PoolBalance::default(), synced_height: 0, @@ -613,6 +619,7 @@ pub fn group_status( total_zatoshis: 0, spendable_zatoshis: 0, orchard: PoolBalance::default(), + ironwood: PoolBalance::default(), sapling: PoolBalance::default(), transparent: PoolBalance::default(), synced_height: 0, @@ -622,14 +629,16 @@ pub fn group_status( let summary = db .get_wallet_summary(ConfirmationsPolicy::default()) .map_err(|e| CoreError::Crypto(format!("wallet summary: {e}")))?; - let (total, spendable, orchard, sapling, transparent, synced, tip) = match summary { + let (total, spendable, orchard, ironwood, sapling, transparent, synced, tip) = match summary { Some(s) => { let bal = s.account_balances().values().next(); let total = bal.map(|b| u64::from(b.total())).unwrap_or(0); let spendable = bal.map(|b| u64::from(b.spendable_value())).unwrap_or(0); - // Per-pool breakdown. Orchard is the only pool the group can hold; - // sapling/transparent read 0 with an Orchard-only UFVK. + // Per-pool breakdown. Orchard (sealed) and Ironwood (post-NU6.3) are + // the pools the group holds; sapling/transparent read 0 with an + // Orchard/Ironwood-only UFVK. let orchard = bal.map(|b| pool_balance(b.orchard_balance())).unwrap_or_default(); + let ironwood = bal.map(|b| pool_balance(b.ironwood_balance())).unwrap_or_default(); let sapling = bal.map(|b| pool_balance(b.sapling_balance())).unwrap_or_default(); let transparent = bal .map(|b| { @@ -647,6 +656,7 @@ pub fn group_status( total, spendable, orchard, + ironwood, sapling, transparent, u64::from(s.fully_scanned_height()), @@ -659,6 +669,7 @@ pub fn group_status( PoolBalance::default(), PoolBalance::default(), PoolBalance::default(), + PoolBalance::default(), 0, 0, ), @@ -669,6 +680,7 @@ pub fn group_status( total_zatoshis: total, spendable_zatoshis: spendable, orchard, + ironwood, sapling, transparent, synced_height: synced, diff --git a/src/ipc/commands.ts b/src/ipc/commands.ts index 09804ca..aa3fe61 100644 --- a/src/ipc/commands.ts +++ b/src/ipc/commands.ts @@ -128,12 +128,15 @@ export interface PoolBalance { export interface WalletStatus { initialized: boolean; address: string | null; - /** Aggregate totals (kept for back-compat; equal to the Orchard pool). */ + /** Aggregate totals across *all* pools — the sum of the sealed `orchard` pool + * and the new `ironwood` pool, not the Orchard pool alone. */ total_zatoshis: number; spendable_zatoshis: number; - /** Per-pool breakdown. With an Orchard-only group UFVK, sapling & transparent - * are 0 — the threshold group cannot hold or spend those pools. */ + /** Per-pool breakdown. `orchard` is the sealed legacy pool (spendable but can + * never receive again); `ironwood` is where new shielded value lands + * post-NU6.3. sapling & transparent are 0 for an Orchard/Ironwood group. */ orchard: PoolBalance; + ironwood: PoolBalance; sapling: PoolBalance; transparent: PoolBalance; synced_height: number; diff --git a/src/screens/Groups.tsx b/src/screens/Groups.tsx index d3bf5dd..ddfa66f 100644 --- a/src/screens/Groups.tsx +++ b/src/screens/Groups.tsx @@ -531,6 +531,9 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo const [memo, setMemo] = useState(""); const [draft, setDraft] = useState(null); const [isConsolidation, setIsConsolidation] = useState(false); + // A migration (Orchard → Ironwood) is a self-send like a consolidation, so it + // reuses the isConsolidation plumbing, but is labelled distinctly for review. + const [isMigration, setIsMigration] = useState(false); const [showConfirm, setShowConfirm] = useState(false); // Shielded send (Orchard → Orchard) vs. unshield (Orchard → transparent). // Both reuse the same prepare/sign machinery; the mode only drives the @@ -548,8 +551,14 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo // funds are the norm right after receiving (ZIP-317 wants 10 confirmations on // received notes, 3 on our own change), so offering a Prepare button that can // only fail with "insufficient funds" is a trap. - const spendableBalance = status.data?.orchard.spendable_zatoshis ?? 0; - const pendingBalance = status.data?.orchard.pending_zatoshis ?? 0; + // Spend across every pool the group holds. Post-NU6.3 its funds are split + // between the sealed Orchard pool and the new Ironwood pool; the backend + // selects inputs from either, so gating on Orchard alone would wrongly hide + // migrated Ironwood funds as unspendable. + const spendableBalance = status.data?.spendable_zatoshis ?? 0; + const pendingBalance = + (status.data?.orchard.pending_zatoshis ?? 0) + + (status.data?.ironwood.pending_zatoshis ?? 0); const noSpendableBalance = spendableBalance <= 0; const exceedsBalance = Number(amountZec) > 0 && Math.round(Number(amountZec) * 1e8) > spendableBalance; @@ -565,6 +574,7 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo onSuccess: (d) => { setErr(null); setIsConsolidation(false); + setIsMigration(false); setDraft(d); }, onError: (e) => setErr((e as unknown as AppError).message), @@ -590,6 +600,37 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo setAmountZec(String(d.amount_zatoshis / 1e8)); setDraft(d); setIsConsolidation(true); + setIsMigration(false); + }, + onError: (e) => setErr((e as unknown as AppError).message), + }); + + // Migrate the sealed Orchard pool into Ironwood: a self-send sized to the + // Orchard spendable balance. Post-NU6.3 the Orchard pool can never receive + // again (Ironwood sealed it), so any Orchard funds should be swept across the + // turnstile into Ironwood — a self-send spends the Orchard notes and, because + // every post-NU6.3 shielded output lands in Ironwood, delivers them there. It + // reuses the self-send review UI (isConsolidation), so the user still reviews + // and runs the normal signing ceremony. + const migrate = useMutation({ + mutationFn: () => { + const addr = status.data?.address; + const orchard = status.data?.orchard.spendable_zatoshis ?? 0; + if (!addr) throw new Error("wallet address not available — try syncing first"); + if (orchard <= CONSOLIDATE_FEE_BUFFER) + throw new Error( + `Orchard balance too low to migrate (need > 0.001 ${unit(isMainnet)} above fees)` + ); + return walletPrepareSend(group.id, addr, orchard - CONSOLIDATE_FEE_BUFFER); + }, + onSuccess: (d) => { + setErr(null); + setRecipient(status.data?.address ?? ""); + setAmountZec(String(d.amount_zatoshis / 1e8)); + setDraft(d); + setIsConsolidation(true); + setIsMigration(true); + setWalletTab("send"); }, onError: (e) => setErr((e as unknown as AppError).message), }); @@ -748,7 +789,7 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo return (
-

Wallet (Zcash Orchard)

+

Wallet (Zcash · Orchard + Ironwood)

{!s || (!s.initialized && (init.isPending || !err)) ? (

Setting up the group's view-only wallet…

) : !s.initialized ? ( @@ -763,24 +804,61 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo ) : ( <> - {/* Balance summary — always visible at top */} + {/* Balance summary — always visible at top. Totals span every pool the + group holds; the per-pool line below shows the Orchard/Ironwood + split, since post-NU6.3 funds live in both. */}
- +
- {zec(s.orchard.spendable_zatoshis)} {unit(isMainnet)} + {zec(s.spendable_zatoshis)} {unit(isMainnet)}
-
{zec(s.orchard.pending_zatoshis)} {unit(isMainnet)}
+
+ {zec(s.orchard.pending_zatoshis + s.ironwood.pending_zatoshis)} {unit(isMainnet)} +
-
{zec(s.orchard.total_zatoshis)} {unit(isMainnet)}
+
{zec(s.total_zatoshis)} {unit(isMainnet)}
+ {/* Per-pool breakdown: Orchard is the sealed legacy pool, Ironwood is + where all new value lands post-NU6.3. */} +
+ Orchard (sealed): {zec(s.orchard.total_zatoshis)} {unit(isMainnet)} + {" · "} + Ironwood: {zec(s.ironwood.total_zatoshis)} {unit(isMainnet)} +
+ {/* Prompt to sweep the sealed Orchard pool into Ironwood. Shown only + while a meaningful, spendable Orchard balance remains (above the + fee buffer) and no send is already in flight. */} + {s.orchard.spendable_zatoshis > CONSOLIDATE_FEE_BUFFER && + !(activeSend && !activeSend.done) && ( +
+ Migrate Orchard → Ironwood. This group holds{" "} + {zec(s.orchard.spendable_zatoshis)} {unit(isMainnet)} in the legacy + Orchard pool, which can no longer receive funds after the Ironwood + (NU6.3) upgrade. Sweep it into Ironwood so all funds stay in the + active pool. +
+ +
+
+ )}
Block {syncedHeight.toLocaleString()} @@ -1068,20 +1146,33 @@ function GroupWallet({ group, isMainnet }: { group: GroupSummary; isMainnet: boo style={{ marginTop: 12, background: "var(--bg-elevated)" }} >

- {isConsolidation - ? "Consolidation transaction" - : draft.is_unshield - ? "Unshield transaction" - : "Prepared transaction"} + {isMigration + ? "Migrate Orchard → Ironwood" + : isConsolidation + ? "Consolidation transaction" + : draft.is_unshield + ? "Unshield transaction" + : "Prepared transaction"}

{isConsolidation && (
- - Self-transfer — sends funds back to this group's own address, merging{" "} - {draft.spends.length} note{draft.spends.length !== 1 ? "s" : ""} into - one. After signing, future sends will need only a single signing round. - A small network fee applies. - + {isMigration ? ( + + Sweeps the group's sealed Orchard balance back to + its own address; because every post-NU6.3 shielded output lands in + the Ironwood pool, this moves the funds across the + turnstile into Ironwood.{" "} + {draft.spends.length} note{draft.spends.length !== 1 ? "s" : ""}{" "} + will be signed (one round each). A small network fee applies. + + ) : ( + + Self-transfer — sends funds back to this group's own address, merging{" "} + {draft.spends.length} note{draft.spends.length !== 1 ? "s" : ""} into + one. After signing, future sends will need only a single signing round. + A small network fee applies. + + )}
)} {!isConsolidation && draft.is_unshield && ( From dff9f1754cf9e43ce102c3663a204bc9c3545a38 Mon Sep 17 00:00:00 2001 From: blocknodes Date: Sat, 1 Aug 2026 23:11:44 +0000 Subject: [PATCH 7/8] docs(todo): queue ZcashNames (ZNS) integration; add Tailscale feasibility - ZNS: human-readable names for groups/wallets (name.zcash -> shielded receive address). Resolve-first (low effort, high value; show resolved address before send), register/claim second (threshold on-chain action via FROST send+memo). - Tailscale serve: carry the feasibility/impact verdict alongside the item. Co-Authored-By: Claude Opus 4.8 --- TODO.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 4a5d6e5..c2d3e95 100644 --- a/TODO.md +++ b/TODO.md @@ -2,9 +2,38 @@ ## Planned for a future iteration -Larger pieces from external user testing. Both are additive — nothing in the +Larger pieces from external user testing. All are additive — nothing in the current build depends on them. +- [ ] **ZcashNames (ZNS) integration** — human-readable names for FROST + groups/wallets (e.g. `treasury.zcash` → the group's shielded receive + address). Repo: https://github.com/zcashme/zcashnames + + How ZNS works: names are claimed/updated **on-chain via ZIP-321 payment + URIs + signed memos**, and a separate **ZNS Indexer / Directory** service + (SQL-backed, with a web app) indexes them for resolution — so a wallet + resolves a name by querying that directory, not by scanning the chain + itself. Two directions, very different effort: + + - **Resolve (read) — low effort, high value.** Accept a `name.zcash` in the + Send recipient field and in contact entries; resolve it to an address via + the ZNS directory before building the tx. Pairs naturally with the + avatars/account-profile identity work. Gated on the directory exposing a + public resolver API (likely HTTP; no confirmed Rust crate yet — verify). + **Trust caveat:** the resolver is external infrastructure, so ALWAYS show + the resolved shielded address for confirmation before a send — a wrong or + compromised resolver could otherwise redirect funds. Never send to a name + without surfacing what it resolved to. + + - **Register/claim (write) — higher effort.** Let a group publish a name for + its receive address. This is a threshold-authorised on-chain action, so it + fits Cyze's existing FROST send + memo path — but confirm the exact + claim/update memo + ZIP-321 format against the ZNS spec first, and decide + who in the group is allowed to initiate a (re)claim. + + Do the resolver first; it's the piece that makes long unified addresses + usable and is independent of the write path. + - [ ] **User avatars** — let a user pick an avatar, shown next to their name everywhere they are referenced (contacts, group participant lists, the signer picker, "Signed by" in transaction history, the inbox coordinator From 52a2bd2ae1c8020c40478925a867968182e15411 Mon Sep 17 00:00:00 2001 From: blocknodes Date: Sun, 2 Aug 2026 00:30:18 +0000 Subject: [PATCH 8/8] fix(wallet): include Ironwood pool in notes, history, and address rotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several read paths still assumed an Orchard-only wallet, so after receiving into or migrating to Ironwood, funds were correct on-chain but misrepresented in the UI: - wallet_notes queried only orchard_received_notes → Ironwood notes were absent from Review Notes (and undercounted the FROST rounds a full-balance send needs). Now queries both pools' (identical) tables and merges, largest-first. - wallet_history's received query was Orchard-only → Ironwood receipts were missing from history. Now unions both note tables before grouping per tx. (The sent path already uses pool-agnostic v_transactions, so it needed no change.) - count_orchard_received_notes (drives receive-address rotation on new activity) counted only Orchard, so a post-NU6.3 receive — which lands in Ironwood — would never rotate the address, silently reusing it across payments. Renamed to count_received_notes and now counts both pools. - Receive card + Review Notes copy updated: funds land in Ironwood post-NU6.3. cargo test (32 core) + tsc + full backend build green. Co-Authored-By: Claude Opus 4.8 --- src-tauri/core/src/wallet.rs | 191 ++++++++++++++++++------------- src-tauri/src/commands/wallet.rs | 2 +- src/screens/Groups.tsx | 17 +-- 3 files changed, 121 insertions(+), 89 deletions(-) diff --git a/src-tauri/core/src/wallet.rs b/src-tauri/core/src/wallet.rs index 5254cad..0b83472 100644 --- a/src-tauri/core/src/wallet.rs +++ b/src-tauri/core/src/wallet.rs @@ -1535,11 +1535,17 @@ pub struct TxRecord { /// clean transaction-list API on `WalletRead`. The tables queried are stable /// parts of `zcash_client_sqlite`'s schema: `transactions`, `accounts`, /// `orchard_received_notes`, and `sent_notes`. -/// Total number of Orchard notes this group has ever received. Used as a coarse -/// "wallet activity" signal to decide when to rotate the receive address (#3): -/// once the count grows, the currently-shown address may have been paid, so the -/// next view hands out a fresh diversifier. Returns 0 when no wallet db exists. -pub fn count_orchard_received_notes( +/// Total number of shielded notes this group has ever received, across both the +/// Orchard and Ironwood pools. Used as a coarse "wallet activity" signal to +/// decide when to rotate the receive address (#3): once the count grows, the +/// currently-shown address may have been paid, so the next view hands out a +/// fresh diversifier. Returns 0 when no wallet db exists. +/// +/// Counting Ironwood too matters post-NU6.3: a payment to the group's unified +/// address now lands in the Ironwood pool, so an Orchard-only count would never +/// grow on a new receive and the address would never rotate — silently reusing +/// one address across payments. +pub fn count_received_notes( data_dir: &Path, group_id: &str, network: WalletNetwork, @@ -1551,9 +1557,12 @@ pub fn count_orchard_received_notes( } let conn = open_readonly_connection(&db_path, db_key)?; let count: i64 = conn - .query_row("SELECT COUNT(*) FROM orchard_received_notes", [], |row| { - row.get(0) - }) + .query_row( + "SELECT (SELECT COUNT(*) FROM orchard_received_notes) \ + + (SELECT COUNT(*) FROM ironwood_received_notes)", + [], + |row| row.get(0), + ) .map_err(|e| CoreError::Crypto(format!("count received notes: {e}")))?; Ok(count.max(0) as u64) } @@ -1609,65 +1618,77 @@ pub fn wallet_notes( .flatten(); let tip = tip.unwrap_or(0); - let mut stmt = conn - .prepare( + // Post-NU6.3 a group holds notes in two pools: the sealed Orchard pool and + // the Ironwood pool that all new value (and migrated funds) land in. The two + // tables are structurally identical, so query each with the same shape and + // merge. Table/column names are compile-time constants, not user input, so + // interpolating them into the SQL is safe. + let mut notes = Vec::new(); + for (notes_table, spends_table, fk_col) in [ + ("orchard_received_notes", "orchard_received_note_spends", "orchard_received_note_id"), + ("ironwood_received_notes", "ironwood_received_note_spends", "ironwood_received_note_id"), + ] { + let sql = format!( "SELECT t.txid, orn.value, orn.is_change, orn.memo, t.mined_height, \ MAX(CASE WHEN spend_t.mined_height IS NOT NULL THEN 1 ELSE 0 END) AS spent_mined, \ - MAX(CASE WHEN s.orchard_received_note_id IS NOT NULL THEN 1 ELSE 0 END) AS has_spend \ - FROM orchard_received_notes orn \ + MAX(CASE WHEN s.{fk_col} IS NOT NULL THEN 1 ELSE 0 END) AS has_spend \ + FROM {notes_table} orn \ JOIN transactions t ON orn.transaction_id = t.id_tx \ - LEFT JOIN orchard_received_note_spends s ON s.orchard_received_note_id = orn.id \ + LEFT JOIN {spends_table} s ON s.{fk_col} = orn.id \ LEFT JOIN transactions spend_t ON spend_t.id_tx = s.transaction_id \ WHERE orn.account_id = ?1 \ - GROUP BY orn.id \ - ORDER BY orn.value DESC", - ) - .map_err(|e| CoreError::Crypto(format!("prepare notes query: {e}")))?; - - let rows = stmt - .query_map([account_id], |row| { - Ok(( - row.get::<_, Vec>(0)?, - row.get::<_, u64>(1)?, - row.get::<_, i64>(2)?, - row.get::<_, Option>>(3)?, - row.get::<_, Option>(4)?, - row.get::<_, i64>(5)?, - row.get::<_, i64>(6)?, - )) - }) - .map_err(|e| CoreError::Crypto(format!("execute notes query: {e}")))?; + GROUP BY orn.id" + ); + let mut stmt = conn + .prepare(&sql) + .map_err(|e| CoreError::Crypto(format!("prepare notes query: {e}")))?; - let mut notes = Vec::new(); - for row in rows { - let (mut txid_bytes, value, is_change, memo_bytes, received_height, spent_mined, has_spend) = - row.map_err(|e| CoreError::Crypto(format!("note row: {e}")))?; - // A note spent in a mined transaction is gone — not part of the balance. - if spent_mined == 1 { - continue; + let rows = stmt + .query_map([account_id], |row| { + Ok(( + row.get::<_, Vec>(0)?, + row.get::<_, u64>(1)?, + row.get::<_, i64>(2)?, + row.get::<_, Option>>(3)?, + row.get::<_, Option>(4)?, + row.get::<_, i64>(5)?, + row.get::<_, i64>(6)?, + )) + }) + .map_err(|e| CoreError::Crypto(format!("execute notes query: {e}")))?; + + for row in rows { + let (mut txid_bytes, value, is_change, memo_bytes, received_height, spent_mined, has_spend) = + row.map_err(|e| CoreError::Crypto(format!("note row: {e}")))?; + // A note spent in a mined transaction is gone — not part of the balance. + if spent_mined == 1 { + continue; + } + txid_bytes.reverse(); + let confirmations = match received_height { + Some(h) if tip as u64 >= h => tip as u64 - h + 1, + _ => 0, + }; + let status = if received_height.is_none() { + "pending" // incoming, not yet mined + } else if has_spend == 1 { + "spending" // a broadcast-but-unmined send is consuming it + } else { + "spendable" + }; + notes.push(NoteRecord { + received_txid: hex::encode(&txid_bytes), + value_zatoshis: value, + status: status.to_string(), + received_height, + confirmations, + is_change: is_change != 0, + memo: memo_bytes.as_deref().and_then(decode_zcash_memo), + }); } - txid_bytes.reverse(); - let confirmations = match received_height { - Some(h) if tip as u64 >= h => tip as u64 - h + 1, - _ => 0, - }; - let status = if received_height.is_none() { - "pending" // incoming, not yet mined - } else if has_spend == 1 { - "spending" // a broadcast-but-unmined send is consuming it - } else { - "spendable" - }; - notes.push(NoteRecord { - received_txid: hex::encode(&txid_bytes), - value_zatoshis: value, - status: status.to_string(), - received_height, - confirmations, - is_change: is_change != 0, - memo: memo_bytes.as_deref().and_then(decode_zcash_memo), - }); } + // Largest notes first, across both pools. + notes.sort_by(|a, b| b.value_zatoshis.cmp(&a.value_zatoshis)); Ok(notes) } @@ -1697,30 +1718,40 @@ pub fn wallet_history( let mut records: Vec = Vec::new(); // ── Received ──────────────────────────────────────────────────────────── - // Orchard notes for our account that are not change (is_change = 0 means + // Shielded notes for our account that are not change (is_change = 0 means // this note arrived in a transaction that we did NOT also spend from — - // i.e., someone else sent us funds). Group by transaction so one tx = one - // history entry, sum the note values, and pick the first real memo. + // i.e., someone else sent us funds). Post-NU6.3 a receive lands in the + // Ironwood pool while legacy receipts are in Orchard, so union both note + // tables (identical columns) before grouping — one tx = one history entry, + // even if a tx somehow deposited into both pools. Sum the note values, pick + // the first real memo. { + // A derived table unioning both pools' non-dummy columns. Table names are + // compile-time constants, so this static SQL carries no injection risk. + const RECEIVED_NOTES_UNION: &str = "( \ + SELECT transaction_id, account_id, value, is_change, memo FROM orchard_received_notes \ + UNION ALL \ + SELECT transaction_id, account_id, value, is_change, memo FROM ironwood_received_notes )"; + let sql = format!( + "SELECT t.txid, t.mined_height, b.time, SUM(rn.value), \ + ( SELECT rn2.memo \ + FROM {RECEIVED_NOTES_UNION} rn2 \ + WHERE rn2.transaction_id = t.id_tx \ + AND rn2.account_id = ?1 \ + AND rn2.is_change = 0 \ + AND rn2.memo IS NOT NULL \ + LIMIT 1 ), \ + ( SELECT vt.fee_paid FROM v_transactions vt WHERE vt.txid = t.txid LIMIT 1 ) \ + FROM {RECEIVED_NOTES_UNION} rn \ + JOIN transactions t ON rn.transaction_id = t.id_tx \ + LEFT JOIN blocks b ON b.height = t.mined_height \ + WHERE rn.account_id = ?1 AND rn.is_change = 0 \ + GROUP BY t.id_tx \ + HAVING SUM(rn.value) > 0 \ + ORDER BY t.mined_height DESC NULLS LAST" + ); let mut stmt = conn - .prepare( - "SELECT t.txid, t.mined_height, b.time, SUM(orn.value), \ - ( SELECT orn2.memo \ - FROM orchard_received_notes orn2 \ - WHERE orn2.transaction_id = t.id_tx \ - AND orn2.account_id = ?1 \ - AND orn2.is_change = 0 \ - AND orn2.memo IS NOT NULL \ - LIMIT 1 ), \ - ( SELECT vt.fee_paid FROM v_transactions vt WHERE vt.txid = t.txid LIMIT 1 ) \ - FROM orchard_received_notes orn \ - JOIN transactions t ON orn.transaction_id = t.id_tx \ - LEFT JOIN blocks b ON b.height = t.mined_height \ - WHERE orn.account_id = ?1 AND orn.is_change = 0 \ - GROUP BY t.id_tx \ - HAVING SUM(orn.value) > 0 \ - ORDER BY t.mined_height DESC NULLS LAST", - ) + .prepare(&sql) .map_err(|e| CoreError::Crypto(format!("prepare receive query: {e}")))?; let rows = stmt diff --git a/src-tauri/src/commands/wallet.rs b/src-tauri/src/commands/wallet.rs index f01d119..895947e 100644 --- a/src-tauri/src/commands/wallet.rs +++ b/src-tauri/src/commands/wallet.rs @@ -307,7 +307,7 @@ async fn resolve_receive_address( let (network, _url, _ufvk) = group_wallet_ctx(state, group_id).await?; let db_key = state.wallet_db_key(group_id).await?; let current_notes = - wallet::count_orchard_received_notes(&state.data_dir, group_id, network, db_key.as_ref())?; + wallet::count_received_notes(&state.data_dir, group_id, network, db_key.as_ref())?; let mut settings = state.load_settings(); let entry = settings.receive_state.entry(group_id.to_string()).or_default(); diff --git a/src/screens/Groups.tsx b/src/screens/Groups.tsx index ddfa66f..9f839fc 100644 --- a/src/screens/Groups.tsx +++ b/src/screens/Groups.tsx @@ -220,12 +220,13 @@ function validateRecipient( return null; } -/** Receive / shield-into-group card: shows the group's *rotating* Orchard - * unified address. Each address is a fresh diversifier of the same viewing key +/** Receive / shield-into-group card: shows the group's *rotating* unified + * address. Each address is a fresh diversifier of the same viewing key * (#3), so incoming payments aren't linkable by a reused address. The address * auto-advances once the group has received new notes; the user can also force * a fresh one. "Shielding" into the group means sending to this address from a - * personal wallet — the group then holds the funds as spendable Orchard. */ + * personal wallet — post-NU6.3 the group then holds the funds as spendable + * Ironwood. */ function ReceiveShieldCard({ groupId, fallback }: { groupId: string; fallback: string | null }) { const queryClient = useQueryClient(); const [copied, setCopied] = useState(false); @@ -245,9 +246,9 @@ function ReceiveShieldCard({ groupId, fallback }: { groupId: string; fallback: s

Receive / Shield into group

Send Zcash to this unified address to fund the group. Funds arrive in the - group's shielded Orchard pool and become spendable by the - threshold. To shield transparent funds, send them here - from a personal wallet — the receive itself is the shielding step. + group's shielded Ironwood pool and become spendable by + the threshold. To shield transparent funds, send them + here from a personal wallet — the receive itself is the shielding step.