Skip to content
 
 

Repository files navigation

eCash.com

eCash.com Wallet

A native, self-custodial mobile wallet for eCash.


A native mobile wallet for eCash — the Layer Two Labs Bitcoin hardfork that activates Drivechain (BIP300/301) and airdrops eCash 1:1 to BTC holders. One Swift + SwiftUI codebase ships as a native SwiftUI app on iOS and native Jetpack Compose on Android via Skip. All key material, signing, and consensus logic is handled by BDK (bdk-swift / bdk-android).

Multi-wallet and multi-network from day one. Bundled networks: Bitcoin mainnet (0'), L2L Signet (1'), and the eCash dry-run chain (drynet2, unit ECX); further eCash / L2L networks slot in as NetworkRegistry entries.

Contributing

We're not accepting outside code contributions right now. The codebase is under heavy active development and changing quickly, and we'd like it in a more stable place before opening it up to pull requests.

Feature ideas are very welcome, though — open an issue describing what you'd like to see and we'll take it under consideration. Bug reports are appreciated too.

Stack

Layer Choice
Language / UI Swift 6 · SwiftUI → Compose (Skip)
Wallet engine BDK 2.3.x (bdk-swift on iOS, bdk-android on Android)
Secure storage SkipKeychain (iOS Keychain / Android Keystore) — mnemonics only
Local storage BDK-owned SQLite (chain data) + JSON wallet-list metadata (no SkipSQL)
Min OS iOS 26+ · Android 9+ (API 28)

Project layout

ECashWalletMobile/             ← the Skip Fuse app (native Swift): UI, view models, state
  Sources/ECashWalletMobile/     App/ · DesignSystem/ · Screens/ · Components/ · Resources/
Packages/WalletService/        ← the BDK seam, a SEPARATE transpiled (Skip Lite) package
  Sources/WalletService/         WalletEngine, BDKWalletEngineFactory, NetworkRegistry,
                                 WalletManager, KeyStore, WalletStore, Descriptors, Models…
Darwin/                        ← iOS app target
Android/                       ← generated Compose output + Kotlin glue

The app is Fuse (native Swift compiled for Android); WalletService is Lite (transpiled to Kotlin) so it can call bdk-android directly. This split is the one architectural subtlety — see CLAUDE.md §5.

Prerequisites

  • macOS with Xcode (Swift 6 toolchain, iOS Simulator).
  • Android Studio + Android SDK/NDK, with an emulator created (Device Manager) and running before you launch the Android app.
  • Skip CLI: brew install skiptools/skip/skip, then verify the toolchain with skip checkup.

Build & run

Warning

Building from source isn't recommended yet. The wallet is under heavy active development — APIs, storage layout, and screens change frequently, and it targets test networks by default. If you build anyway, treat it as a preview: don't put real funds in a wallet built from an in-development checkout. (Bitcoin mainnet is selectable but the app is pre-release.)

# Both platforms at once (iOS Simulator + running Android emulator):
skip app launch

# iOS: open the workspace in Xcode and run the "ECashWalletMobile App" target.
open Project.xcworkspace

# Android only (quick): build the debug APK and install to the running emulator:
skip export --debug
adb install -r .build/skip-export/ECashWalletMobile-debug.apk

iOS logs appear in the Xcode console; Android logs in Android Studio's Logcat or adb logcat.

Signing for a physical iOS device

Simulator and Android builds need no signing setup. To run on a real iPhone, supply your own Apple Developer Team ID — it's deliberately not committed:

cp Darwin/DeveloperSettings.xcconfig.example Darwin/DeveloperSettings.xcconfig
# edit the file and set DEVELOPMENT_TEAM = <your team id>   (Xcode → Settings → Accounts)

That file is gitignored; the project's xcconfig includes it optionally, so signing then works in Xcode, xcodebuild, and fastlane. With a device connected + trusted, you can build/install/launch from the command line:

scripts/run-ios-device.sh          # Debug (default)
scripts/run-ios-device.sh Release  # Release

Testing

# Fast: host tests for the app view models + Thunder crypto (Swift Testing, on the Mac).
swift test

# The wallet engine package — transpiled JUnit on the JVM (Robolectric), so both platforms in one run:
swift test --package-path Packages/WalletService

# Verify the Android build actually transpiles + compiles (the real Android gate):
skip export --debug

# Real-BDK integration on a device runtime:
ANDROID_SERIAL=emulator-5554 swift test          # Android instrumented
WALLETSERVICE_LIVE=1 swift test --filter testLiveSignetSync   # opt-in live L2L Signet

swift build only checks Apple + transpilation; skip export --debug is the real Android check. No change to WalletService or a view model merges without tests in the same PR.

Security model

