# ZIP 318: Orchard to Ironwood Migration

Status: Draft

Owners: Schell Carl Scivally, Pacu Gindre, Kris Nuttycombe

Snapshot: a34cfc091434275120ff017c92c3b50d3cef623a

Source date: 2026-10-16T02:56:04+01:00

[Source revision](https://github.com/zcash/zips/commit/a34cfc091434275120ff017c92c3b50d3cef623a)

[Official source](https://zips.z.cash/zip-0318) · [Source file](https://github.com/zcash/zips/blob/a34cfc091434275120ff017c92c3b50d3cef623a/zips/zip-0318.md) · [Discussion](https://github.com/zcash/zips/issues/1315)

## Document parts

[Part 1](https://zips.tools/zip/318) · [Part 2](https://zips.tools/zip/318?part=2)

Reading part 1 of 2. Follow all parts for the complete proposal.

Preamble

**ZIP**: 318

**Title**: Orchard to Ironwood Migration

**Owners**: 

- [Schell Carl Scivally](mailto:efsubenovex@gmail.com)
- [Pacu Gindre](mailto:pacu@zecdev.org)
- [Kris Nuttycombe](mailto:kris@nutty.land)

**Status**: Draft

**Category**: Wallet

**Created**: 2026-06-16

**License**: MIT

**Discussions-To**: [https://github.com/zcash/zips/issues/1315](https://github.com/zcash/zips/issues/1315)

<a id="terminology"></a>

## Terminology

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", "MAY", and "RECOMMENDED"
in this document are to be interpreted as described in BCP 14 <a id="user-content-fnref-bcp14"></a>
[1](/zip/318?part=2#user-content-fn-bcp14) when, and
only when, they appear in all capitals.

The terms "*Orchard pool*" and "*Ironwood pool*" are to be interpreted as
described in ZIP 229 <a id="user-content-fnref-zip-0229"></a>
[2](/zip/318?part=2#user-content-fn-zip-0229). Following the convention in the protocol
specification <a id="user-content-fnref-protocol"></a>
[3](/zip/318?part=2#user-content-fn-protocol), we use *slanted text* to refer to pool names, in order
to more clearly distinguish them from shielded protocols.

The term "network upgrade" is to be interpreted as described in ZIP 200.
<a id="user-content-fnref-zip-0200"></a>
[4](/zip/318?part=2#user-content-fn-zip-0200)

The terms "Mainnet" and "Testnet" are to be interpreted as defined in the Zcash
protocol specification. <a id="user-content-fnref-protocol-networks"></a>
[5](/zip/318?part=2#user-content-fn-protocol-networks)

The terms "trusted TXO", "untrusted TXO", "known-spendable", and
"confirmed-spendable" are to be interpreted as defined in ZIP 315. <a id="user-content-fnref-zip-0315"></a>
[6](/zip/318?part=2#user-content-fn-zip-0315)

The terms below are to be interpreted as follows:

Migration
:   The process by which a wallet transfers a user's funds from the *Orchard pool*
to the *Ironwood pool*.

Pool-crossing transfer
:   A transaction that moves value from one shielded pool to another. The net
amount crossing between the pools is revealed on-chain. <a id="user-content-fnref-zip-0209"></a>
[7](/zip/318?part=2#user-content-fn-zip-0209)

Note preparation
:   A wallet-internal send-to-self transaction (or set of such transactions)
whose purpose is to restructure the wallet's existing notes — dividing
larger notes, combining smaller ones, or both — into notes that exactly
fund the planned migration transactions, so that the entire migration
schedule can be pre-signed and broadcast without waiting for change from
earlier transactions to confirm.

Migration transaction (or part)
:   A single pool-crossing transfer that moves part of the user's *Orchard-pool*
balance to the *Ironwood pool* as part of a migration. In the recommended
scheme each migration transaction spends exactly one *Orchard-pool* note and
moves exactly one denomination to a single *Ironwood* output.

Denomination
:   A canonical amount of the form $n \times 10^k$ ZEC with $n \in \{1, 2, 5\}$
(for example `100, 50, 20, 10, 5, 2, 1, 0.5` ZEC), bounded below by the
maximum residual value and above by a cap specified in
[Amount selection, canonical quantization](#amountselectioncanonicalquantization).

Maximum residual value
:   The value below which any remainder of the balance is left unmigrated, in
order to prevent small, user-identifying amounts from being leaked in
pool-crossing transactions.

Anchor-height bucket (boundary)
:   A shared, network-wide interval of block heights delimited by *boundaries*:
blocks whose height is $\equiv 0 \pmod{M}$ for a network-wide modulus $M$
(provisionally 144). The anchor height of a migration transaction is drawn
at random from among past boundaries rather than derived from the wallet's
own chain tip, so that the anchor does not reveal when a particular wallet
last synchronized.

Cohort
:   The set of all migration transactions, from all wallets, that share the
same boundary anchor.

Multiplicity ($k$)
:   The number of migration transactions a single wallet contributes to one
cohort.

Migration schedule
:   The ordered set of migration transactions, together with their scheduled
broadcast heights, that a wallet plans in order to complete a migration.

Background scheduling
:   The use of platform mechanisms (for example, *BGTaskScheduler* on iOS or
*WorkManager* on Android) to broadcast a migration transaction at an
approximate future time without requiring the user to have the application in
the foreground.

<a id="abstract"></a>

## Abstract

This ZIP specifies best practices for wallets migrating funds from the
*Orchard pool* to the *Ironwood pool* introduced by the NU6.3 network upgrade
<a id="user-content-fnref-zip-0258"></a>
[8](/zip/318?part=2#user-content-fn-zip-0258). It is written with light client wallets in mind,
because their reliance on a light wallet server and on mobile background
scheduling makes the privacy and reliability concerns most acute, but the same
practices apply to desktop and full-node wallets.

Because a pool-crossing transfer reveals the migrated amount on-chain, directly
sending from one pool to another can reveal the wallet balance. A naive
migration risks linking transfers to a single wallet and to the user's
activity, again potentially revealing balance, and also risking that migration
transactions could be linked to personally identifying information such as IP
addresses. To mitigate this, wallets should decompose the balance into
notes with values drawn from a fixed set of denominations, which may then
be sent across the turnstile as multiple
transactions submitted to the chain over time using a network anonymity layer.
In order to avoid linking transactions via anchor selection, proofs are made
and updated against anchors drawn from shared, network-wide boundary heights,
forming cohorts that mix many wallets and de-correlate transfers from when the
user opens the application.

The migration runs as a two-phase process: a note-preparation phase followed by
a scheduled transaction-creation phase. Migration transactions are pre-signed,
persisted, and then have their proofs updated and are broadcast by best-effort
background tasks, with a fallback that prompts the user on the next application
open when a scheduled window is missed. Synchronization is kept decoupled in
time from broadcast. This ZIP also specifies user-consent, network-privacy,
progress-reporting, and error-handling requirements.

<a id="motivation"></a>

## Motivation

The *Ironwood pool*, introduced by the NU6.3 network upgrade <a id="user-content-fnref-zip-0258-2"></a>
[8](/zip/318?part=2#user-content-fn-zip-0258),
enables verification of the Zcash shielded supply after NU6.2 mitigated a
soundness flaw in the Orchard circuit
<a id="user-content-fnref-draft-zodl-valargroup-action-circuit-update"></a>
[9](/zip/318?part=2#user-content-fn-draft-zodl-valargroup-action-circuit-update). To that end, NU6.3 enables a
rule that disables ordinary payments within the old *Orchard pool* while
still permitting change <a id="user-content-fnref-zip-2006"></a>
[10](/zip/318?part=2#user-content-fn-zip-2006); therefore, wallets are required to
add functionality to migrate Orchard funds to the *Ironwood pool*.

Migrating funds between shielded pools is fundamentally different from spending
within a single pool. Within a pool, both balances and the relationships
between transactions remain private; a pool-crossing transfer, however,
necessarily reveals the net amount crossing between the pools on-chain
<a id="user-content-fnref-zip-0209-2"></a>
[7](/zip/318?part=2#user-content-fn-zip-0209), so the only privacy levers available to a wallet are the shape of
the amounts it migrates and the timing of their broadcast. If a wallet
migrates a user's entire balance in a single transaction, that amount, its
timing, and (via network-layer metadata) potentially the user's IP address are
all exposed at once, and the transfer can be correlated with the wallet's other
activity.

ZIP 315 <a id="user-content-fnref-zip-0315-2"></a>
[6](/zip/318?part=2#user-content-fn-zip-0315) already establishes that the user's consent is needed to
reveal amounts publicly, and that wallets should minimize pool crossing. A mass
migration event is a case where many users perform pool-crossing transfers in a
relatively short window. This both creates an opportunity (many simultaneous
migrations form an anonymity set) and a risk, because an observer who can
distinguish one user's transfers from the crowd learns a great deal.

A precedent exists in ZIP 308 <a id="user-content-fnref-zip-0308"></a>
[11](/zip/318?part=2#user-content-fn-zip-0308), which defined a privacy-preserving
procedure for the Sprout-to-Sapling migration by sending a bounded amount per
period and hiding individual migration transactions among those of all migrating
users. This ZIP adapts that idea to the light-client setting, where the wallet
does not run a full validator, scheduling is constrained by mobile operating
systems, and synchronization happens against a light wallet server whose operator
is a potential observer. The security analysis of migration strategies is subtle,
and the more obvious strategies leak significant information; this document
records the analysis behind the chosen strategy, including several rejected
alternatives (see [Alternatives](/zip/318?part=2#alternatives)).

The goal of this ZIP is therefore to document how a light client wallet SHOULD
perform the Orchard-to-Ironwood migration so that, by default, individual
transfers are as hard as practical to correlate to a specific wallet or to the
user's behaviour, while still completing the migration reliably and giving the
user enough information to consent to any residual information leakage. The
separate NU6.3 routing change — that new payments to Orchard receivers (inside
existing unified addresses) are sent via the *Ironwood pool* <a id="user-content-fnref-zip-2006-2"></a>
[10](/zip/318?part=2#user-content-fn-zip-2006) — is a
general send-path concern and is out of scope, although the migration
destination is the same *Ironwood* receiver.

<a id="requirements"></a>

## Requirements

- The user can migrate *Orchard-pool* funds to the *Ironwood pool*, and is
  informed that using a privacy preserving migration method is necessary for
  the user to be able to preserve the privacy of transaction amounts when
  spending Orchard funds.

- Before any funds leave the *Orchard pool*, the wallet obtains the user's consent
  to the public revelation of pool-crossing amounts, consistent with
  ZIP 315. <a id="user-content-fnref-zip-0315-3"></a>
  [6](/zip/318?part=2#user-content-fn-zip-0315)

- All *Orchard-pool* funds, except a residual value, are eventually transferred
  to the *Ironwood pool*.

- The migration process, by default, preserves the following privacy
  invariants, to the extent practical on the target platform:
  
  
  
  
  
  - **Transfer unlinkability.** An observer cannot cluster the migration
    transactions of a single wallet — by value, structure, anchor, expiry, or
    timing — into a per-wallet set.
  
  - **Behavioural de-correlation.** Broadcasts of migration transactions are
    de-correlated from the user's interaction with the application and from wallet
    synchronization, so that transfers reveal neither when the user opens the
    application nor when the wallet has synchronized.
  
  - **Balance privacy.** Neither any single transfer nor the observable set of
    transfers reveals any wallet's total *Orchard-pool* balance.
  
  - **Note-distribution privacy.** The migration does not reveal the
    distribution of individual note values held by the wallet.
  
  - **Holdings-concentration privacy.** The migration does not reveal the
    number of users that hold funds in the *Orchard pool* or how funds are
    distributed between those users' holdings.
  
  - **Migration-status privacy.** A chain-observing adversary who knows the
    values of notes a wallet has received — including an adversary who has
    deliberately targeted a victim by sending notes of attacker-chosen
    values — cannot determine whether or when the wallet has migrated those
    funds.

- The user can authorize the migration in a small number of signing sessions —
  a single session for typical balances and note distributions. Additional
  sessions are needed only when multi-layer note preparation is required and
  the wallet does not pre-sign the layers as a chain; this affects wallets
  holding very many notes and wallets with very large balances identically.

- The migration completes reliably even when best-effort background scheduling does
  not run, without requiring the user to keep the application in the foreground.

- Before the migration begins, the user is given an informed choice about
  network-layer privacy options (Tor, VPN, or Nym).

- The wallet reports migration progress, and does not present the fallback
  (prompting on the next application open) as an error.

- The migration adapts safely when the user spends *Orchard-pool* funds outside the
  migration, when scheduled transactions expire, or when the application is
  reinstalled.

<a id="non-requirements"></a>

## Non-requirements

The following are explicitly **not** requirements of this flow:

- **Statelessness.** The migration is permitted to rely on locally persisted
  state (the migration schedule and pre-signed transactions). It is not required
  to be reconstructible from on-chain data alone. (The tradeoff against a
  stateless, chain-recoverable design is discussed in
  [Rationale for the stateful design](#rationaleforthestatefuldesign).)

- **Multi-device and recovery continuity.** A migration in progress is not
  required to be resumable on another device, nor after restoring from seed on a
  new device. A wallet that detects unspent *Orchard-pool* funds after such a
  restore may treat the situation as requiring a fresh migration.

- **Guaranteed background execution.** Background scheduling is best-effort.
  Wallets are not required to guarantee that any transfer is broadcast without the
  user ever opening the application.

- **Network-layer anonymity.** Network-layer anonymity (for example, Tor) is
  offered as an opt-in but is not mandated; the user MAY proceed without it but
  this option should not be recommended except in cases where the user is
  confident in the privacy provided by the attached lightwalletd server, e.g.
  Tor should not be required if the user connects to their own private
  lightwalletd.

- **Provably leak-free migration.** The procedure does not have to provably leak
  no information; migration transactions need only be hidden among the population
  of canonical-shaped *Orchard*→*Ironwood* spends (see
  [Rationale for the canonical transaction shape](#rationaleforthecanonicaltransactionshape)),
  and a small residual amount is left unmigrated.

<a id="specification"></a>

## Specification

<a id="overview-two-phase-architecture"></a>

### Overview, two-phase architecture

A wallet performing a privacy-preserving migration SHOULD implement it as two
phases:

1. **Note preparation** (see [Phase 1, Note preparation](#phase1notepreparation)):
   quantization of the migratable balance into canonical denominations, followed
   by one or more wallet-internal send-to-self transactions that restructure the
   *Orchard-pool* balance into notes that exactly fund the planned migration
   transactions.

2. **Scheduled migration transactions** (see
   [Phase 2, Scheduled migration transactions](#phase2scheduledmigrationtransactions)):
   pre-signed pool-crossing transfers, each transferring a canonical denomination
   at a scheduled broadcast height with a boundary anchor, broadcast by
   best-effort background tasks.

A wallet MAY offer an immediate single-transfer migration in addition to the
privacy-preserving flow (see
[Migration entry point and user consent](#migrationentrypointanduserconsent)),
but it SHOULD present the privacy trade-off of doing so.

<a id="migration-entry-point-and-user-consent"></a>

### Migration entry point and user consent

When a wallet detects a non-zero confirmed-spendable *Orchard-pool* balance
once the NU6.3 network upgrade is scheduled or has activated, it SHOULD surface
a dedicated migration entry point. (Surfacing the entry point before activation
allows note preparation to begin early; see
[Phase 1, Note preparation](#phase1notepreparation).)

- The entry point MUST display the *Orchard-pool*-specific balance at risk.

- The wallet SHOULD offer the user a choice between:
  
  
  
  
  
  - **Migrate immediately**: a single pool-crossing transfer with no delay and
    minimal privacy; and
  
  - **Migrate with privacy**: the scheduled, quantized approach specified below.

- Before any funds leave the *Orchard pool*, the wallet MUST present the full
  proposed migration schedule and obtain the user's confirmation. This
  confirmation constitutes the user's consent, required by ZIP 315 <a id="user-content-fnref-zip-0315-4"></a>
  [6](/zip/318?part=2#user-content-fn-zip-0315), to
  the public revelation of the pool-crossing amounts.

- Once the schedule is confirmed, individual transfers within it SHOULD be
  broadcast automatically when their scheduled broadcast height arrives, and
  SHOULD NOT require separate per-transfer confirmation.

To keep the choice tractable for users who may not know what is best, the wallet
SHOULD minimize the number of privacy-tuning options exposed.

<a id="phase-1-note-preparation"></a>

### Phase 1, Note preparation

Note preparation begins with **amount selection**: quantization of the
migratable balance into the canonical denominations that the Phase 2 migration
transactions will transfer. Quantization is necessarily the first step,
because the note-preparation transactions cannot be constructed without
knowing the exact note values they must produce.

#### Amount selection, canonical quantization

The migratable *Orchard-pool* balance MUST be decomposed into a set of migration
transactions, each transferring a single denomination. It is RECOMMENDED that
the denominations be selected by **canonical quantization** rather than by
random or arbitrary sizing. Canonical denominations collide across wallets
and resist leaking information that can be used for wallet fingerprinting (see
[Why value collision provides privacy](#whyvaluecollisionprovidesprivacy)).
A wallet MAY use a different amount-selection strategy provided it achieves the
same effect, namely that migrated amounts collide across the migrating population
rather than fingerprinting the wallet. Random arbitrary amounts do not achieve
this and are a rejected alternative (see
[Alternatives](/zip/318?part=2#alternatives)).

- Permitted denominations are the values $v = n \times 10^k$ ZEC with
  $n \in \{1, 2, 5\}$ and `MAX_RESIDUAL_VALUE` $\le v <$ `DENOM_CAP`, where:
  
  
  
  
  
  - `MAX_RESIDUAL_VALUE`, the smallest permitted denomination, is
    **0.01 ZEC**; the portion of the balance smaller than this value should not
    be decomposed and is left unmigrated as the residual.
  
  - `DENOM_CAP` is **10000 ZEC plus the canonical fee**, making
    **10000 ZEC** the largest pool-crossing denomination; equivalently,
    `DENOM_CAP` caps the funding-note values (denomination plus fee) produced
    by note preparation.

- The balance is decomposed by **decimal digit expansion** of the integer- and
  fractional-ZEC digits, each digit expanding greedily into parts drawn from
  $\{5, 2, 1\}$ times its place value (so a digit of 9 yields `5, 2, 2`; 8
  yields `5, 2, 1`; 7 yields `5, 2`; 6 yields `5, 1`; 4 yields `2, 2`; 3
  yields `2, 1`). Value in places above the largest denomination is decomposed
  into repeated maximal-denomination (10000 ZEC) parts. For example:
  
  
  
  
  ```
  123.45  ZEC -> [100, 20, 2, 1, 0.2, 0.2, 0.05]
  540     ZEC -> [500, 20, 20]
  25000   ZEC -> [10000, 10000, 5000]
  ```

- The baseline quantization is a **pure, deterministic function of the
  balance**: there is no rare, high-entropy "remainder" output. Every emitted
  denomination is canonical and therefore collision-prone across wallets,
  whether the decomposition is deterministic or randomized (below). This is the
  key privacy property (see [Privacy Implications](#privacyimplications)).

- A wallet MAY randomize the decomposition for improved balance hiding,
  substituting smaller denominations for the greedy choice. At each selection
  step the available options are the denominations $n \times 10^k$, for the
  magnitude $10^k$ of the value remaining, that do not exceed that value.
  Smaller denominations SHOULD be chosen with low frequency so that expected
  part counts stay small; provisionally: where all of
  $\{1, 2, 5\} \times 10^k$ are available, $1 \times 10^k$ is chosen with 10%
  frequency and $2 \times 10^k$ with 25% frequency ($5 \times 10^k$
  otherwise); where only $\{1, 2\} \times 10^k$ are available, $1 \times 10^k$
  is chosen with 25% frequency. Randomization changes only which canonical
  denominations are emitted, never the values themselves.

- A wallet SHOULD exclude any preexisting unspent notes that already have quantized
  values from the computation of balance to be migrated; this situation can arise from
  a migration that is resumed after a wallet restore and such notes can be used in
  a Migration Transaction directly.

- The quantization leaves a deterministic residual of less than
  `MAX_RESIDUAL_VALUE` (the balance modulo the smallest denomination)
  unmigrated; this residual remains in the *Orchard pool* at the end of the
  migration. Notes individually smaller than `MAX_RESIDUAL_VALUE` are
  nonetheless migratable, because note preparation may combine them; whether
  consuming a given small note is economic is a ZIP 317 marginal-fee
  consideration. <a id="user-content-fnref-zip-0317"></a>
  [12](/zip/318?part=2#user-content-fn-zip-0317)

The fee for each part is in addition to its denomination (the visible
Orchard-out value of a part is its denomination plus the canonical fee;
equivalently the *Ironwood* output equals the denomination). Each part is
funded by a single note of exactly this value, produced by note preparation.

#### Note preparation transactions

A migration transaction spends exactly one *Orchard-pool* note (see
[Canonical migration transaction structure](#canonicalmigrationtransactionstructure)).
The purpose of the note-preparation transactions is to ensure that a note of
exactly the right value exists for every part of the schedule, so that every
part can be funded independently of the others and the entire schedule can be
pre-signed at once. After NU6.3, anchors are no longer committed to by signature
digests and therefore migration transactions may be signed as soon as preparation
transactions that construct the notes being spent have been constructed. Only the
proving step requires that the funding notes have been mined and that a candidate
boundary anchor exists (see
[Anchor-height bucketing and cohorts](#anchor-heightbucketingandcohorts)).
Whether preparation divides larger notes into smaller ones, combines smaller
notes into larger ones, or both, is purely a function of the wallet's existing
note distribution, and the distinction is not visible on-chain (see
[Rationale for the canonical transaction shape](#rationaleforthecanonicaltransactionshape)).

- Note preparation MUST be implemented as one or more wallet-internal
  send-to-self transactions with no external receiver.

- Each note-preparation transaction SHOULD use the canonical expiry height
  specified for migration transactions in
  [Canonical migration transaction structure](#canonicalmigrationtransactionstructure),
  computed from the note-preparation transaction's scheduled broadcast height.

- For mobile wallets, proving time is a concern. For that reason, and also for
  indistinguishability, Note preparation transactions SHOULD be constructed
  such that each preparation transaction contains exactly
  16 Orchard actions, padding if necessary to reach this threshold. Because a
  bundle's action count is the sum of its spends and outputs (each is paired
  with a fabricated counterpart under NU6.3), a 16-action transaction can
  consume and produce at most 16 notes in total — for example, 15 spends and
  one output when consolidating, or one spend and 15 outputs when splitting.

- The output notes of preparation are determined by the quantization above:
  one note per scheduled part, valued at exactly that part's denomination plus
  the canonical fee, together with at residual notes with cumulative value less than
  `MAX_RESIDUAL_VALUE`.

- Where the number of notes involved exceeds what a single 16-action
  transaction can accommodate, preparation SHOULD be partitioned into multiple
  transactions with disjoint input notes wherever possible, so that the
  transactions can confirm in parallel rather than chaining through one
  another's outputs.

- Partitioning with disjoint inputs is not always possible: a funding note
  that must combine value from more notes than one transaction can spend
  (consolidation), or a large note that must be divided into more funding
  notes than one transaction can produce (splitting), requires preparation to
  proceed in **layers**, with later preparation transactions spending the
  outputs of earlier ones. While all layers MAY be constructed and signed in
  a single  session, each layer can be proved and broadcast only after the
  previous layer's outputs have been mined and witnessed, so each layer
  extends the preparation phase by mining and witness-synchronization latency
  — a handful of blocks, not an anchor-height bucket, since preparation
  transactions anchor at the wallet's ordinary near-tip depth (see below).
  The number of layers required is logarithmic in the number of notes
  consumed or produced, with base approximately 15 (the per-transaction
  fan-in or fan-out).

- On-chain, layered splitting and layered consolidation are indistinguishable
  from each other and from parallel preparation of the same transaction
  count: preparation values and direction are fully shielded, so a
  large-balance wallet dividing a single note and a wallet consolidating many
  small notes present the same observable footprint (see
  [Rationale for the canonical transaction shape](#rationaleforthecanonicaltransactionshape)).

- A note-preparation transaction SHOULD anchor at the wallet's ordinary
  near-tip anchor depth (a small number of confirmations below the chain tip
  observed at proving time), **not** at a bucketed boundary height. The
  boundary-anchor machinery exists to protect the pool-crossing migration
  transactions, whose crossing values are public: their anchors must not
  reveal when a particular wallet synchronized. A preparation transaction is
  a fully shielded send-to-self — its values, direction, and linkage are
  hidden — so its anchor reveals only that some wallet recently synchronized,
  which broadcasting any transaction already reveals. Using the ordinary
  anchor keeps preparation proofs identical to those of routine shielded
  spends and lets successive layers proceed without waiting out boundary
  intervals.

- The broadcasts of a wallet's preparation transactions SHOULD be temporally
  decoupled from one another: the delay from each preparation transaction to
  the next is drawn (using a CSPRNG) from an exponential distribution with
  mean `PREP_MEAN_DELAY` (**16 blocks**, about twenty minutes at 75-second
  block spacing), rounded to the nearest whole number of blocks, with any
  draw exceeding `PREP_MAX_DELAY` (**96 blocks**, about two
  hours) discarded and redrawn; a later layer's schedule begins after the
  previous layer's last scheduled transaction plus a small mining margin.
  Although preparation values are fully shielded, a burst of identically
  shaped padded transactions appearing at a single moment is itself a
  linkable cluster — by shape and timing — and such a burst would also
  visibly precede the wallet's scheduled transfers. The much tighter spacing
  relative to the transfers' `MEAN_DELAY` is possible precisely because no
  anchor bucketing constrains preparation, and keeps the preparation phase
  short while preventing the cluster.

- If the wallet's existing notes already exactly fund every planned part, note preparation MAY
  be skipped.

- Note preparation MAY be performed at any time after the user initiates the
  migration, including before the network upgrade that activates the
  *Ironwood pool* has finalized.

- The wallet MUST wait until the boundary that closes the anchor-height bucket
  in which a note-preparation transaction was mined has passed before treating
  its output notes as available to fund the Phase 2 migration transactions.
  This is implied by the candidate anchor set (see
  [Anchor-height bucketing and cohorts](#anchor-heightbucketingandcohorts)):
  no boundary at or after the notes' creation exists any earlier. Spending the
  notes *across the turnstile* sooner would require anchoring to a non-boundary
  tree state between the preparation transaction and the next boundary, making
  it possible for a lightwalletd-compromising adversary to correlate a user's
  synchronization behaviour (attached to a public IP address) with the anchor
  selected by their wallet. This constraint applies only to the pool-crossing
  spends: a later *preparation* layer may spend the notes as soon as they are
  mined and witnessed, per the ordinary-anchor rule above.

<a id="phase-2-scheduled-migration-transactions"></a>

### Phase 2, Scheduled migration transactions

#### Canonical migration transaction structure

Each migration transaction SHOULD have:

- exactly one *Orchard* spend, with the Orchard bundle padded to exactly two
  actions, so that the presence or absence of an *Orchard* change output is not
  observable;

- exactly one *Ironwood* output, whose value is a single canonical denomination,
  in a single-action *Ironwood* bundle with no padding action (see
  [Rationale for the canonical transaction shape](#rationaleforthecanonicaltransactionshape));

- no transparent inputs or outputs;

- no spends from any pool other than *Orchard*;

- the canonical fee (provisionally the ZIP 317 minimum fee) <a id="user-content-fnref-zip-0317-2"></a>
  [12](/zip/318?part=2#user-content-fn-zip-0317);

- the canonical anchor described in
  [Anchor-height bucketing and cohorts](#anchor-heightbucketingandcohorts) and
  the canonical expiry height described below;

- `lock_time = 0`;

- no nonstandard fee amount or any other outputs (this would partition the
  anonymity set between wallets that add such outputs and those that do not).

The canonical expiry height is computed from the transaction's scheduled
broadcast height: take the most recent height at or below it that
`EXPIRY_MODULUS` (the number of blocks corresponding to 30 days, 34560 blocks at 75-second block
spacing) divides without remainder, and add 2 × `EXPIRY_MODULUS`
(69120 blocks): a rolling window that guarantees every transaction between one
and two months of validity from its scheduled broadcast. Unlike the anchor,
the expiry height is committed by the transaction digest <a id="user-content-fnref-zip-0229-2"></a>
[2](/zip/318?part=2#user-content-fn-zip-0229) and is
therefore fixed when the schedule is signed; because the schedule precomputes
every broadcast height (see [Transfer scheduling](#transferscheduling)), the
expiry is nonetheless known at signing time. The bucketed rule makes the
committed value identical for every migration transaction — from any wallet —
whose scheduled broadcast falls within the same 30-day period, so an expiry
height reveals only the coarse period in which its broadcast was scheduled,
information the broadcast itself substantially makes public. (Deriving the
expiry from the construction height instead would reveal the otherwise
unobservable period in which the wallet's schedule was created, and would
deny the late parts of a long schedule their full validity window, forcing
needless rebuilds.) For example, NU6.3 activates at Mainnet height 3428143, so every
migration transaction scheduled for broadcast before height 3456000 has
expiry height 3490560, and one scheduled between heights 3456000 and 3490559
has expiry height 3525120. Parts still unbroadcast when their expiry height
is reached are rebuilt with a fresh anchor and expiry (see
[Error handling](#errorhandling)).

This strict, uniform structure serves two audiences. To an observer, it makes
every migration transaction structurally identical both to every other
migration transaction and to an ordinary manually created *Orchard*→*Ironwood*
spend, and it hides whether a change output is present (see
[Rationale for the canonical transaction shape](#rationaleforthecanonicaltransactionshape)).
To the wallet that created it, the same structure serves as a canonical
migration-transaction predicate for chain-based status recovery, with
disambiguation from other conforming transactions provided by viewing-key
information that an observer lacks: whether the *Ironwood* output belongs to
the wallet's own account, and whether its value is a canonical denomination.

#### Anchor-height bucketing and cohorts

- The anchor height of each migration transaction MUST be a shared,
  network-wide boundary height, rather than a value derived from the wallet's
  own chain tip, so that the anchor does not reveal precisely when this wallet
  last synchronized.

- Buckets are delimited by **boundaries**: blocks whose height is
  $\equiv 0 \pmod{M}$, with $M$ provisionally `144`. At the current target
  block spacing of 75 seconds, a boundary occurs approximately every
  $144 \times 75\,\text{s} = 3$ hours. This interval concentrates migration
  transactions onto fewer shared anchors, enlarging per-anchor cohorts.
  `EXPIRY_MODULUS` (34560 blocks) is an exact multiple of $M$ (240 buckets),
  so expiry buckets align with anchor buckets.

- Each migration transaction MUST take, as its *Orchard* anchor, the tree
  state as of a boundary drawn from the **candidate anchor set**: those
  boundaries that are above the NU6.3 activation height, at or after the
  height at which the transaction's funding note was created, and at or
  before the most recent boundary the wallet has observed at proving time. An
  anchor therefore reveals only that its creator had scanned beyond that
  boundary at *some* time before broadcast, and sharing it does **not** link
  a wallet's transactions to one another (see
  [Rationale for anchor selection](#rationaleforanchorselection)).

- The draw MUST be recency-weighted: the anchor's age $a \geq 1$, measured in
  boundaries before the most recent boundary the wallet has observed at
  proving time, is drawn (using a CSPRNG) from a geometric distribution with
  parameter **1/2** — so the most recent boundary is never used, the most
  probable age is one boundary, and the mean age is two boundaries (about six
  hours). A draw exceeding `ANCHOR_AGE_CAP` (provisionally **4 boundaries**,
  about twelve hours) or falling outside the candidate set MUST be discarded
  and redrawn; equivalently, the distribution is truncated to the candidate
  set.

- The set of all migration transactions sharing a boundary anchor forms a
  **cohort**. A wallet MAY contribute several migration transactions to the
  same cohort (multiplicity $k \geq 1$), because all denominations are
  canonical and therefore not attributable to a single wallet by their values
  (see [On multiplicity and cohorts](#onmultiplicityandcohorts)).

#### Transfer scheduling

The schedule is constructed in **block deltas**: starting from the height at
which the schedule is committed (lower-bounded so that every part can anchor;
see below), the wallet assigns each part a scheduled broadcast height by
advancing a running height by an independently drawn delay per part, so that a
wallet's broadcasts approximate a Poisson process.

- The wallet MUST first shuffle the quantized parts into a uniformly random
  order, so that the temporal sequence of denominations a wallet emits is not
  a predictable function of its balance (for example, a largest-first
  ordering would let an observer infer migration progress from any part it
  could attribute, and would make the sequence predictable to a targeted
  adversary who knows the balance).

- The delay to each successive migration transaction MUST be drawn from an
  exponential distribution with rate $\lambda = 1 /$ `MEAN_DELAY`, so that the
  expected delay is `MEAN_DELAY` (provisionally **66 blocks**, about 82
  minutes at 75-second block spacing), rounded to a whole number of blocks; any
  draw exceeding `MAX_DELAY` (provisionally **576 blocks**, about twelve
  hours) MUST be discarded and redrawn.

- The schedule MUST place every migration transaction at a scheduled height
  whose candidate anchor set (see
  [Anchor-height bucketing and cohorts](#anchor-heightbucketingandcohorts)) is
  non-empty, so that no transaction can ever lack a valid boundary to anchor
  to and no fallback anchor-selection rule is needed. Concretely, the running
  height from which the delays accumulate MUST start no earlier than one full
  bucket interval past the lowest candidate boundary — the first boundary
  strictly above the NU6.3 activation height and at or after the estimated
  creation height of the funding notes (the last scheduled note-preparation
  transaction plus a small mining margin). Lower-bounding the starting height,
  rather than clamping individual transactions, preserves the drawn
  inter-arrival gaps and hence the schedule's Poisson character.

- All randomness used in scheduling — the shuffle, the delay draws, and the
  anchor-age draws — and in the randomized decomposition of
  [Amount selection, canonical quantization](#amountselectioncanonicalquantization)
  MUST be generated by a cryptographically secure random number generator.

- The wallet MUST propose the complete schedule to the user before any
  transfer is sent, obtaining confirmation of the whole schedule (see
  [Migration entry point and user consent](#migrationentrypointanduserconsent)).

- Each migration transaction takes a canonical anchor drawn from the
  recency-weighted distribution over the candidate anchor set (see
  [Anchor-height bucketing and cohorts](#anchor-heightbucketingandcohorts)).
  Because the version 6 transaction format commits the anchor as authorizing
  data rather than in the signature hash <a id="user-content-fnref-zip-0229-3"></a>
  [2](/zip/318?part=2#user-content-fn-zip-0229), the wallet can attach
  or update a pre-signed transaction's anchor and proof without re-signing.

- Whenever the application is granted background processing time, the wallet
  SHOULD synchronize and construct the proofs of upcoming scheduled
  transactions, drawing each transaction's anchor from the candidate anchor
  set as observed at proving time, but MUST NOT broadcast a migration
  transaction within the same background processing window in which a
  synchronization is performed (see
  [Decoupling synchronization from broadcast](#decouplingsynchronizationfrombroadcast)).

- Spreading a wallet's transfers over time with memoryless inter-transfer
  delays, and drawing each transfer's anchor independently, are the primary
  means by which the wallet's own transfers are kept from being linked to one
  another; distinct per-wallet anchor heights are **not** required, because a
  shared boundary anchor carries no per-wallet information.

#### Pre-signed transaction storage

- Once the schedule is committed, migration transactions SHOULD be pre-signed and
  persisted, reusing the wallet's existing transaction-resubmission storage
  mechanism where one exists.

- Under the version 6 transaction format, the anchor is committed as
  authorizing data rather than by the signature hash <a id="user-content-fnref-zip-0229-4"></a>
  [2](/zip/318?part=2#user-content-fn-zip-0229), so a
  pre-signed transaction's anchor and proof can be updated at (or near)
  broadcast time without re-signing. This is what allows the entire schedule
  to be signed in a single session while each transaction carries a boundary
  anchor drawn from the shared candidate set (see
  [Rationale for anchor selection](#rationaleforanchorselection)).

- If a stored transaction becomes invalid (for example, because its input notes
  were spent outside the migration, or it expired), the wallet MUST detect this
  and prompt the user to re-initiate the affected step (see
  [Error handling](#errorhandling)).

#### Background scheduling

- Background scheduling MUST be treated as best-effort. The operating system
  chooses the exact execution time within the requested window.

- A single background processing window MUST be used either to synchronize
  (updating the anchors and proofs of upcoming transactions) or to broadcast,
  never both (see
  [Decoupling synchronization from broadcast](#decouplingsynchronizationfrombroadcast)).

- If a scheduled window is missed, the wallet MAY fall back to prompting the user
  on the next application open (see
  [Fallback on application open](#fallbackonapplicationopen)).

Platform-specific guidance is given in
[Platform considerations](#platformconsiderations).

#### Decoupling synchronization from broadcast

A background session is defined as a period of time wherein the wallet is
performing computation and network interaction decoupled from any
user interaction with the wallet interface. While a background session
and user interaction with the wallet interface may coincide, the wallet
MUST NOT permit the user's behavior to influence the execution of
the background operations.

- The wallet MUST NOT perform a wallet synchronization in the same background
  session as a migration broadcast, because doing so would let an observer
  correlate the synchronization (which may leak wallet-identifying data) with the broadcast.

- Where a synchronization is needed, it MUST be separated in time from any
  broadcast. In the recommended flow migration transactions produce no
  *Orchard-pool* change, so the required synchronizations are the one that
  witnesses the notes produced by note preparation before the first scheduled
  send, and the routine background synchronizations that allow the proofs of
  upcoming transactions to be constructed (see
  [Transfer scheduling](#transferscheduling)). A migration transaction that
  produces change in the *Orchard pool* (for example, one rebuilt during error
  recovery) requires the wallet to synchronize before that change can be spent;
  the wallet MUST schedule that synchronization decoupled in time from the
  broadcast of the next migration transaction.

How a wallet determines when a synchronization is needed is implementation-defined.

#### Fallback on application open

- On every application launch, the wallet MUST reconcile the scheduled broadcast
  times against the transfers actually completed, and MUST surface any overdue
  transfers. This on-launch reconciliation is the primary catch-up mechanism and
  MUST NOT rely on notification delivery.

- When the user is prompted to send overdue transfers, the wallet SHOULD disclose
  that sending them at application-open time correlates the broadcasts with the
  wallet's sync activity, weakening the privacy of those transfers.

- The wallet MUST NOT send more than one overdue transfer at wallet open.
  While this may delay the migration of user funds, the alternative (sending
  multiple transactions with pool-crossing value within the same session)
  leaks balance.

- When a window is missed and the remaining transfers are rescheduled, the
  wallet SHOULD shift the remaining schedule by the offset, or redraw the
  delays of the remaining transfers.

- A slip of up to approximately two hours in which the background task eventually
  runs SHOULD be treated as normal operation and SHOULD NOT be surfaced as an
  error.

<a id="destination"></a>

### Destination

- The destination of a migration MUST be the user's internal change address in
  the *Ironwood pool*. Migration to the *Sapling pool* MUST NOT be offered or
  recommended as part of this flow.

<a id="network-layer-privacy"></a>

### Network-layer privacy

Before the schedule is committed, the wallet MUST present a network-privacy step.

## Citation relationships

Cites: [ZIP 200](https://zips.tools/zip/200), [ZIP 203](https://zips.tools/zip/203), [ZIP 209](https://zips.tools/zip/209), [ZIP 229](https://zips.tools/zip/229), [ZIP 244](https://zips.tools/zip/244), [ZIP 258](https://zips.tools/zip/258), [ZIP 308](https://zips.tools/zip/308), [ZIP 315](https://zips.tools/zip/315), [ZIP 317](https://zips.tools/zip/317), [ZIP 2006](https://zips.tools/zip/2006)

Cited by: [ZIP 229](https://zips.tools/zip/229), [ZIP 258](https://zips.tools/zip/258), [ZIP 326](https://zips.tools/zip/326)