Skip to content

Ironwood (NU6.3) SDK + Orchard→Ironwood migration bridge#71

Draft
peachbits wants to merge 5 commits into
zcash-spm-deps-binaryfrom
zcash-ironwood
Draft

Ironwood (NU6.3) SDK + Orchard→Ironwood migration bridge#71
peachbits wants to merge 5 commits into
zcash-spm-deps-binaryfrom
zcash-ironwood

Conversation

@peachbits

Copy link
Copy Markdown
Contributor

Ironwood (NU6.3) SDK + Orchard→Ironwood migration bridge

Stacked on #69 (zcash-spm-deps-binary) — review only the top five commits.

Why

Zcash's Ironwood hardfork (NU6.3) activates ~end of July and introduces a new shielded pool. Without an Ironwood-capable SDK, wallets stop syncing correctly at activation; and users must migrate Orchard funds to the new pool. No upstream SDK release carries Ironwood yet — the work lives on upstream branches — so this PR pins branch hashes and swaps to release pins later (a pins-only commit, same shape as the alpha.6 bump).

What

  1. 4049a04 — Pin the Ironwood SDK + prebuilt FFI. Vendors zcash-swift-wallet-sdk @ a9637998 (upstream's michal/MOB-1455-6 integration line, minus its two external-signer commits which require an unmerged crate branch and aren't bridged here). libzcashlc is an Edge-hosted one-time build from that commit's own Rust source + the pinned ZODLIronwoodMigrationRust @ 17be9388 crate — provenance/rebuild commands in scripts/build-ironwood-ffi.md, hosted at the ironwood-ffi-a9637998 pre-release, sha256-pinned. The checkout's Package.swift binaryTarget is patched to the same asset so the vendored-deps SwiftPM build resolves the new FFI. copySwift gains two Ironwood-line fixes (skip Rust/Voting — upstream gates voting off on this line; neutralize the new regtest Bundle.module reference). Supersedes the alpha.6 pins: the Ironwood line forked from ~alpha.4 and gates alpha.6's voting module off.
  2. 10a04d3 — BalanceEvent: Ironwood pool fields (ironwood{Available,Total}Zatoshi, zero until activation; deprecated sums include the new pool so funds never vanish mid-migration).
  3. a1555bd — Bridge the migration API (iOS), 15 methods: state/progress polls, note split, schedule proposal for both product paths (proposeMigrationTransfers = randomized denominated transfers over time; proposeImmediateMigration = one whole-balance transfer now), one-time pre-signing, height-due execution (executeNextPendingTransfer — seedless, transfers are pre-signed), detection/recovery (hasOverdue/hasInvalid/refreshStale/restartCurrentMigrationStep, initializeIronwoodPostUpgrade). Conventions: per-call seed (never stored); opaque base64 round-trip of the SDK's own Codable models so the user signs exactly the plan they confirmed; Swift enums flatten to discriminated unions; TransferResult non-success outcomes resolve (engine-driven retry UX); ZcashError messages carried to JS. The external-signer PCZT quartet is deliberately not bridged (Edge holds seeds).
  4. e6da919 — Android stubs: all 15 methods mirrored, rejecting with stable code IronwoodMigrationUnsupported (zcash-android-sdk has no Ironwood release; its branches mirror the Swift names, so filling these in later is mechanical).
  5. a416a51 — Changelog.