Your keys stay on your device, and the app is built to keep them exposed as little as possible.

  • Keys never leave the device. The recovery phrase (and only the phrase) is stored in the OS secure store — iOS Keychain (WhenUnlockedThisDeviceOnly, no iCloud sync) / Android Keystore-backed encrypted storage — keyed per wallet. Everything else (xpub descriptors, labels, the transaction cache) is public data.
  • BDK owns all cryptography for the Bitcoin/eCash wallet. Key derivation, signing, PSBT building, and coin selection are handled by the Bitcoin Dev Kit — no hand-rolled crypto. (The one exception is the in-development Thunder sidechain engine — a non-BDK chain, not yet user-facing — which uses swift-crypto + BLAKE3 with derivation and serialization pinned to published test vectors. See the acknowledgements table.)
  • Watch-only + sign-on-demand. Day-to-day the wallet runs watch-only: balance, address derivation, syncing, and even building a transaction use only the public descriptors — the secret store is never read. Your phrase is loaded for exactly one purpose, at one moment: to sign a transaction you've confirmed. It's pulled into a transient in-memory signer, used, and dropped — so the private key's lifetime in memory is a single signing operation.
  • Nothing secret on disk, nothing secret in logs. Only public data is persisted. Errors are typed and scrubbed before they reach the UI or any log — a signing failure says "signing failed," never the key (enforced by an automated no-leak test).
  • Device-auth gates. Optional biometric/passcode lock on launch and on returning to the foreground (with a configurable grace window so a quick trip to another app doesn't re-prompt), plus an independent auth gate on the confirm-send step. On a device with no biometric/passcode enrolled the gate passes through rather than locking you out.
  • Guarded backup. Revealing the phrase is behind an explicit gate + device auth, and you confirm a few words before it's marked backed up. Screenshots aren't blocked — capturing your own recovery phrase is your call (the app advises against it) — though the app-switcher snapshot stays obscured.
  • Spendable balance (0-conf policy). Only confirmed coins + your own unconfirmed change are treated as spendable. Coins you received that are still unconfirmed (0-conf) are shown separately as pending and are kept out of coin selection until they confirm — because an unconfirmed incoming payment can still be double-spent or RBF-replaced, which would orphan anything you tried to send on top of it. This mirrors Bitcoin Core's trusted/untrusted rule (BDK gives us the confirmed / trustedPending / untrustedPending split; the send path also marks untrusted outpoints unspendable). A configurable confirmation threshold — and potentially a per-network one (e.g. stricter on mainnet than on testnets) — is a planned option.
  • Clean removal. Removing a wallet purges its phrase from the secure store plus all of its on-device data.

The decision records behind this live in docs/key-storage.md and docs/key-derivation.md; the non-negotiable rules are CLAUDE.md §2 (Golden Rules) and §7 (Security model).

Docs

  • CLAUDE.md — architecture bible (the what and why; wins on conflicts).
  • PLAN.md — full build plan + tracked checklist.
  • DESIGN.md — visual spec (tokens, type, components, voice).
  • docs/release.md — build / sign / ship to App Store + Google Play.
  • docs/ — decision records: key storage & derivation, wallet/network model, accounts & labels, backends & endpoints, CoinNews, and more.

Open source & acknowledgements

eCash.com Wallet stands on these projects. The same list is shown in-app under Settings → About → Open-source licenses, sourced from a single array (OpenSourceLicense.all in Sources/ECashWalletMobile/App/OpenSourceLicense.swift) — add or edit a credit there and both the app screen and this table should be kept in sync.

Project Use License
Skip Swift→Kotlin cross-platform toolchain + frameworks MPL-2.0
Bitcoin Dev Kit (bdk-swift / bdk-android) Wallet engine Apache-2.0 / MIT
swift-crypto ed25519 signing (Thunder sidechain) Apache-2.0
SwiftBlake3 BLAKE3 hashing (Thunder addresses) ISC (bundled BLAKE3 C: CC0-1.0 / Apache-2.0)
SkipKeychain Secure mnemonic storage LGPL-3.0
swift-qrcode-generator Receive QR codes MIT
SkipQRCode Send QR scanning (Android camera) LGPL-3.0
JetBrains Mono Mono / numeric typeface OFL-1.1
Space Grotesk Display typeface OFL-1.1
Material Symbols Icon set (.symbolset) Apache-2.0

Release note: bundling the full license texts / copyright notices (required by MIT/Apache/OFL) is still TODO — the in-app screen currently links out. See PLAN.md Milestone F.

License

Copyright (C) 2026 LayerTwo Labs and contributors.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. See LICENSE.txt for the full text (SPDX: GPL-2.0-or-later).

About

eChash.com Wallet for iOS and Android

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages