Zingo Mobile is a shielded Zcash light-client wallet for Android and iOS, built with React Native and powered by the Zingolib Rust SDK.
App Store: https://apps.apple.com/app/zingo/id1668209531
Google Play: https://play.google.com/store/apps/details?id=org.ZingoLabs.Zingo
If you believe you have discovered a security issue, please contact us at:
Please see the platform specific iOS and Android "quickstart" documentation.
Zingo ships as two parallel apps from this repo:
- Production (
org.ZingoLabs.Zingo) — App Store + Play Production. - Beta (
org.ZingoLabs.Zingo.Beta) — TestFlight External + Play Open Testing.
Both share the same JS bundle and Rust libs; only the native shell differs
(bundle ID, display name, icon with BETA band). Version/build bumps are
scoped per channel via:
yarn release:prod:prep <version> <build>
yarn release:beta:prep <version> <build>Create the tag before building the app: the About screen shows the zingo-mobile descriptor that the app build computes, so an app built before the tag ships naming its commit instead of the tag. See Release order.
Pushing a zingo-<version>-<build> or zingo-beta-<version>-<build> tag
triggers a CI workflow that builds the 4 ABI APKs + a universal APK from
source on the tagged commit and publishes them to a fresh GitHub Release.
Full step-by-step for both stores, signing setup, and the underlying iOS/Android flavor architecture: see docs/release_quickstart.md.
Architecture decision records live in
zingo-adrs, and zingo-mobile's own
records sit under docs/adr/zingo-mobile/ once the submodule is initialised.
The zingo-adrs README explains how to read them, advance the
pointer, and propose a record.
The Rust wallet and the mixnet proxy, with their Kotlin and Swift bindings,
live in zingolabs/zingolib. This
repository pins them as a submodule at zingolib/ (ADR zingo-mobile/0016).
The Android and iOS builds read that checkout. Initialise it before any build.
git submodule update --init zingolib- From the root directory, run:
yarn test
Peak heap per wallet-file path, on a connected Android device or emulator.
yarn bench:memory: measure and compare againstscripts/wallet_memory_baseline.json, non-zero exit on a regressionyarn bench:memory --report: measure onlyyarn bench:memory:accept: record a new baseline
The device tests exercise the Binding Layer through Kotlin and Swift on an
emulator or a simulator. An annotation on each Android test class names its
kind (CONTEXT.md defines the terms).
- An offline device test (
@OfflineDeviceTest) opens a wallet with an empty server URI and reads no chain. - A public-chain test (
@PublicChainTest) reads mainnet or testnet through a public server. A test that needs funds reads a testnet fixture wallet (docs/testnet_fixture_wallets.md).
The android-ubuntu-integration-test-ci workflow runs both kinds on every
pull request, and ios-integration-test runs the XCTest classes of
ios/ZingoTests.
To run the Android tests, boot an emulator and run these commands from the
android directory. Replace x86_64 with the ABI of the emulator.
./gradlew :app:connectedProdDebugAndroidTest \
-PreactNativeArchitectures=x86_64 \
-Pandroid.testInstrumentationRunnerArguments.annotation=org.ZingoLabs.Zingo.OfflineDeviceTest
./gradlew :app:connectedProdDebugAndroidTest \
-PreactNativeArchitectures=x86_64 \
-Pandroid.testInstrumentationRunnerArguments.annotation=org.ZingoLabs.Zingo.PublicChainTest \
-Pandroid.testInstrumentationRunnerArguments.timeout_msec=420000To run the iOS tests, open ios/Zingo.xcworkspace in Xcode and run the
ZingoTests target on a simulator.
Maestro drives the released app from the
outside, asserting on the rendered UI. Flows live in .maestro/ as YAML
(01_new_wallet.yaml, etc.). Runs nightly in CI via
.github/workflows/maestro-nightly.yaml against both Android and iOS;
this is the e2e suite that PR reviewers and releases lean on going
forward.
To run locally:
-
Install the Maestro CLI:
curl -Ls "https://get.maestro.mobile.dev" | bash(puts the binary in~/.maestro/bin) -
Boot an emulator/simulator and install the app you want to test against (debug or release). Maestro talks to whatever device is currently selected by
adb/xcrun simctl. -
From the repo root:
maestro test --exclude-tags=screen-awake .maestro/Or run a single flow:
maestro test .maestro/01_new_wallet.yaml
The flows restore or create their wallets on mainnet, and need network
access. The screen-awake flow runs alone in CI, after a step that
shortens the device's screen-off timeout. New e2e coverage lands as
Maestro flows.
Browse components in isolation with Storybook (on-device via
yarn storybook:ios/storybook:android, web via yarn storybook:web).
The web build powers per-PR visual regression: yarn visual captures and
diffs components and animations against a baseline. See
visual/README.md for the harness, and
.github/CLOUDFLARE.md for the Cloudflare Pages deploy
that publishes the review site.
For notes on known issues and problems, see the trouble-shooting notes.