Zingo PC is a shielded Zcash light-client wallet for desktop (Windows, macOS, Linux), built with Electron and powered by the Zingolib Rust SDK.
App Store: https://apps.apple.com/app/zingo-pc/id6763584326
Pre-built binaries for each release are available on the Releases page.
| Platform | Format |
|---|---|
| Windows | .msi installer, .zip portable |
| macOS | .dmg |
| macOS (App Store) | App Store link |
| macOS (TestFlight) | Public beta |
| Linux | .deb, .AppImage (x64, and ARM64 for a Raspberry Pi 4/5 or other ARM64 machine) |
| Linux (Flatpak) | .flatpak (x64) |
Trying the beta: the TestFlight build is where what is still being tested reaches first, before any of it goes to the App Store. It needs a Mac and the TestFlight app; the link above joins the public group, no invitation needed. Feedback is welcome from there.
Windows users: if Windows blocks the app on launch, see Windows blocks Zingo PC from opening in Troubleshooting. Our Windows builds are code signed, but a recently issued certificate has to accumulate reputation before Windows stops flagging it.
Zingo PC is written in Electron/JavaScript and can be built from source. It will also automatically compile the Rust SDK.
Using a version manager avoids polluting your system with multiple Node.js installs.
# Example on Arch Linux
paru -S nvm
nvm install 22.18.0
nvm use 22.18.0git clone https://github.com/zingolabs/zingo-pc.git
cd zingo-pc
yarn setup
yarn build
yarn startyarn setup installs with the frozen lockfile and then runs the dependency
scripts the allowlist in package.json permits (lavamoat.allowScripts), plus
our own postinstall. A plain yarn add or yarn remove re-links
node_modules without them, which leaves Electron's binary, keytar's build
and the patches behind: run yarn allow-scripts again afterwards.
yarn build also builds nym-proxy, the mixnet transport, whose source lives
in zingolib. Nothing to set up for it: the build fetches zingolib into
.zingolib-src/ at the exact revision native/Cargo.lock pins, the same
revision the Rust SDK is compiled from, so the proxy and the wallet core are
always the same zingolib. CI runs these same steps.
yarn mixnet rebuilds only nym-proxy, which is all that is needed after the
pinned revision changes.
The renderer runs under SES
lockdown: the language intrinsics are frozen before any dependency runs. In
development that is public/lockdown.js, loaded from index.html. In a
production build LavaMoat also wraps
every npm package in its own Compartment, with the globals its policy grants
(lavamoat/webpack/policy.json, generated; policy-override.json, by hand).
After a dependency change, regenerate the policy and commit it:
LAVAMOAT_GENERATE_POLICY=1 yarn script:buildyarn start serves the development bundle, which has lockdown but no
Compartments. yarn start:prod builds the production bundle, serves it on the
port the unpackaged Electron loads and launches the app against it.
A package that reaches a global the policy does not grant fails at runtime,
typically as TypeError: … is not an object or … is not a function inside
that package. To find every such gap in one session, run
yarn start:prod --debug-policy, use the app, and run LM_printPolicyDebug() in
the DevTools console: it prints the entries policy-override.json still
needs. Never ship a debug-runtime build.
To build the proxy from a zingolib working copy instead — when developing
nym-proxy itself — point ZINGOLIB_PATH at it. That opts out of the pinning,
so it warns, and the dist:* scripts refuse it outright.
yarn dist:linux # Linux x64 (AppImage + deb)
yarn dist:linux-arm64 # Linux ARM64 (AppImage + deb), built on an ARM64 machine
yarn dist:win-x64 # Windows x64
yarn dist:win-arm64 # Windows ARM64
yarn dist:mac-x64 # macOS x64 (DMG)
yarn dist:mac-arm64 # macOS ARM64 (DMG)
yarn dist:mac-mas # macOS universal (Mac App Store)Binaries are output to the dist/ directory.
The version and build number live in several files (package.json,
src/version.ts, bin/printversion.{sh,ps1}, plus the AppStream metainfo for
Flatpak). To bump them all in one shot:
yarn release:prep <X.Y.Z> <BUILD>
# e.g.
yarn release:prep 2.0.15 142Wallet
- Light client — no full chain download, syncs from a
lightwalletdserver - Follows the chain while it is open — sync stays at the tip and scans each block as it is mined, rather than running to the end and waiting to be asked again, so a payment shows up when it lands
- Looks ten transparent addresses past the last one used, so funds sent to an address you skipped are found rather than left behind the first gap
- Multi-wallet support — manage several wallets in the same install
- Multi-network — Mainnet, Testnet and Regtest; the network is chosen when the wallet is created and fixed from then on, so several wallets can sit on different networks side by side
- Create from a fresh BIP-39 seed, restore from seed, or import from a Unified Full Viewing Key (read-only mode)
- Wallet seed phrase / UFVK backup viewer
- Per-wallet performance profiles
- Rescan from the Wallet menu, with a nonlinear scanning map on the dashboard showing sync progress
- Every other wallet kept close to the tip too: they are synced in the background, one after another, when the app starts and every 15 minutes, while the app stays in use — see Syncing every wallet
- A birthday below Sapling activation, which never synced, is raised to activation on restore or on opening the wallet, and the app says so once
- A wallet whose file cannot be found stays in the list: the open error says where the file is looked for and, when the wallet was last opened from elsewhere, where that was and whether the file is still there
Transactions
- Full Zcash address support — Unified, Sapling, Transparent and TEX
- Shielded transactions by default (Ironwood / Sapling)
- Encrypted memos
- One-click shielding of the transparent balance
- Multi-send — several recipients in one transaction
- Any amount can be typed in USD instead of ZEC — in Send, in a payment request and in a swap; what is sent, requested or swapped is always ZEC
- Payment requests — a
zcash:link and QR for an amount, a memo and an optional title, from Receive - Scan a payment QR in Send — from an image (file, drag and drop, or a pasted screenshot) or the camera; decoded on the device, never stored or sent
zcash:URI scheme handler (ZIP-321 payment requests, including several recipients)- Transaction history, and a separate Messages view for transfers carrying memos; both searchable by address, contact name, memo or transaction id
- Receive lists every address of each pool, numbered ("2 of 5"), with a search across both pools once there is more than one
- Financial Insight — amounts sent, number of sends and memo bytes, charted per destination address
Servers
- Three selection modes per wallet, shown at all times in the bar above every screen, beside the wallet selector:
- Auto — picks a server on every launch and stays automatic: Zingo's recommended Zaino server while it answers, then the fastest of the registry's best few, then the built-in list, and the network's default when none answers
- List — you choose from the published servers
- Custom — your own
lightwalletdURI
- Live server list from the community registry (hosh.zec.rocks), filtered to online clearnet servers and ranked by 30-day uptime; the built-in list is the fallback whenever the registry is unreachable
- Health indicator next to the active server — green while it answers, amber after an occasional failure, red after three in a row or when it answers but cannot serve this wallet. Clicking it offers the next step for the current mode: switch server (Auto), pick from the list (List), or open the wallet settings (Custom)
- A server that stops being published, or that we retire, moves the wallet back to Auto rather than leaving it on a dead URI
- "Try Again" on the wallet-open error screen, to retry without changing any settings
- The server list is searchable by address, with the recommended server pinned on top
- Server info names the Zingo PC build (
zpc_<version>-<build>_<commit>) beside zingolib's
Privacy
- Nym mixnet transport for sending a payment and for the price lookup, with a status indicator in the sidebar and an on/off control under Settings → Nym Mixnet. Syncing is not covered; what rides it and what does not is set out in The Nym mixnet
- ZEC price is fetched over the mixnet only; while the transport is not ready the USD figures read
USD --rather than falling back to clearnet - Sending fails closed: a payment goes out over the mixnet, or not at all, unless the mixnet has been switched off deliberately. Shielding the transparent balance is a payment by another name and waits the same way
Swaps
- Swap ZEC to and from assets on other chains through SwapKit (NEAR Intents, Flashnet and other providers)
- Routes compared by cost against the market rate, with the slippage tolerance chosen and the slippage realised
- Swap status and history, with links to each chain's explorer and refund tracking
- When no route is offered, each provider's own reason is given (a minimum to reach, a provider that cannot price the pair right now), and a route already quoted is kept while it is still valid
- A provider that refuses to start a swap it has just quoted is set aside, with its reason, until the swap asked for changes, rather than offered again every refresh
- Deposit QR and payment link for paying an inbound swap from another wallet
- The address field reads a QR code (image, screenshot or camera), for the chain on screen only, and checks each chain's format: an uppercase bech32 address from a QR is accepted, and a NEAR name that could be another chain's address asks for confirmation
- A Maya deposit is paid in one shielded transaction, with its memo in a 0 ZEC note to Maya's memo address, when Maya takes it; otherwise, and for THORChain, the memo rides in an OP_RETURN after a deshield
- A deposit whose first transaction went out and second did not is finished by Try Again, without deshielding a second time
- When the swap service is busy (it rate-limits the app's key), quotes pause with a countdown and resume by themselves
- Swap traffic goes over clearnet, not the mixnet: see docs/swap-privacy.md
Ironwood migration
- Guided migration of Orchard funds to Ironwood, with progress on the dashboard
- Immediate migration for the straightforward case, and a scheduled, batched migration that spreads the transfer over time when privacy calls for it
Address book
- Save contacts per network (Mainnet / Testnet / Regtest) — the list filters by the active wallet's network
- "Show contacts from all networks" toggle to see everything at once
- Contacts on other chains too, with Swap To / Swap From — the chains that can be swapped with ZEC; an address on any other chain is refused by name
- Search contacts by any part of a name or an address, in the book and in the picker that fills an address field
- Scan a QR into the address field, for any asset, with the chain chosen when the code's payment link names it
- Save a contact from Send, Swap or a transaction's detail without leaving the screen
- Show any contact's address as a QR code, to scan it from another device
- A contact saved from a ZNS alias keeps the name and follows it (see Zcash Names below)
Zcash Names (ZNS)
- Type
alice.zcashoralice.zecin the recipient field — auto-resolves to the unified address via the public ZNS indexer - Network-aware (
Mainnet/Testnet), with a one-click link to the public ZNS explorer page - Save the alias as a contact: it keeps the name and the address it resolves to. Each send to the
contact asks the name again; if the owner moved it, the confirmation shows the change and the
payment goes to the new address, which the contact then keeps. A name nobody holds any more stops
the send. The Address Book shows the name next to the contact (
ZNS: alice.zec)
Block explorers
- User-selectable per-network explorer for transactions and addresses (Zcashexplorer, ZecBlock, Zexplorer, or a custom URL)
Security
- Hardened Electron renderer (sandboxed, CSP, no node integration)
- Hardened JavaScript: SES lockdown freezes the language intrinsics in the renderer and in the main process, every npm package runs in its own LavaMoat Compartment with only the globals its policy grants, and dependency install scripts run only when allowlisted — see Hardened JavaScript
- Optional device authentication for opening the wallet and signing sends:
- macOS: Touch ID
- Windows: Windows Hello
- Linux (
.deb): polkit
- Encrypted credential storage (Keychain / Credential Manager / libsecret) for the auth setting itself,
falling back to
settings.jsonwhere no secret service is available (Linux AppImage)
Data portability
- DMG ↔ MAS first-launch migration assistant (macOS) — imports wallets, address book, settings and swap history from a previous DMG install
- deb/AppImage → Flatpak first-launch migration (Linux) — the same, without copying the wallet files, which the Flatpak reads where they are
- Manual "Import data from another installation" from the Settings menu (MAS / Flatpak), with per-item Replace / Merge / Skip choices
- Swap history moves with the rest. Each wallet's records are encrypted with a key derived from that wallet, so they travel with it — to another installation, another machine, or out of a backup. Records left by a version that encrypted them per installation are converted the next time their wallet is opened; until then they can only be read where they were written, and an import that cannot read them says so and leaves them there
- "Change wallets folder location" from the Settings menu (MAS)
Zingo PC bundles nym-proxy and starts it with the app. What the mixnet covers
is the two surfaces zingolib judged highest-linkage (its ADR 0011): sending a
payment, and fetching the price. Syncing is not one of them.
Goes through the mixnet
- Broadcasting a payment. The transaction is transmitted through the tunnel, so the indexer it is submitted to does not learn the IP it came from. This is what the mixnet is for: a broadcast is handed to the same indexer that has been serving your wallet, and without the tunnel that indexer sees a person and a transaction at the same address
- Shielding the transparent balance, which is a transmission like any other: the Shield button waits for the transport exactly as Send and Swap do
- The transmissions of the Ironwood migration, which are payments by another name and follow the same rule
- The ZEC price. Mixnet-only: no setting sends it over clearnet, and while
the transport is not ready the USD figures read
USD --rather than falling back
Goes over clearnet
- Syncing. Compact blocks, nullifiers, transparent-address queries, full transaction fetches, the mempool — the whole scan talks to your server directly. zingolib's ADR 0023 decided that the top of the chain should ride the mixnet and records that its implementation is deferred, so the server you sync from does see your IP. What the mixnet keeps from it is the IP behind a payment. The same holds for the other wallets synced in the background, each against its own server
- The server health check behind the indicator next to the active server, which asks each server for its latest block over an ordinary connection
- Swap traffic: quotes, the commit, tracking, the token catalog with its logos, and Maya's deposit settings read from mayanode. The provider therefore sees the IP the request came from, beside the addresses a quote has to carry. The Swap screen says so, and docs/swap-privacy.md has the reasoning and what it would take to change
- Resolving a
name.zcashalias, which asks the Zcash Name Service. A contact saved from a name asks it again on every send to that contact, so the service sees which name this IP is about to pay - The server list, fetched from
hosh.zec.rockswhen you open the server picker - Anything handed to your browser: a block explorer, or "Open in wallet" on a deposit
- The Nym client's own hostname lookups, which go to Quad9 and Cloudflare over DNS-over-TLS and DNS-over-HTTPS (see the antivirus entry under Troubleshooting)
If you want the rest covered too, that is a job for a system-level VPN or NymVPN; the wallet does not embed one.
Sending fails closed. A payment goes out through the mixnet or not at all. While the transport is bootstrapping, unattached or lost, sending refuses rather than falling back — losing the transport is not consent to clearnet. That covers shielding and a swap deposit too: the screens hold their buttons back and say what they are waiting for, instead of letting the wallet refuse afterwards.
Turning it on and off. The sidebar carries the current state, and Settings → Nym Mixnet turns the transport off and on. Switching it off also puts that session's payments on clearnet, which is the one way a payment travels that way: by being asked for. The choice is deliberately not saved, so the next launch starts on the mixnet again.
The wallet you have open syncs itself and follows the chain while it is open. The others used to move only when you opened them, so a wallet you had not looked at for a while started days behind. Zingo PC now syncs them too, in the background, while you keep using the one in front of you.
When it runs
- By itself, ten seconds after the app has opened its wallet, and again 15 minutes after each run ends. The time is counted from the end, so a long run is never overlapped by the next one
- When you ask, from Wallet → Sync all Wallets (
Ctrl+Y), after a confirmation that says what it will do - Settings → Background Sync (
Ctrl+B) turns the automatic runs off, and counts down to the next one while they are on. Turned off, a run only starts from the Wallet menu
What a run does
- Takes every wallet except the one open on screen, one after another: Mainnet first, then Testnet, then Regtest. Each syncs from its own server — the one you chose for it, or for an Auto wallet the fastest of the published ones
- A thin line under the wallet bar, on every screen, says how many wallets are done and which one is being synced; Details opens the list of every wallet with its state
- From that list you can skip the wallet being synced, or cancel the whole run. Either way what has been scanned is kept
- A wallet that cannot be synced is passed over with the reason and the server it failed on, and the run carries on with the next. The same goes to the log
- An automatic run that ends with nothing to report puts its line away by itself. One where a wallet failed leaves it, so you see what happened
What it costs
- Sending and shielding take longer while a run is going: the scan and the proofs share the processor. They are not held back, only slower
- A run you start from the menu keeps the computer from sleeping until it ends. An automatic one does not: it comes round every 15 minutes, and keeping a laptop awake that often is not something a setting left on should do
- A wallet is never held open twice. Opening on screen the wallet a run is syncing makes the run let go of it first, and the wallet open on screen is never taken by a run
Q: An older version of Zingo PC will not open my wallet any more
A: Opening a wallet with a newer version can write it in a newer format, and that is one-way: the older build refuses a file whose layout it does not know. Stay on the version you upgraded to, or restore the wallet from its seed phrase in the older one — which is what the seed is for.
Q: After updating on Linux, a wallet is missing or will not open ("No such file or directory")
A: Since 2.0.21, Zingo PC keeps wallet files on Linux in ~/.local/share/.zcash/ (or
$XDG_DATA_HOME/.zcash/). Older versions kept them in ~/.zcash/, and a wallet created there was
not moved over. Testnet and regtest wallets are in the testnet3/ and regtest/ subfolders of
either. The file is not lost.
From 2.0.27 (201), Zingo PC copies it to the new folder by itself the first time it opens that wallet, and leaves the original where it was. On 2.0.21 to 2.0.27 (200), copy it by hand:
ls ~/.zcash/
mkdir -p ~/.local/share/.zcash
cp ~/.zcash/zingo-wallet-4.dat ~/.local/share/.zcash/Use the name of your file, and copy rather than move, so the original stays as a backup. Copy only
your Zingo wallet files: ~/.zcash/ is also zcashd's folder (wallet.dat, blocks/, chainstate/).
- The wallet is still in the list: after copying, select it again or press "Try Again". The error it shows says where the wallet was last opened from.
- The wallet is gone from the list: older versions removed a wallet whose file they could not find. After copying, add it back with "Restore Wallet from an existent DAT file", using the file name. Its alias and server need setting again; nothing in the wallet itself is lost.
Q: Clicking a zcash: payment link doesn't open Zingo PC (Linux AppImage)
A: The AppImage must be launched at least once from its current location before the OS registers it as the handler for zcash: links. After the first launch, cold-start links work automatically. If you move the AppImage to a new path, launch it once from the new location to re-register it.
Q: The camera does not open when scanning a payment QR
A: Scanning from an image always works; the camera needs the operating system's permission.
- macOS: the first attempt asks. If it was refused, allow it in System Settings → Privacy & Security → Camera.
- Windows: allow it in Settings → Privacy & security → Camera, including "Let desktop apps access your camera".
- Linux (Flatpak): the sandbox grants device access at install; reinstall the Flatpak if it was denied.
If another app holds the camera, the dialog says so. There is no camera on the machine? Use "Choose image", drag an image in, or paste a screenshot.
Q: "Require device authentication" is greyed out on Linux
A: Device authentication on Linux relies on polkit and a policy file that must be installed at the system level. This is only supported by the .deb package, which installs the policy automatically via its post-install script.
If you are running the AppImage, device authentication is not available and the option will remain disabled. Use the .deb package instead if you need this feature.
If you installed the .deb package and the option is still greyed out, verify the policy file is in place:
ls /usr/share/polkit-1/actions/co.zingo.pc.policyIf the file is missing, reinstall the package or copy it manually:
sudo cp /opt/Zingo\ PC/resources/co.zingo.pc.policy /usr/share/polkit-1/actions/
sudo chmod 644 /usr/share/polkit-1/actions/co.zingo.pc.policyQ: The app security setting is not being saved securely on Linux (falls back to a plain file)
A: Zingo PC stores the "Require device authentication" setting in the OS credential store via the Secret Service API (libsecret). This requires a secrets daemon to be running — typically GNOME Keyring or KDE Wallet.
If neither is available (e.g. a minimal desktop environment or a headless system), the setting falls back to a plain configuration file, which offers no tamper protection.
To fix this, install and start a compatible secrets daemon:
# Debian / Ubuntu / Arch (GNOME Keyring)
sudo apt install gnome-keyring # Debian/Ubuntu
paru -S gnome-keyring # Arch
# or KDE Wallet (if using a KDE-based desktop)
sudo apt install kwalletmanagerAfter installing, log out and back in so the daemon starts with your session.
Q: The app shows a blank blue screen and never loads (Linux — Ubuntu 22.04+, Debian 11+, Linux Mint)
A: Ubuntu 22.04 and later restrict unprivileged user namespaces at the kernel level, which breaks Chromium's built-in process sandbox that Electron depends on.
In order of preference:
-
Flatpak (recommended): Flatpak runs the app inside its own bubblewrap sandbox, so it does not depend on Chromium's namespace-based sandbox at all. Install the
.flatpakfrom the Releases page:flatpak install Zingo.PC-<version>.flatpak
-
.debpackage: The post-install script sets thechrome-sandboxbinary as SUID root (the same technique used by the official Google Chrome.deb), which restores Chromium's sandbox without relying on user namespaces. If you installed the.deband still see the issue, try reinstalling. -
AppImage: The AppImage detects the restriction automatically and disables the Chromium sandbox when needed (a warning is shown). On Ubuntu 24.04 or systems where AppArmor blocks user namespaces and the automatic detection does not catch it, you can launch the AppImage manually with
--no-sandbox:./Zingo.PC-<version>.AppImage --no-sandbox
⚠️ Note:--no-sandboxdisables Chromium's process isolation. For a wallet this is a real security concern — prefer the Flatpak or the.debif either is available on your system.
Q: My antivirus warns about dns.quad9.net or cloudflare-dns.com every time I open Zingo PC
A: Expected, and it comes from Mixnet Mode. Zingo PC bundles the nym-proxy binary, which starts with the app. So that its own lookups cannot be intercepted or redirected by whatever DNS your network hands out, the Nym client resolves the hostnames it needs (its API and gateways) through a fixed group of encrypted resolvers instead of the system one: Quad9 and Cloudflare over DNS-over-TLS (port 853) and DNS-over-HTTPS (port 443). This happens once per launch, as the mixnet goes from "Connecting" to "Ready" — which is why the warning is tied to opening the wallet.
Antivirus products that inspect HTTPS traffic cannot decrypt those connections, so they report that the site "may not be displayed correctly". Only hostname lookups travel over them; no wallet data is involved. To confirm, open the Nym Mixnet panel in the sidebar and press "Disable" — the connections stop for that session. Note the choice is deliberately not saved: the mixnet re-enables on the next launch, and so does the warning.
The fix is to allowlist those two hosts in your antivirus. Do not turn off Mixnet Mode just to silence it — that is what hides your IP from the indexer when you send.
Unrelated to this warning: always download releases from the official Releases page and check the digital signature. That, not an antivirus popup, is how you confirm your build is genuine.
Q: Windows blocks Zingo PC from opening ("Smart App Control" or "Windows protected your PC")
A: Expected on recent releases. Windows weighs reputation, not just whether a file is signed, and a signing certificate starts with no history — so early releases can be flagged exactly like unsigned ones. It clears as installs accumulate.
Before working around the warning, confirm the file is ours: right-click it → Properties → Digital Signatures. There should be a valid signature with a timestamp. And download only from the Releases page — a warning on a file from anywhere else is a different problem.
Then:
- SmartScreen ("Windows protected your PC"): More info → Run anyway.
- Smart App Control (clean installs of Windows 11 22H2+): no per-app exception exists. It can only be disabled entirely, and cannot be re-enabled without reinstalling Windows — we do not recommend it. Use the Microsoft Store build instead once it is published; Store packages are trusted by SAC from the first install.