[DIS] Pocket Node for iOS: a self-custody CKB light client for Apple and Identity/Signer for CCC web apps

另外,据我所知,委员会面对不断发展的 DAO, 目前也在酝酿对自身工作模式的改革,应该不久后会与社区进行同步,相信暨时会对 DAO 的运作带来更多积极作用

3 Likes

Pocket Node for iOS: Milestone 1 completion report

Milestone 1 of the iOS grant (“Shared core, iOS bridge, app skeleton”) is complete and tagged as ios-m1 on main. This post lists what shipped, how it was verified, and what comes next.

Acceptance criteria, as written in the proposal

The iOS app builds, embeds the light client, and completes a testnet query end to end, while the shared core still compiles for Android unchanged.

All three parts are met on real hardware:

  • The iOS app builds from main and runs on an iPhone (iOS 26.5.2).
  • It embeds the same Rust light client the Android app uses, compiled for iOS and exposed to Swift through UniFFI.
  • On the phone it connected to CKB testnet peers and reported tip block 22,424,678 (screenshot 1). Stopping the node now works too (screenshot 2).
  • The shared Kotlin core compiles for Android and iOS, and the Android app on the same commit passed a full testnet regression: faucet receive, send, Nervos DAO deposit and phase 1 withdrawal, address book, backup, sync options, lock, and network switching, with no crash.

What was delivered

Shared Kotlin Multiplatform core. A new shared module compiles for Android, iosArm64 and the iOS simulator and ships to Xcode as the PocketNodeCore framework. Transaction building, molecule encoding, cell selection, the data models, address handling and the app’s preference interfaces now live there, with unchanged package names so the Android app needed no import edits. The module has no Hilt, no Android or JVM types, and no expect/actual declarations; platform pieces are injected behind small interfaces.

CKB Java SDK replaced. The signing path used seven symbols from the Java SDK. They are replaced by multiplatform primitives: BLAKE2b-256 with the CKB personalization, secp256k1 recoverable signing on the ACINQ library (native on iOS), a hex codec, and a bech32m CKB address codec that decodes full, short and deprecated-full formats. Correctness was proven by differential tests against the Java SDK at 10,000 seeded iterations per primitive, by RFC 0021 test vectors, and by replaying a real mainnet transaction through the shared encoder and hash to its on-chain hash. The SDK is gone from every production classpath and a Gradle check keeps it out.

Rust bridge for iOS. The light client crate built for iOS with zero source changes. The JNI layer was split into a platform-neutral bridge_core (lifecycle plus all 20 query, DAO and RPC functions) with thin JNI and UniFFI adapters, so Android and iOS call the same Rust. The 24 JNI entry points are unchanged; the Swift surface has 25 functions and typed errors. Along the way the light client’s own unit tests (95 of 107 were failing on macOS from a test helper bug) were fixed and now run in CI, and a stop deadlock that Android had never exercised was found on the phone and fixed.

SwiftUI app. A native iPhone app with navigation, theme, a Home placeholder and a Node Status screen driving the embedded node, plus an on-device UI test that starts the node, waits for a tip, and stops it. Xcode project generated by xcodegen; iOS CI runs the shared iOS tests, the Rust iOS build and the Xcode build on every relevant pull request.

Android kept green throughout. Kotlin was bumped to 2.3.10 (Xcode 26 requires it), 355 logging calls moved behind an injected logger, the central repository lost its only dependency cycle and 400 lines, and a Room schema export that had been disabled since April works again. Every change went in as a reviewed pull request with the Android build and unit tests passing.

Verification numbers

Check Result
Rust light client unit tests 115 pass
Android app unit tests 837 pass
Shared core tests (Android host / iOS simulator) 150 / 70 pass
Differential crypto tests vs the Java SDK 10,000 iterations per primitive, identical
iOS CI (macOS runner) green on main
Physical device testnet tip reached in 10 s

Fixes found by the regression pass

Testing the merged code also surfaced and fixed a few Android issues that were not on the M1 list: the recovery-phrase screen could be opened without re-authentication on older key storage, the wallet switcher showed mainnet addresses on testnet, sends had no review step, DAO withdrawals paid a flat fee 100 times the estimate, and the transaction detail sheet had no fee row. All are merged.

Known limits at M1

  • iPhone only, as agreed in the discussion thread.
  • Stopping the node from Node Status is final until the app relaunches; restarting in-process needs the same refactor that blocks in-process network switching on Android.
  • Keys, onboarding, send and sync on iOS are Milestone 2 and 3 work; M1 is the skeleton and the shared core.

Next: Milestone 2

Keychain and Secure Enclave key storage, Face ID and Touch ID with PIN fallback, BIP39 generation and import, onboarding, and the Receive screen.

Source: 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 (tag ios-m1).

Note: Full code test has been carried out by the Nervos Dev testing team, and no security issues were found.

4 Likes