walletdk: expose the wallet SDK to mobile via gomobile - #801
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a gomobile-safe facade (sdk/walletdk/mobile) over the wallet SDK, enabling Android and iOS hosts to run an embedded darepod wallet in-process. It includes flat translation layers for configuration, lifecycle management (Start/Stop), scalar convenience methods, and JSON-based RPC/streaming interfaces, along with a build script (gen_bindings.sh) and documentation. Feedback on the changes highlights critical race conditions in the Start and Stop lifecycle methods that could lead to leaked daemons or database lock conflicts, as well as a potential script crash in gen_bindings.sh when locating NDK directories under set -euo pipefail.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aa18d6fde4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@claude review this |
|
Claude finished @Roasbeef's task in 2m 8s —— View job Review: walletdk mobile gomobile bindingsI read the full facade ( 🔴 1. The
|
aa18d6f to
ac9c418
Compare
|
Addressed the review feedback and force-pushed (branch rebased onto latest
The host wrappers in lightninglabs/damobile already map the PascalCase response |
|
@claude review this |
|
Claude finished @Roasbeef's task in 2m 20s —— View job Re-review: walletdk mobile bindings (post-fixup)I re-read the whole facade against the force-pushed branch and traced the lifecycle state machine and the subscription path through
✅ Verified fixed1.
2. Negative config ( 3. Doc JSON field names ( 4. 🟡 Still open —
|
ac9c418 to
74c8033
Compare
In this commit, we add sdk/walletdk/mobile, a thin facade that exposes the embedded walletdk wallet to iOS and Android through gomobile bind. gomobile carries only a narrow set of types across the language boundary, so the existing walletdk.Client surface (context.Context, channels, maps, unsigned integers, time.Time, and slices of structs) cannot be bound directly. The facade translates at the edge. RPC verbs take and return JSON bytes, a handful of hot paths return plain scalars, and the one streaming verb hands back a pull-based Subscription rather than a channel or a host-implemented callback. Start is synchronous and singleton-guarded via a CAS; it owns an internal context that Stop cancels, so the boundary never has to express a context, and in-flight work unwinds on shutdown. Every entry point recovers panics into errors, since an unrecovered panic does not cross the gomobile boundary and would otherwise take down the host process. Unlike falafel and lnd-mobile we keep the bytes-out shape but drop the callback interfaces: walletdk.Start returns once gRPC is serving, whereas lnd.Main blocks forever, so a synchronous Start is both possible and simpler. The package builds only under the mobile, walletdkrpc, and swapruntime tags together, matching walletdk's embedded wallet runtime requirement, so default builds are unaffected. gen_bindings.sh drives gomobile bind for the Android .aar and the iOS .xcframework.
In this commit, we cover the mobile facade against a bufconn-embedded daemon: the config JSON decodes onto the right walletdk.Config fields, verbs fail cleanly before Start, Start rejects a malformed config and resets the singleton so a retry can succeed, Stop is idempotent, and an Entry survives a JSON round trip with its optional progress and request unions intact. The suite is tagged like the package (mobile, walletdkrpc, swapruntime) and runs on the host toolchain, so it does not need gomobile.
In this commit, we add mobile, mobile-android, and mobile-ios make targets that drive sdk/walletdk/mobile/gen_bindings.sh. The targets give a stable entry point for building the Android .aar and iOS .xcframework, and are what the bindings CI and the damobile fetch scripts invoke.
In this commit, we document the mobile binding design: the gomobile type restrictions the facade works around, the JSON bytes-out convention, the callback-free lifecycle (synchronous Start, pull-based Subscribe), and how to build the .aar / .xcframework. The sample apps and host wrappers live in the separate lightninglabs/damobile repo, which this guide points to.
In this commit, we add a Mobile Bindings workflow. On pull requests and the merge queue it runs a fast host-tagged compile and the boundary tests, so a change that breaks the facade is caught cheaply. The expensive gomobile builds cross compile the whole embedded daemon for every ABI, so they run only when a mobile-v* tag is pushed, producing the Android .aar and iOS .xcframework as artifacts rather than on every merge.
74c8033 to
3faf8be
Compare
|
Thanks for the thorough re-review. Addressed the open item and the polish
Verified locally: The unit failures in the previous run were a flaky |
|
@claude review this |
|
Claude finished @Roasbeef's task in 2m 27s —— View job Re-review: walletdk mobile bindings (third pass)I re-read the full facade on the current branch and traced the two things the latest fixups touch most: the
✅ Confirmed resolved
🟡 New —
|
This series exposes
sdk/walletdkto iOS and Android throughgomobile bind, so a React Native, Swift, or Kotlin host can drive an embeddeddarepodwallet in-process, with no separate daemon binary and no opensocket.
We already do the hard part in
sdk/walletdk:Startboots the daemon anddials it over a private bufconn gRPC transport. So rather than a
falafel-style protoc plugin, we add a thin hand-written facade,
sdk/walletdk/mobile, that translates at the boundary and respectsgomobile's type restrictions.
The facade is callback-free. gomobile carries only a narrow set of types, so
the rich
walletdk.Clientsurface (context, channels, maps, unsigned ints,time.Time, slices of structs) cannot cross directly. Instead:
Startis synchronous and singleton-guarded. It returns once gRPC isserving, which
walletdk.Startalready guarantees, unlikelnd.Main,which blocks forever and forces lnd-mobile to use a callback.
Subscriptioninstead of achannel or a host callback.
cross the gomobile boundary and would otherwise kill the host process.
The package builds only under
mobile && walletdkrpc && swapruntime, sodefault builds are untouched.
make mobile-android/mobile-iosdrivegen_bindings.sh.What is here
sdk/walletdk/mobile: the facade plus its boundary tests.make mobile-*targets andgen_bindings.sh.docs/walletdk_mobile.md.merge queue, with the heavy
.aar/.xcframeworkbuilds gated tomobile-v*tags so routine merges do not trigger them.What is not here
The sample apps and the idiomatic Kotlin (coroutines /
Flow) and Swift(
async/AsyncThrowingStream) wrappers live inlightninglabs/damobile. Both
were validated end to end against signet: the embedded wallet boots
in-process, connects to the operator mailbox, syncs from Esplora, and runs
on the Android emulator and the iOS simulator.
Closes #713.