Milestone 3 Completion Report
Project: Pocket Node: Mobile CKB Light Client Wallet for Android
Repository: GitHub - RaheemJnr/pocket-node: A native Android CKB (Nervos) wallet that runs an embedded light client directly on the device via JNI — full sovereignty, no remote servers. · GitHub
Milestone: M3 — Multi-Wallet & Sync Optimization
Releases: v1.5.0
Deliverables Summary
All accepted deliverables for M3 have been completed:
| # |
Deliverable |
Status |
| 1 |
Multi-wallet data model, Room schema (walletId FKs), migrations v2→v5 |
Done |
| 2 |
Wallet CRUD — create, import (mnemonic/raw key), switch, delete |
Done |
| 3 |
HD sub-account derivation from parent mnemonics |
Done |
| 4 |
Wallet-scoped data isolation (transactions, balance cache, DAO cells, sync mode) |
Done |
| 5 |
Key storage redesign — ESP → Room encrypted with Android Keystore AES-256-GCM |
Done |
| 6 |
Mandatory PIN with PIN-encrypted KeyBackupManager recovery path |
Done |
| 7 |
Sync strategies — ALL_WALLETS / ACTIVE_ONLY / BALANCED; Paging 3 transaction list |
Done |
| 8 |
Background sync foreground service with notification updates |
Done |
| 9 |
In-app auto-update (GitHub Releases + DownloadManager) |
Done |
| 10 |
CSV transaction export with UTF-8 BOM for Excel compatibility |
Done |
| 11 |
End-to-end testing, multi-wallet edge-case guards, Review fixes |
Done |
| 12 |
Release: v1.5.0 |
Done |
Feature 1: Multi-Wallet Management
Users can now create, import, switch between, and delete multiple wallets independently, each with its own address, transaction history, balance, and sync state.
What was built:
- Wallet CRUD in
WalletRepository — createWallet, importWallet (mnemonic), importRawKey, createSubAccount, switchActiveWallet, renameWallet, deleteWallet, all keyed by a UUID walletId
- Wallet Manager screen grouping parent wallets with their sub-accounts,account selector bottom sheet, per-wallet settings screen with seed reveal behind PIN
- Wallet-scoped prefs — sync mode, custom block height, last-synced block, sync-completed flag all keyed by
(walletId, network)
- Room migrations v2→v3, v3→v4 adding the
wallets table and walletId columns to transactions, balance_cache, dao_cells; idempotent WalletMigrationHelper promoting existing single-wallet users to the multi-wallet schema
- Color-coded
WalletAvatar with WCAG AA contrast-aware initials
- Guards — can’t delete the active wallet, can’t delete a parent with sub-accounts, can’t import the same mnemonic/raw key twice, can’t rename to a duplicate name, can’t delete the last wallet
deleteWallet atomicity — Room row + caches removed inside a withTransaction block; key material destroyed only after commit
Issues: M3 Multi-Wallet PRs: #76, #80
Feature 2: HD Sub-Account Derivation
Parent mnemonic wallets can now spawn sub-accounts with their own keys and addresses, without exposing or duplicating the seed.
What was built:
createSubAccount(parentWalletId, name) derives m/44'/309'/<n>'/0/0 where n = max(existingSubIndexes) + 1 (gap-resistant after sub deletions)
- Sub-accounts store their own derived private key — no need to re-derive from parent on every sign
- Parent wallet’s mnemonic is the only place the seed lives; sub-accounts inherit via derivation path
- UI: sub-accounts nested under their parent in Wallet Manager, own entry in account selector sheet
- Backup reminder suppressed for sub-accounts (parent holds the seed)
Issues: M3 Sub-Accounts PR: #80
Feature 3: Key Storage Redesign (ESP → Room)
Private keys and mnemonics moved off EncryptedSharedPreferences and into Room, encrypted with an Android Keystore AES-256-GCM key.
What was built:
- New
key_material table (migration v4→v5) holding encryptedPrivateKey, encryptedMnemonic, iv, walletType, mnemonicBackedUp
KeystoreEncryptionManager — AES-256-GCM with hardware-backed Keystore key generation, round-trip verification
KeyStoreMigrationHelper — idempotent one-time migration reading from ESP and writing to Room, with round-trip verification before marking complete
- ESP fallback retained in
KeyManager for one release cycle (read-only) so corrupted Room state can recover
deleteEspFilesIfSafe() — only runs after migration completes
KeyBackupManager — PIN-encrypted secondary backup on disk, written alongside every Room key update, used as a recovery path if Keystore eviction corrupts the AES key
AuthManager is the single source of truth for session PIN; KeyManager reads it via injection; session PIN cleared on app backgrounding
Issues: M3 Key Storage Redesign (Phase 1 + 2) PR: #80
Feature 4: Mandatory PIN & Security Hardening
PIN is now required whenever a wallet exists, with a dedicated onboarding screen explaining why in layman terms.
What was built:
InitialPinSetupScreen — standalone composable with three internal phases (INTRO → SETUP → CONFIRM), explains that the PIN locks the wallet and unlocks an on-device encrypted recovery-phrase backup
- Startup gate in
MainActivity — users upgrading from v1.4.x are routed through the PIN flow once
destinationAfterWalletReady() helper in NavGraph — every path that reaches Main is gated on pinManager.hasPin()
- PIN removal refused while any wallet exists; dialog explains the constraint up front instead of surfacing it as a post-verify snackbar
PinViewModel propagates PIN to AuthManager.setSessionPin on both CONFIRM and VERIFY so KeyBackupManager backups are always written
SecurityChecklistScreen + SecuritySettingsViewModel expose PIN/biometric/backup state
RecoveryScreen — Keystore-corruption recovery flow using PIN-encrypted backup
Issues: M3 Mandatory PIN, Security Checklist PR: #80
Feature 5: Sync Strategies & Background Sync
Users can choose how to balance freshness across multiple wallets, and sync continues while the app is backgrounded.
What was built:
SyncStrategy enum — ALL_WALLETS (up to MAX_CONCURRENT_WALLET_SCRIPTS = 3), ACTIVE_ONLY, BALANCED (active real-time, others every 15 min)
registerAllWalletScripts — registers every tracked wallet’s lock script with the light client; logs dropped wallets above the cap for support diagnostics
SyncProgressTracker — rolling-window ETA + percentage with reset() on wallet switch to avoid cross-wallet sample contamination
SyncForegroundService — START_STICKY foreground service with notification updates showing current sync block/tip
SyncNotificationManager — notification channel, permission flow, auto-dismiss when synced
- Per-wallet sync mode (
NEW_WALLET, RECENT, FULL_HISTORY, CUSTOM) defaults: newly created wallets start in NEW_WALLET so they don’t walk history; imported wallets use the user-selected mode
- Paging 3 wired into
ActivityScreen for infinite-scroll transaction list
- Post-send rescan captures sender wallet before the 5 s delay so switching wallets mid-flight doesn’t re-register the wrong script
Issues: M3 Sync Optimization, Background Sync PR: #80
Feature 6: In-App Auto-Update
Pocket Node checks GitHub Releases on launch and offers a one-tap install of new versions, Telegram-style.
What was built:
UpdateRepository — polls api.github.com/repos/.../releases/latest, compares versionCode, filters for the APK asset
UpdateDownloader — Android DownloadManager download with progress, FileProvider-backed install intent (REQUEST_INSTALL_PACKAGES permission)
UpdateDialog composable — modal with “What’s new” from release notes, download progress, install action
- Wired into
HomeViewModel — checks on wallet screen resume, respects 24 h backoff between checks
- Tested via
UpdateRepositoryTest covering version comparison, APK asset resolution, and no-update scenarios
Issues: M3 In-App Update PR: #80
Feature 7: CSV Transaction Export
Users can export a wallet’s transaction history as CSV, ready to open in Excel/Google Sheets.
What was built:
TransactionExporter — emits CSV with columns for tx hash, direction, amount (CKB), fee, block, timestamp, status, confirmations, DAO type
ActivityScreen export flow — Storage Access Framework CreateDocument contract so users pick the destination
- UTF-8 BOM prepended so Excel on Windows renders non-ASCII wallet names/memos correctly
pendingCsvContent cleared on every picker result (even cancellation) so wallet data doesn’t leak across export sessions
Issues: M3 CSV Export PR: #80
Testing
15 new test files were added covering the full M3 feature surface:
| Test File |
Coverage |
WalletRepositoryTest |
Wallet CRUD, active-delete refusal, duplicate import rejection |
WalletDaoTest |
Room wallets table: insert, deactivate-all, activate, sub-account queries |
WalletEntityTest |
Entity round-trip, equality, sub-account relations |
WalletMigrationHelperTest |
Idempotent single→multi wallet backfill |
KeyManagerMultiWalletTest |
Per-wallet key store, storeKeysForWallet, deleteWalletKeys |
KeyStoreMigrationHelperTest |
ESP→Room encryption, round-trip verification, migration-complete flag |
KeystoreEncryptionManagerTest |
AES-256-GCM encrypt/decrypt, wrong-IV failure, Keystore key rotation |
KeyBackupManagerTest |
PIN-encrypted backup write/read, recovery path |
WalletPreferencesMultiWalletTest |
Wallet-scoped preference keys per network |
MigrationTest |
Room migration chain 1→2→3→4→5 schema correctness |
BalanceCacheDaoTest / BalanceCacheEntityTest |
Per-(walletId, network) balance cache |
TransactionDaoWalletTest |
Wallet-scoped transaction queries and deletion |
SyncProgressTrackerTest |
Rolling-window ETA, reset semantics |
RecoveryViewModelTest |
Keystore-corruption recovery flow |
UpdateRepositoryTest |
GitHub Releases poll, version comparison, APK asset filter |
TransactionExporterTest |
CSV column formatting, DAO-type labelling |
PinManagerTest / AuthManagerSessionPinTest |
PIN hashing, session PIN lifecycle |
Releases
| Version |
Highlights |
| v1.5.0 |
Multi-wallet, HD sub-accounts, key storage redesign (ESP→Room, Keystore AES-256-GCM), mandatory PIN, sync strategies, background sync foreground service, in-app auto-update, CSV export, Paging 3 transaction list, 15+ new test files |
All releases include signed APKs attached as assets.
What’s Next: M4 — Address Book, Polish & Launch
Work on Milestone 4 will add:
- Address book / contacts for frequent recipients
- Play Store listing preparation, screenshots, store copy(almost done, I just need to open a company account and setup an organization for google)
- User-facing documentation and onboarding polish
- Any bug fixes discovered in v1.5.0 field testing (to ship as v1.6.0)
Latest Release: v1.5.0 — M3: Multi-Wallet & Key Storage Redesign