Validation

  • npm run update-sources at the pins: full regen green — 138 SDK files vendored incl. Migration.swift, 0 voting files, 17 zcashlc_migration_* decls in the header, vendored SwiftPM deps rebuilt (dep graph unchanged vs alpha.6 — grpc 1.27.3/NIO 2.95.0 — so no piratechain Handle potential throw in synchronizer.latestHeight() #22 lockstep bump needed).
  • Edge develop (RN 0.79, iOS 15.6) Release build with piratechain co-installed (consumer mode): BUILD SUCCEEDED, 0 undefined, 0 duplicate-symbol errors; 36 migration-FFI references linked into the app.
  • Runtime smoke on the sim: app boots on the Ironwood SDK, existing ZEC wallet (databases created by the alpha.6 line) opens and renders — DB compatibility exercised. No crashes.
  • npm run prepare (tsc + rollup + lint) green.

Honest limits

  • Merge ≠ activation-readiness sign-off. The migration happy path (note-split confirm, scheduled execution, stale refresh, immediate broadcast, ironwood balance events) is untestable until NU6.3 activates on testnet/mainnet or via regtest; upstream itself flags end-to-end broadcast as unverified. Pre-activation we can only verify the read-only surface rejects/reports cleanly.
  • The pinned -6 branch has no upstream PR yet; re-pin deliberately if upstream moves.
  • At the upstream Ironwood release: swap pins (commit hash, asset URL, sha256, drop the Package.swift patch) and re-diff Package.resolved (open dependabot PRs would bump NIO → piratechain lockstep + joint regen).

Consumed next by edge-currency-accountbased (engine orchestration) and edge-react-gui (migration UX) — see the project plan.

🤖 Generated with Claude Code

peachbits and others added 5 commits July 15, 2026 20:37
No tagged SDK release carries the Ironwood hardfork yet, so this pins the tip of upstream's integration line: zcash-swift-wallet-sdk @ a9637998 (branch michal/MOB-1455-6-integration-with-final-zodl, minus its top two external-signer commits, which require an unmerged migration-crate branch and are not bridged here). The libzcashlc binary is an Edge-hosted one-time build from that commit's own Rust source plus its pinned sibling migration crate (ZODLIronwoodMigrationRust @ 17be9388) - provenance and rebuild commands in scripts/build-ironwood-ffi.md; the download stays sha256-pinned. The checkout's Package.swift binaryTarget is patched to the same asset so the vendored-deps SwiftPM build resolves the new zcashlc_migration_* symbols.

copySwift grows two Ironwood-line fixes: Rust/Voting sources are skipped (upstream gates voting off on this line - the FFI exports no zcashlc_voting_* symbols), and the new regtest checkpoint Bundle.module reference is neutralized (the path is never read; RegtestCheckpointSource synthesizes its checkpoint).

This supersedes the 2.6.0-alpha.6 pins: the Ironwood line forked from ~alpha.4, and alpha.6's voting module is gated off on it. When an Ironwood SDK release tags, the swap back to upstream pins is a pins-only commit (commit hash, asset URL, sha256, drop the Package.swift patch).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ironwoodAvailableZatoshi / ironwoodTotalZatoshi join the per-pool balance split (zero until NU6.3 activates; zero on Android until its SDK ships Ironwood - the JS side defaults missing fields). The deprecated summed fields include the ironwood pool, so a migrating wallet's funds never vanish from them mid-migration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fifteen Synchronizer methods covering the SDK's migration lifecycle: state/progress polls, note split (prepare/submit), schedule proposal for both product paths (proposeMigrationTransfers = randomized denominated transfers over time; proposeImmediateMigration = one whole-balance transfer executable now), one-time pre-signing (signAndStoreMigrationSchedule), height-due execution (executeNextPendingTransfer - no seed, transfers are pre-signed), and detection/recovery (hasOverdue/hasInvalid/refreshStale/restartCurrentMigrationStep, initializeIronwoodPostUpgrade).

Conventions: the mnemonic crosses the bridge per call and is never stored (as createTransfer/shieldFunds); proposals and schedules round-trip as opaque base64 of the SDK's own Codable JSON, so the user signs exactly the plan they confirmed (a re-proposal would produce different randomized amounts); Swift enums flatten to discriminated unions (no serde tagging leaks to JS); TransferResult non-success outcomes resolve rather than reject - rejections are reserved for thrown ZcashError, whose message (rustMigration* detail) is carried to JS. No fullySynced gate: executeNextPendingTransfer is designed to run without full sync, and isSyncRequiredBeforeNextTransfer is the SDK's own gate. The surface is pull-based by design; the SDK persists all migration state in its own database. The external-signer PCZT quartet is deliberately not bridged (Edge holds seeds locally).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
zcash-android-sdk has no Ironwood release yet. These mirror the iOS bridge signatures exactly (the JS API is the contract) and reject with the stable code IronwoodMigrationUnsupported so the app can feature-gate per platform. Fill in against the android SDK's migration API when it ships - its ironwood branches mirror the Swift names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant