Zcash

ZIPs in use

The Zcash Improvement Proposals Umbra Trade follows, and the exact place in the code where each one applies.

ZIPWhat it saysHow Umbra Trade uses itCode
ZIP 32Shielded hierarchical deterministic walletsThe Zcash account and its spending key come from the 24 words through librustzcash's ZIP 32 derivationpackages/zwallet/rust/src/wallet.rs, send.rs
ZIP 317Proportional transfer feeEvery payment pays the standard ZIP 317 fee (FeeRule::standard()), computed by the wallet before it sendssend.rs
ZIP 318 (draft)Migrating funds between poolsOrchard value moves to Ironwood as canonical crossings (below). Umbra Trade also borrows its standard amounts and timing: fundings use only its denominations (n × 10^k ZEC, n ∈ 5), start at random times, keep-ready refills wait an exponential delay, and a broadcast and a sync never share a windowpackages/engine/src/constants.ts, schedule.ts, apps/web/src/constants.ts
ZIP 321Payment request URIsEach send is built as a ZIP 321 transaction requestsend.rs

The standard amounts

ZIP 318's denominations, as Umbra Trade uses them: seven sizes from 0.01 to 1 ZEC. A funding is always exactly one of them, and the leak meter blocks any other amount. Amounts above 1 ZEC are not split; a wallet holds one size.

0.010.020.050.10.20.51 ZEC

The timing rules

RuleValueCode
A funding you asked forstarts at a random moment 20 s to 3 min later (uniform)fundingTime, packages/engine/src/schedule.ts
A keep-ready refillwaits an exponential delay, 90 min on average, between 20 s and 12 h (the first wallet after the switch goes on starts like one you asked for)refillTime, same file; setKeepReady, apps/web/src/features/private-wallets/jobs.ts
A funding due while the app was closedgets a new random start instead of going out when the app opensretimed, same file
After a broadcastno sync for a random 1 to 10 minSEND_QUIET_MIN_MS, apps/web/src/constants.ts

Moving Orchard to Ironwood

A payment spends Ironwood notes only. ZEC still in the old Orchard pool moves across the way ZIP 318 specifies, using librustzcash's own canonical-crossing check:

RuleValueCode
Partsthe Orchard value split into n × 10^k ZEC (n ∈ 5, 0.01 to 10,000 ZEC); each part pays its own fee from one note; under 0.01 ZEC staysmigrationParts, packages/engine/src/migration.ts
Each crossingone Orchard note in, one standard amount out to the account's internal address, at most one Orchard change output, the canonical fee, an anchor on the ZIP 318 grid; anything else is refused unsentpropose with kind: "migrate", packages/zwallet/rust/src/send.rs (is_canonical_crossing)
Order and timingparts shuffled, each an exponential delay after the one before: 66 blocks (82.5 min) on average, at most 576 (12 h)migrationSchedule, same file
Consentnothing is sent until you agree to the whole schedule on Portfolioapps/web/src/features/wallet/orchard-move.tsx
Due while closeda part that came due while the app was closed gets a new random time; none goes out because the app openedmigrationTick, apps/web/src/features/private-wallets/migration.ts
Sync and broadcastnever in the same window: after each part, no sync for a random 1 to 10 minmigrate, apps/web/src/features/wallet/wallet-store.ts

On this page