DUCAT Wallet is a non-custodial Expo/React Native wallet for Bitcoin Mutinynet, UNIT Runes, Cashu e-cash, and BTC-backed Ducat vault workflows.
DUCAT Wallet is hard-locked to Mutinynet. It is not a mainnet wallet and must not be used with mainnet funds.
| Area | What the app supports |
|---|---|
| BTC | SegWit receive/send, Taproot-aware flows, fee selection, pending send recovery |
| Turbo BTC | Cashu sat proofs for app-to-app P2PK sends and receives inside the BTC asset |
| UNIT | Bitcoin Runes balance, send, receive, transaction history, and vault repayment |
| Turbo UNIT | Cashu unit proofs for instant UNIT transfers and mint/melt conversion |
| Vaults | Open, borrow, repay, deposit, withdraw, liquidation state, and recovery journals |
| USDC settlement | Hidden developer-gated Sepolia USDC flows for vault payout/repayment testing |
| Passkeys | WebAuthn encrypted seed backup and restore through iCloud Keychain |
| Notifications | Transaction, vault health, and liquidation opportunity alerts |
BTC and UNIT each have an on-chain form and a Turbo Cashu form:
| Asset | On-chain form | Turbo form |
|---|---|---|
| BTC | Mutinynet BTC UTXOs | Cashu sat proofs stored in an account-scoped BTC proof store |
| UNIT | Bitcoin Runes outputs | Cashu unit proofs stored in an account-scoped UNIT proof store |
Turbo BTC is Cashu sat only in this release. Lightning Cashu support is out of
scope.
| Layer | Technology |
|---|---|
| App framework | Expo SDK 54, React Native 0.81, React 19 |
| Language | TypeScript strict mode |
| Navigation | React Navigation 7 stacks and bottom tabs |
| Bitcoin | bitcoinjs-lib v7, BIP32/39/84/86, @bitcoinerlab/secp256k1 |
| UNIT / Runes | Ducat SDK, Ducat runestone tooling, Mutinynet ord data |
| E-cash | @cashu/cashu-ts v4, Cashu onchain/unit, Cashu onchain/sat, NUT-11 P2PK |
| EVM testing | Sepolia USDC, wUNIT, bridge router, and pool wiring |
| State | React Context for session state, Zustand for durable workflow state |
| Security | SecureStore, biometric auth, PBKDF2 PIN hashing, passkey backup |
| Quality | Jest, Maestro, ESLint, TypeScript, Knip, custom release doctors |
The repo keeps UI composition, state orchestration, protocol logic, and tooling separate:
components/ Reusable UI components
screens/ Navigation targets and full-screen flows
hooks/ Presentation logic and state composition
contexts/ Session-scoped providers
stores/ Durable Zustand workflow and recovery state
services/ API clients, wallet logic, signing, Cashu, vault, liquidation
utils/ Pure utilities, formatting, safety checks, error taxonomy
constants/ Network, security, analytics, and app constants
navigation/ Root, stack, and tab navigators
e2e/ Maestro product and live regression flows
docs/ Architecture, recovery, release, and protocol documentation
scripts/ Local validation, release, regression, and maintenance scripts
vendor/ Local Ducat protocol packages consumed through file dependencies
bridge-service/ Server-side bridge reference code and fixtures
evm/ EVM-side bridge and settlement helpers
store/ App Store metadata and screenshots
Important boundaries:
- docs/REPO_BOUNDARIES.md defines ownership and import rules.
- docs/STATE_MANAGEMENT.md documents context/store responsibilities.
- docs/RECOVERY_MATRIX.md maps crash and relaunch recovery behavior.
- services/ERROR_HANDLING.md documents error handling conventions.
- The wallet is non-custodial and derives keys from a BIP39 seed phrase.
- Seed material is stored in iOS Keychain through Expo SecureStore.
- Passkey backup encrypts the mnemonic before iCloud storage.
- PINs are PBKDF2-hashed and protected by lockout.
- Transaction signing is guarded by typed PSBT validation and signing-context checks.
- Cashu proof storage is split by account and unit so Turbo BTC and Turbo UNIT proofs cannot mix.
- Analytics hash addresses, truncate transaction IDs, and suppress sensitive payloads.
Report suspected vulnerabilities privately. See SECURITY.md.
- Node.js 22.x and npm 10+
- Xcode 15+ for iOS development
- EAS CLI for store/TestFlight builds
- Maestro CLI for local end-to-end flows
git clone https://github.com/DUCAT-UNIT/app.git
cd app
npm ci
npm run doctornpm run start
npm run iosThe app is intended to run as a native app or development client. Expo Go is not the production target.
The app ships with public Mutinynet/Sepolia defaults and can run without a local
.env. Copy .env.example only when overriding public endpoints
or supplying optional live-test fixture values.
Core public endpoints:
| Service | Default |
|---|---|
| Esplora | https://mutinynet.com/api |
| Ord API | https://ord-mutinynet.ducatprotocol.com |
| Guardian WebSocket | wss://guardian-mutinynet-1.ducatprotocol.com |
| Vault API | https://validator.ducatprotocol.com/api |
| Cashu mint | https://dev-cashu-mint.ducatprotocol.com |
| Quote service | https://quote.ducatprotocol.com |
| Price service | https://price.ducatprotocol.com |
| Unit bridge API | https://unit-bridge-sepolia-z6mcndbb6q-ue.a.run.app |
The mobile runtime rejects non-Mutinynet EXPO_PUBLIC_APP_NETWORK values in
app.config.ts and utils/networkConfig.ts.
Use the smallest gate that matches the risk of your change:
npm run typecheck
npm run lint -- --quiet
npm test -- --runInBand
npm run verify:quickFor protocol, wallet, auth, Cashu, recovery, or release changes, run the broader gate:
npm run verifynpm run verify runs the local doctor, TypeScript, ESLint, cleanup guardrails,
dead-code detection, Maestro flow validation, user-facing regression manifest
validation, and Jest coverage.
Focused release checks:
npm run release:doctor
npm run release:doctor -- --quicknpm test
npm run test:coverage
npm run e2e:validate
npm run e2eMaestro flows live under e2e/maestro/flows/. Live funded regression flows are
separate from deterministic product flows because they can spend Mutinynet and
Sepolia test funds.
Regression documentation:
- REGRESSION.md describes live regression scope.
- e2e/USER_FACING_REGRESSION.md maps user-facing flows.
- docs/RELEASE_DOCTOR.md explains release gating.
Run the release gate first:
npm run release:doctorThen build and submit with EAS:
eas build --platform ios --profile production --auto-submitProduction releases use the Mutinynet environment, remote iOS credentials, and
App Store Connect submit metadata from eas.json.
- CONTRIBUTING.md - contributor workflow and review expectations
- CODING_STANDARDS.md - code style and app conventions
- SECURITY.md - vulnerability reporting and high-risk areas
- docs/REPO_BOUNDARIES.md - workspace ownership and import rules
- docs/STATE_MANAGEMENT.md - context and store responsibilities
- docs/RECOVERY_MATRIX.md - recovery behavior by workflow
- docs/RELEASE_DOCTOR.md - release gate details
- scripts/README.md - validation and maintenance scripts
MIT. See LICENSE.