From 4b8b4deff5652a360d7cbb545ccdbffc3e4fe333 Mon Sep 17 00:00:00 2001 From: peachbits Date: Tue, 2 Jun 2026 16:14:10 -0700 Subject: [PATCH 1/4] Upgrade Zcash SDK to version 2.5.1 and update related dependencies - Android use scanning progress from processor - Android error handler was removed - iOS sdk packaging updated to use bundled ffi --- android/build.gradle | 4 +- .../java/app/edge/rnzcash/RNZcashModule.kt | 25 ++++++----- scripts/updateSources.ts | 42 ++++++++++++------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 76017d5..a5a008b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -49,8 +49,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.paging:paging-runtime-ktx:2.1.2' - implementation 'cash.z.ecc.android:zcash-android-sdk:2.4.0' - implementation 'cash.z.ecc.android:zcash-android-sdk-incubator:2.4.0' + implementation 'cash.z.ecc.android:zcash-android-sdk:2.5.1' + implementation 'cash.z.ecc.android:zcash-android-sdk-incubator:2.5.1' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3" } diff --git a/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt b/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt index 15330b8..d9632c5 100644 --- a/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt +++ b/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt @@ -82,19 +82,26 @@ class RNZcashModule( } val wallet = getWallet(alias) val scope = wallet.coroutineScope - combine(wallet.progress, wallet.networkHeight) { progress, networkHeight -> - return@combine mapOf("progress" to progress, "networkHeight" to networkHeight) + // Synchronizer.progress now blends scan + recovery and never hits 100%, so + // read the un-blended per-wallet scan progress off the processor instead. + combine(wallet.processor.scanProgress, wallet.networkHeight, wallet.status) { scanProgress, networkHeight, status -> + return@combine mapOf("scanProgress" to scanProgress, "networkHeight" to networkHeight, "status" to status) }.collectWith(scope) { map -> - val progress = map["progress"] as PercentDecimal + val scanProgressDecimal = map["scanProgress"] as PercentDecimal + val status = map["status"] as Synchronizer.Status var networkBlockHeight = map["networkHeight"] as BlockHeight? if (networkBlockHeight == null) networkBlockHeight = BlockHeight.new(birthdayHeight.toLong()) + // Force 100 once the synchronizer reports SYNCED so truncation in + // toPercentage() can't leave a fully-synced wallet stuck below 100. + val scanProgress = when (status) { + Synchronizer.Status.SYNCED -> 100 + else -> scanProgressDecimal.toPercentage() + } + sendEvent("UpdateEvent") { args -> args.putString("alias", alias) - args.putInt( - "scanProgress", - progress.toPercentage(), - ) + args.putInt("scanProgress", scanProgress) args.putInt("networkBlockHeight", networkBlockHeight.value.toInt()) } } @@ -200,10 +207,6 @@ class RNZcashModule( handleError("error", error) false } - wallet.onSubmissionErrorHandler = { error -> - handleError("error", error) - false - } wallet.onChainErrorHandler = { errorHeight, rewindHeight -> val message = "Chain error detected at height: $errorHeight. Rewinding to: $rewindHeight" handleError("error", Throwable(message)) diff --git a/scripts/updateSources.ts b/scripts/updateSources.ts index dd0b301..abf84fe 100644 --- a/scripts/updateSources.ts +++ b/scripts/updateSources.ts @@ -21,31 +21,43 @@ async function main(): Promise { await copyCheckpoints(disklet) } +// The Swift SDK version to vendor. The matching libzcashlc.xcframework is +// downloaded from this release's assets (see rebuildXcframework). +const ZCASH_SWIFT_SDK_VERSION = '2.5.1' + function downloadSources(): void { getRepo( 'ZcashLightClientKit', - 'https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk.git', - // 2.4.0: - '1cf8a2375264995224f8282eaf63931439c28368' - ) - getRepo( - 'zcash-light-client-ffi', - 'https://github.com/Electric-Coin-Company/zcash-light-client-ffi.git', - // 0.19.0: - 'a7211faa2cea15db017fa138043ba712f61724a2' + 'https://github.com/zcash/zcash-swift-wallet-sdk.git', + // 2.5.1: + '7d947516bf1e5348ec859719cfc1dbafd4d3135e' ) + // libzcashlc is no longer a separate package as of SDK 2.5.x — it ships as a + // binaryTarget zip on the SDK's GitHub release, downloaded in rebuildXcframework(). } /** - * Re-packages zcash-light-client-ffi. + * Downloads and re-packages the libzcashlc XCFramework. + * + * As of SDK 2.5.x the FFI ships as a release-asset zip on the Swift SDK repo + * (no longer a separate zcash-light-client-ffi package). * * An XCFramework can either include a static library (.a) * or a dynamically-linked library (.framework). - * The zcash-light-client-ffi package tries to stuff a static library - * into a dynamic framework, which doesn't work correctly. + * The published XCFramework stuffs a static library into a dynamic framework, + * which doesn't work correctly. * We fix this by simply re-building the XCFramework. */ async function rebuildXcframework(): Promise { + // Download the prebuilt libzcashlc XCFramework from the SDK's GitHub release. + // (The SDK's Package.swift `.binaryTarget` points at this same asset.) + console.log('Downloading libzcashlc XCFramework...') + const zipUrl = `https://github.com/zcash/zcash-swift-wallet-sdk/releases/download/${ZCASH_SWIFT_SDK_VERSION}/libzcashlc.xcframework.zip` + const zipPath = join(tmp, 'libzcashlc.xcframework.zip') + loudExec(tmp, ['curl', '--fail', '--location', '--output', zipPath, zipUrl]) + await disklet.delete('tmp/libzcashlc.xcframework') + loudExec(tmp, ['unzip', '-q', '-o', zipPath]) + console.log('Creating XCFramework...') await disklet.delete('ios/libzcashlc.xcframework') @@ -53,13 +65,13 @@ async function rebuildXcframework(): Promise { await disklet.setData( 'tmp/lib/ios-simulator/libzcashlc.a', await disklet.getData( - 'tmp/zcash-light-client-ffi/releases/XCFramework/libzcashlc.xcframework/ios-arm64_x86_64-simulator/libzcashlc.framework/libzcashlc' + 'tmp/libzcashlc.xcframework/ios-arm64_x86_64-simulator/libzcashlc.framework/libzcashlc' ) ) await disklet.setData( 'tmp/lib/ios/libzcashlc.a', await disklet.getData( - 'tmp/zcash-light-client-ffi/releases/XCFramework/libzcashlc.xcframework/ios-arm64/libzcashlc.framework/libzcashlc' + 'tmp/libzcashlc.xcframework/ios-arm64/libzcashlc.framework/libzcashlc' ) ) @@ -149,7 +161,7 @@ async function copySwift(): Promise { await disklet.setText( 'ios/zcashlc.h', await disklet.getText( - 'tmp/zcash-light-client-ffi/releases/XCFramework/libzcashlc.xcframework/ios-arm64/libzcashlc.framework/Headers/zcashlc.h' + 'tmp/libzcashlc.xcframework/ios-arm64/libzcashlc.framework/Headers/zcashlc.h' ) ) } From 2a63c744c54149a8b3d33b18f83adad83c7f08a3 Mon Sep 17 00:00:00 2001 From: peachbits Date: Wed, 3 Jun 2026 11:59:49 -0700 Subject: [PATCH 2/4] Report scan progress with decimal granularity (iOS + Android) Emit scanProgress as a 0-100 value that keeps its decimal places instead of truncating to an integer, so more frequent progress updates pass the sync tracker's monotonic gate. Range and consumer contract are unchanged. Co-Authored-By: Claude Opus 4.8 --- .../main/java/app/edge/rnzcash/RNZcashModule.kt | 14 +++++++++----- ios/RNZcash.swift | 12 +++++++----- src/types.ts | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt b/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt index d9632c5..d20b26b 100644 --- a/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt +++ b/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt @@ -92,16 +92,20 @@ class RNZcashModule( var networkBlockHeight = map["networkHeight"] as BlockHeight? if (networkBlockHeight == null) networkBlockHeight = BlockHeight.new(birthdayHeight.toLong()) - // Force 100 once the synchronizer reports SYNCED so truncation in - // toPercentage() can't leave a fully-synced wallet stuck below 100. + // Report scan progress as a 0-100 percentage but keep the decimal places + // (no truncation) so consumers get granular, more frequent updates. Force + // 100.0 when SYNCED, and 0.0 when not actively syncing (stopped / + // disconnected / initializing) instead of reusing a stale percentage, to + // match the iOS module. val scanProgress = when (status) { - Synchronizer.Status.SYNCED -> 100 - else -> scanProgressDecimal.toPercentage() + Synchronizer.Status.SYNCED -> 100.0 + Synchronizer.Status.SYNCING -> scanProgressDecimal.decimal.toDouble() * 100 + else -> 0.0 } sendEvent("UpdateEvent") { args -> args.putString("alias", alias) - args.putInt("scanProgress", scanProgress) + args.putDouble("scanProgress", scanProgress) args.putInt("networkBlockHeight", networkBlockHeight.value.toInt()) } } diff --git a/ios/RNZcash.swift b/ios/RNZcash.swift index 0286ea8..7783053 100644 --- a/ios/RNZcash.swift +++ b/ios/RNZcash.swift @@ -54,7 +54,7 @@ struct ConfirmedTx { } struct ProcessorState { - var scanProgress: Int + var scanProgress: Double var networkBlockHeight: Int var dictionary: [String: Any] { return [ @@ -641,15 +641,17 @@ class WalletSynchronizer: NSObject { func updateProcessorState(event: SynchronizerState) { updateBalanceState(event: event) - var scanProgress = 0 + var scanProgress = 0.0 switch event.internalSyncStatus { case .syncing(let progress, _): - scanProgress = Int(floor(progress * 100)) + // Report a 0-100 percentage but keep the decimal places (no floor) for + // granular progress. + scanProgress = Double(progress) * 100 case .synced: - scanProgress = 100 + scanProgress = 100.0 case .unprepared, .disconnected, .stopped: - scanProgress = 0 + scanProgress = 0.0 default: return } diff --git a/src/types.ts b/src/types.ts index 9affcf1..a33a50f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -71,7 +71,7 @@ export interface TransactionEvent { export interface UpdateEvent { alias: string - scanProgress: number // 0 - 100 + scanProgress: number // 0 - 100 (may include decimal places) networkBlockHeight: number } From 9e4ac5b5fe7b57f2252002790480c55311ecfc6f Mon Sep 17 00:00:00 2001 From: peachbits Date: Wed, 3 Jun 2026 12:00:09 -0700 Subject: [PATCH 3/4] Update checkpoints Co-Authored-By: Claude Opus 4.8 --- .../co.electriccoin.zcash/checkpoint/mainnet/3320000.json | 8 ++++++++ .../co.electriccoin.zcash/checkpoint/mainnet/3330000.json | 8 ++++++++ .../co.electriccoin.zcash/checkpoint/mainnet/3340000.json | 8 ++++++++ .../co.electriccoin.zcash/checkpoint/mainnet/3350000.json | 8 ++++++++ .../co.electriccoin.zcash/checkpoint/mainnet/3360000.json | 8 ++++++++ 5 files changed, 40 insertions(+) create mode 100644 android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3320000.json create mode 100644 android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3330000.json create mode 100644 android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3340000.json create mode 100644 android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3350000.json create mode 100644 android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3360000.json diff --git a/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3320000.json b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3320000.json new file mode 100644 index 0000000..6e446f6 --- /dev/null +++ b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3320000.json @@ -0,0 +1,8 @@ +{ + "network": "main", + "height": "3320000", + "hash": "00000000004fb9b204f85a15d34b0132ccf63db73275017358ffc8bc2268ad7b", + "time": 1777097332, + "saplingTree": "014961b911db6ca9648a19f611b92885e92b0c1370e39c67c9f93bc12efb51b11c01dfb252e9aebbadadec79815def64e191ba9398aa2f136fb9d20b61b4dc604d221f01ad9ff18a8ca63454ddfe55740d68ee9fe10063a74fe5daa1dff535c1f1f186140156b2c8d475ebfd67192a15994bd0ad8c1c6115714e7f4e408f5b0fb07c334069000001b9f0c44da08836c1b840aa10cbf8948c9642a007fe4db280abbbdf564a17f807013a864b735d74ed5a26c7ca7ec2851707e9ed67efb8b60dc2e1c27d334ce9ac44000000017249031a7e8a63373c6f2cca8cfff7c0b165d571a0cc2aa2462ec296053ad50701c7d6949773a176f8662f15980d4aa03c2fe37159b8202ccdbbe7a45b2a97730a013c11c5c16d930a9131cb982f34292600bcb3ad7550b2b7433d2de60f4af1c43a0000011d85b015e936981d3a869c16ed2e03aeeb2444206933acc3f7b384aeb963256601929f0d44045c58428bd8daca3e2c9ca5a0361b5573a4158251dbe9f63a84e94901931c48ea50688eae5e54c24d0df7a6b00ce498f92eb5e1cfd6a2d87d8ebd5364017d1ce2f0839bdbf1bad7ae37f845e7fe2116e0c1197536bfbad549f3876c3c590000013e2598f743726006b8de42476ed56a55a75629a7b82e430c4e7c101a69e9b02a011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e0000000000", + "orchardTree": "01020903639f27b5a404672d457bc910e84ee3a8fb30b06c63d59ae75ffe9f922e01859514ae0fa64c0296548c4b94886803715db4f7428a4029a515334cd659c91d1f000000000000015b02346fe82e10016bf619ed9b58d3901ac07ae19d1b32f6f386876a78e1712c0000017d0b4292bd823ef44a01c5fc7282c098f515c2bd712e7fef9075c60561ae460e00000131e80d81a95e579a9fd47076c28a306adf4a57d220932ab60d709e0d1197353a01e3bfb7711570dbd7c53d2f2282fdef803df6405499fa31b552d26d5e966d1a2501e138d4d2240b194bcee2e11a80b088e02020aceae603de2d45bfc012aac5e4260188443948aa43362e496ad2f4f3b16357f9d8c9e5ffc00e64b55c76fbea01d9380000012829e8aacdf1501baaeb5cb6e189d4e7182228e3d4b9acf54713595241e97f21017c8ece2b2ab2355d809b58809b21c7a5e95cfc693cd689387f7533ec8749261e01cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000" +} diff --git a/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3330000.json b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3330000.json new file mode 100644 index 0000000..cb9992e --- /dev/null +++ b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3330000.json @@ -0,0 +1,8 @@ +{ + "network": "main", + "height": "3330000", + "hash": "000000000023ab2f79bd547abbb231fd0dfb325c01e8384bf4f4378bd226cada", + "time": 1777851068, + "saplingTree": "0194213f428c8e759afdee8eb284a3e03129be7c8d7d538e6db313553ff80f3f1201d69d0e36ff0e355f995a48ec67f502b51cefb57397d6001a3a1784f99f6bd26a1f019fa63f0c50ad63a2cfcbb8708a3cc999233cde27612a2a9a6ecf617c84747351000000011c762f3514aaae599e05e5d91de67851cd35d6dfc3c3bc77f9cf47ed4a77da51000196e56ef5d4601f35444403a09f2e061fe29556aae65891fa1717cfa5b3b20c2b00017afd972f0aff5f609b77288625aa116cb4245340a053582fcb902e9c92ce44080001d0d1c34e478a0ec4a9246fb92aa17a358fd2110c31f65443ceaccc5711197f670001e1ed2cd5a21ca655ae19e2f2c367d0039f37ee35ba856791768e01e8b5012d5b00011d85b015e936981d3a869c16ed2e03aeeb2444206933acc3f7b384aeb963256601929f0d44045c58428bd8daca3e2c9ca5a0361b5573a4158251dbe9f63a84e94901931c48ea50688eae5e54c24d0df7a6b00ce498f92eb5e1cfd6a2d87d8ebd5364017d1ce2f0839bdbf1bad7ae37f845e7fe2116e0c1197536bfbad549f3876c3c590000013e2598f743726006b8de42476ed56a55a75629a7b82e430c4e7c101a69e9b02a011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e0000000000", + "orchardTree": "015ece656504bb32abdd165209fe552335e20656c1e121cbd24f505089bf13610701096f6aca1989167325c41f552965f8f52c59b3ae77973424edbc30ff65208b2a1f015a09701752283479ac2e948d7a1e912526163a895b876dac25c6435c2127eb2d000148fd1916193e59e82cac753a27cbc893f0697cd59c0d300be733f6eeeb432b2d00011f7890fded325ffb243f7c138be018e3fea2ef1d146d5dba47087cb98e3a1918014fbf25637a696d31d7b80b9fc4a8ef4d6211f9159cd931cf71535fa849bedf300001b8750f1a6d3ce7554eecac1a677918c25fdd1d52c0ec38288b77657f7b9edf2501fb87516e6d86726d35ce2277be63f70ab64687c94f01dbdad60deab1ed704d1e01fb690093c87d3bedbcd98d8c2897ae0ea318b1afafe9402c543efc7c68298d330136f488f7280bc738173c50f7096f284dea52a74be925a3010a6f0219928b1f0b0000011b965e10b3835311197d9b8b1f0219607c5adb7b4dfb80878c95e5351ef3b118000001e4bb5b2b7df9f4c3f508da258d91255399df66e84af8795377b7696bb87df42300012829e8aacdf1501baaeb5cb6e189d4e7182228e3d4b9acf54713595241e97f21017c8ece2b2ab2355d809b58809b21c7a5e95cfc693cd689387f7533ec8749261e01cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000" +} diff --git a/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3340000.json b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3340000.json new file mode 100644 index 0000000..8a794a8 --- /dev/null +++ b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3340000.json @@ -0,0 +1,8 @@ +{ + "network": "main", + "height": "3340000", + "hash": "0000000000176c646f484fd89f0849d5d12b2e72fc3b6bb19f28513c131542aa", + "time": 1778604451, + "saplingTree": "017d5d63df6a14192d72dc5e6e2a6a71fe973ca6fcf9a5857593a3fea29f7b9b24001f000001ea8124cfa09f07e8fb7fc4cb0a3b057b4b4632d76e5b5a2d6a036019f290fa5701f9c1a177d696088c1398689bc6f444d8613325e0118158c83c71ac3e1832376101381defcce60fe6d2eda20d3de8c1ccf5b3e1ae4dab9c0a6782faa15fc056960c0164a0c7286c5a9196246d0a0db160c876377cea24154133bcda23acc06ca1fa32015ed6a4099c41ded03f5dbec882a691849d4b62e0c2dff282c7a0250cefbb024c01319578858ea9e3381642e979dd307c59c2aa360392ec75e5a88c23143457f76c01b6dd3f9fe1163acb4750b9dedde2b9be4741b1ebe94cc3a676dac57ec230e461000120cc0c0ff8e16bd54c723a4340007c266b33f0a99ef18aa0a4a2cf3889f0375b01b79e8339dd14c75d334b7d22837c83b54af56dc8ffc00c1d9e000d73218c1f4501e1ed2cd5a21ca655ae19e2f2c367d0039f37ee35ba856791768e01e8b5012d5b00011d85b015e936981d3a869c16ed2e03aeeb2444206933acc3f7b384aeb963256601929f0d44045c58428bd8daca3e2c9ca5a0361b5573a4158251dbe9f63a84e94901931c48ea50688eae5e54c24d0df7a6b00ce498f92eb5e1cfd6a2d87d8ebd5364017d1ce2f0839bdbf1bad7ae37f845e7fe2116e0c1197536bfbad549f3876c3c590000013e2598f743726006b8de42476ed56a55a75629a7b82e430c4e7c101a69e9b02a011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e0000000000", + "orchardTree": "012ff8ec2da5684e75195ca3be148c2d1fdab647848993c57a0094ae56b3f8aa1a001f00016be1e58474aa3149c3134be705a323141bba08d15fda001449ee24d1473e55380175414578d3f0c6104759ba284786e7f647214afeced76161f22dca0fb0671908015bc02f397a949f4195c09d547f22b1c5243d43cd6d7187f959f1aee7ff69de0c0197ef4dc418b370caff537b1557da0a466ff9440c0109f1f248f56cbec7c78b16010eb8701f4fb780766f8dc8050fc47a1529ec1f6ea4ac2fe4191fdac7ff91041c00013a71bdcbf164f8fa61cf6a3a057167fb91fcc9296df6222d5d010c248dc7f13501bc080d714f1761a7526c31badf0a5cc7d9b192f7f9380196fcc3ce2146f71b13000188c7f21ce6fbdc7d161545b0050aa75aeeb0884849326b33180ca0365cb6210b00000140234bc97e83a54c01338f668afbf26a7e88d945d266bf2374ed25b051e8e92e01d2cadcf4fa18a265421bb67f40cdf518a208d55ea1cbaf7bdaaa12df99860d000001e4bb5b2b7df9f4c3f508da258d91255399df66e84af8795377b7696bb87df42300012829e8aacdf1501baaeb5cb6e189d4e7182228e3d4b9acf54713595241e97f21017c8ece2b2ab2355d809b58809b21c7a5e95cfc693cd689387f7533ec8749261e01cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000" +} diff --git a/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3350000.json b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3350000.json new file mode 100644 index 0000000..6fe66bd --- /dev/null +++ b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3350000.json @@ -0,0 +1,8 @@ +{ + "network": "main", + "height": "3350000", + "hash": "00000000007cf26cfa1ad66d6b09d49adb6b4cf18bf6409bfc621600c01504e1", + "time": 1779359129, + "saplingTree": "01fca7be66740db6352ed4499a6f4bb4508a6e46bc33f2d636cb19b362b21ba739001f0000000159e0fbf2bc549165950198a8fb11866defa168404dcb3b4f31d3e4d5a57e941a0000000157aff948d08dc586d69663d49816ebf59dc466cf4ba819903e865f39c41cf75500017d1a68c8d2a5fa9c517c8b24dd71ccbb332a7bf6e2518d71a253f88c4905584f012946f1f71e50fe21515671354c0447f30378066e0ed9c12664bae82f3cc77b1300000190e323f6e45d107d4c5cbe2c4cb4c18a466d71c43fb4b4613d3617ed45d8f456011d85b015e936981d3a869c16ed2e03aeeb2444206933acc3f7b384aeb963256601929f0d44045c58428bd8daca3e2c9ca5a0361b5573a4158251dbe9f63a84e94901931c48ea50688eae5e54c24d0df7a6b00ce498f92eb5e1cfd6a2d87d8ebd5364017d1ce2f0839bdbf1bad7ae37f845e7fe2116e0c1197536bfbad549f3876c3c590000013e2598f743726006b8de42476ed56a55a75629a7b82e430c4e7c101a69e9b02a011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e0000000000", + "orchardTree": "01984c9b721a04ec43f83af2fe55be4d5c35a3ffe4c5ef66f5c470f36656c30f01010355c689bb56ce852be016174c5dfb9dc318afeb7d073f65017ac66babac5e321f01307c9f8ee0f436765b99d2314a9d1bf9005bf7d43a57b29593efc2ee1d4e42120000000101a6c04f0de2a7683af45e5e89a71498c3f916da5857454f85835ae0765e5b1c01024543199efdffc0bf65e01742445be10f0e29a803117320f1465846d6a73a38000114e9dad761c617620e2222f7d0f13c21330fbdcb2fb6ad467b673cf5273c4b1b000001ddaf39259ef5e6d5b21d4213c1452be45e2f7af711bbb1176c3cf973a8c45e250164a1f5c861aea42e28991321d00dbb8ed5a0bf0a9e51a453b5766b10fabc5f2a01d4607d9c3a44b2a0e4a25a4852a897c1da40bd8e168183ba8177407a452d9d180000012058ed30845b642624f5e97c395da919472fc4cf33310e9c6c5592fb2402863a01e4bb5b2b7df9f4c3f508da258d91255399df66e84af8795377b7696bb87df42300012829e8aacdf1501baaeb5cb6e189d4e7182228e3d4b9acf54713595241e97f21017c8ece2b2ab2355d809b58809b21c7a5e95cfc693cd689387f7533ec8749261e01cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000" +} diff --git a/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3360000.json b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3360000.json new file mode 100644 index 0000000..e7c9dcc --- /dev/null +++ b/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/3360000.json @@ -0,0 +1,8 @@ +{ + "network": "main", + "height": "3360000", + "hash": "0000000000c978c3e17f5730423403a1cbbd5ed0760438bdc42ccb2691d704d9", + "time": 1780112204, + "saplingTree": "016f5a3e5e7378449a233939c7dbbc2b360b12ccce85aca6d590e60b394384ed33001f000001e04d2e260a8164be37778f82836e58853b85fdc1d974ce74c131971cea258b1c01af4546de2dfd1e537fcee95c997788264757f469b54af747acd470de5afeb6630135f26225cd71bbfba4da9f92dafab83ba4f9a5ca584d56173e55951328b5c90301bc0e7ec13ff3ccb3179dfcaeb79ef2135158895d49fc7066e19152b2dc8a182a000000015a6f7dddd2c4a83a3959d83ea432d804fb61beee384eca3ae6d95a3a2650282c013a34a53f2da9c6ad7ee7fdefc7e53b47581308409bb831d2d33476835ce7f7500108e503d54848e8fa94b9e24529ba433446f05f9cb5ca52cf046465b24dad943e000190e323f6e45d107d4c5cbe2c4cb4c18a466d71c43fb4b4613d3617ed45d8f456011d85b015e936981d3a869c16ed2e03aeeb2444206933acc3f7b384aeb963256601929f0d44045c58428bd8daca3e2c9ca5a0361b5573a4158251dbe9f63a84e94901931c48ea50688eae5e54c24d0df7a6b00ce498f92eb5e1cfd6a2d87d8ebd5364017d1ce2f0839bdbf1bad7ae37f845e7fe2116e0c1197536bfbad549f3876c3c590000013e2598f743726006b8de42476ed56a55a75629a7b82e430c4e7c101a69e9b02a011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e0000000000", + "orchardTree": "01adc0dc4968e89db5f2f59dc442c579a0eefd947c71edc2f2d7b9d3d1da3c010e01d961228e10f26de0d28a0ae3f84d0a883fe548af6146cb0e3e222de6a718b6001f01088f91a6f1e17300f8696b16b725784e5172dec953241523b669d648c78dcd1000000000011a51c0577b39dec68c9cadf4b6630031df4103d8ba0cb212896b05133bd0c70c0148f336981d1721588868aec819dcad5115b5b96efd8e45ebd5184b64e11b8a0f0001bb9c9de1d49f42f051e51acedf6aca375ddedc18ead68e6f131052d03861d7100000014a11b178cdc85ff3a87fe310311658b95fa742358e14522236093ac1ecc2cb1b0170c3f32332a37e8699942bef527ab282a6d8ecb0fc1eb73f92528aa528f6e5250001d524b4a2c2d3cc4940420cd4c854db574ecb92ae2457d5879dde5c2965615336012058ed30845b642624f5e97c395da919472fc4cf33310e9c6c5592fb2402863a01e4bb5b2b7df9f4c3f508da258d91255399df66e84af8795377b7696bb87df42300012829e8aacdf1501baaeb5cb6e189d4e7182228e3d4b9acf54713595241e97f21017c8ece2b2ab2355d809b58809b21c7a5e95cfc693cd689387f7533ec8749261e01cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000" +} From e4cc7416eabe07cba1eb6288852f0aa58c8aa409 Mon Sep 17 00:00:00 2001 From: peachbits Date: Wed, 3 Jun 2026 12:31:07 -0700 Subject: [PATCH 4/4] Upgrade Zcash SDK to 2.5.2 Both the 2.5.2 Swift SDK (and its libzcashlc.xcframework release asset) and the 2.5.2 Android SDK are now published, so vendor iOS via the normal updateSources download (pinned to the 2.5.2 release commit) and resolve the Android SDK from Maven Central. No local/shim packages remain. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 4 ++++ android/build.gradle | 4 ++-- scripts/updateSources.ts | 29 +++++++++++++++++++++++++---- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b232f26..f233d1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- changed: Upgrade sdks to v2.5.2 +- changed: Use floats for scan progress +- changed: Updated checkpoints + ## 0.10.7 (2026-04-24) - changed: Updated checkpoints diff --git a/android/build.gradle b/android/build.gradle index a5a008b..8b1875b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -49,8 +49,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.paging:paging-runtime-ktx:2.1.2' - implementation 'cash.z.ecc.android:zcash-android-sdk:2.5.1' - implementation 'cash.z.ecc.android:zcash-android-sdk-incubator:2.5.1' + implementation 'cash.z.ecc.android:zcash-android-sdk:2.5.2' + implementation 'cash.z.ecc.android:zcash-android-sdk-incubator:2.5.2' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3" } diff --git a/scripts/updateSources.ts b/scripts/updateSources.ts index abf84fe..92249df 100644 --- a/scripts/updateSources.ts +++ b/scripts/updateSources.ts @@ -4,8 +4,9 @@ // and install it into the correct locations. import { execFileSync } from 'child_process' +import { createHash } from 'crypto' import { deepList, justFiles, makeNodeDisklet, navigateDisklet } from 'disklet' -import { existsSync, mkdirSync } from 'fs' +import { existsSync, mkdirSync, readFileSync } from 'fs' import { join } from 'path' import { copyCheckpoints } from './copyCheckpoints' @@ -23,14 +24,22 @@ async function main(): Promise { // The Swift SDK version to vendor. The matching libzcashlc.xcframework is // downloaded from this release's assets (see rebuildXcframework). -const ZCASH_SWIFT_SDK_VERSION = '2.5.1' +const ZCASH_SWIFT_SDK_VERSION = '2.5.2' + +// SHA-256 of the libzcashlc.xcframework.zip release asset for the version +// above. The download is verified against this pin before it is unpacked, so a +// tampered or swapped upstream asset fails the build instead of injecting +// attacker-controlled native code. Update this whenever the SDK version bumps: +// curl -fL https://github.com/zcash/zcash-swift-wallet-sdk/releases/download//libzcashlc.xcframework.zip | shasum -a 256 +const LIBZCASHLC_XCFRAMEWORK_SHA256 = + '27089796e15eacd0e5a90e7ea01884ea5c40806cf25a6fa9a6aca933dad65813' function downloadSources(): void { getRepo( 'ZcashLightClientKit', 'https://github.com/zcash/zcash-swift-wallet-sdk.git', - // 2.5.1: - '7d947516bf1e5348ec859719cfc1dbafd4d3135e' + // 2.5.2: + 'e725a2482dced83afda91bcebe881bd0791aa359' ) // libzcashlc is no longer a separate package as of SDK 2.5.x — it ships as a // binaryTarget zip on the SDK's GitHub release, downloaded in rebuildXcframework(). @@ -55,6 +64,18 @@ async function rebuildXcframework(): Promise { const zipUrl = `https://github.com/zcash/zcash-swift-wallet-sdk/releases/download/${ZCASH_SWIFT_SDK_VERSION}/libzcashlc.xcframework.zip` const zipPath = join(tmp, 'libzcashlc.xcframework.zip') loudExec(tmp, ['curl', '--fail', '--location', '--output', zipPath, zipUrl]) + + // Verify the downloaded asset against the pinned SHA-256 before unpacking it, + // so a tampered/replaced upstream release can't inject native code into the build. + const actualSha256 = createHash('sha256') + .update(readFileSync(zipPath)) + .digest('hex') + if (actualSha256 !== LIBZCASHLC_XCFRAMEWORK_SHA256) { + throw new Error( + `libzcashlc.xcframework.zip integrity check failed: expected ${LIBZCASHLC_XCFRAMEWORK_SHA256}, got ${actualSha256}` + ) + } + await disklet.delete('tmp/libzcashlc.xcframework') loudExec(tmp, ['unzip', '-q', '-o', zipPath])