react-native-turbo-lnd
v0.0.20
Published
C++ TurboModule for lnd! ⚡️
Readme
react-native-turbo-lnd
A pure C++-only TurboModule for lnd.
Easily embed and interact with the Lightning Network client lnd inside an app with a convenient API. This lib uses lnd's falafel bindings in order to run lnd embedded inside an app.
⚡️ Runs lnd embedded inside your app
🕺 Epic C++ TurboModule bindings for interacting with lnd, sharing the same source-code for all platforms
🤯 Convenient and simple API for all lnd gRPC methods and server/bidi streams
🤓 Type-safety and auto-complete for all protobufs, using protobuf-es
📦 Unopinionated core bindings for other protobuf libraries. Zero dependencies
👷♂️ Provide your own lnd binaries, or use our prebuilt ones
Platform support:
✅ Android
✅ iOS
✅ macOS
✅ Windows
✅ Electrobun (Windows, Linux, macOS) [WIP]
🚫 Web
✅ Jest mocks (all gRPC methods not yet mocked)An opinionated API react-native-turbo-lnd using protobuf-es bindings is
provided for lnd's protobufs, giving auto-complete and type-safety for all
protobufs and gRPC methods.
An unopinionated core API react-native-turbo-lnd/core to lnd's falafel
bindings is also available if you want to use another protobuf library.
This API let's you send and receive protobufs as base64-encoded strings,
which you can then encode/decode yourself.
[!NOTE] We currently use an out-of-tree fork of lnd for building the binaries, which can be found here. This is because the official lnd repository does not yet support using falafel bindings with cgo. Once/if the official lnd repository supports building with cgo, we will switch to using the official lnd repository. This fork also has a few minor patches that is being used in Blixt Wallet.
Installation
This lib requires new architecture enabled in your app. It will not work on the old architecture and there are no plans to support it.
- Install the package:
| npm | yarn |
| ------------------------------------ | --------------------------------- |
| npm install react-native-turbo-lnd | yarn add react-native-turbo-lnd |
If you wish to use the protobuf-es bindings:
| npm | yarn |
| -------------------------------- | ----------------------------- |
| npm install @bufbuild/protobuf | yarn add @bufbuild/protobuf |
- Download the lnd binaries automatically using a convenience script from the root of your project:
node node_modules/react-native-turbo-lnd/fetch-lnd.jsBy default the convenience script fetches the Android and iOS binaries into
package-owned paths under node_modules/react-native-turbo-lnd.
You can override that with --targets=..., for example:
node node_modules/react-native-turbo-lnd/fetch-lnd.js --targets=android,ios,macos,macos-dylib,linux,windowsSupported targets are android, ios, macos, macos-dylib, linux, and windows.
Android:
Download the latest liblnd-android.zip from smolcars/react-native-turbo-lnd/releases
containing lnd .so binaries. Place the shared libraries in
<project root>/node_modules/react-native-turbo-lnd/android/src/main/jniLibs.
The structure should look like this:
node_modules/react-native-turbo-lnd/android/src/main/jniLibs
├── arm64-v8a
│ └── liblnd.so
├── armeabi-v7a
│ └── liblnd.so
├── x86
│ └── liblnd.so
└── x86_64
└── liblnd.soThis package now ships a real Android library module, so the package-owned
android/src/main/jniLibs directory is what gets bundled into the APK.
The Android liblnd.h headers are already checked into this repo under
node_modules/react-native-turbo-lnd/cpp/liblnd and are not part of the
downloaded artifact installation step.
CMake will by default look for the files in
../android/src/main/jniLibs, starting from
<project root>/node_modules/react-native-turbo-lnd/cpp.
If you have another structure or wish to customize it, you can pass in
-DLND_JNILIBS_PATH to CMake. For example from your app/build.gradle:
defaultConfig {
// Other configs
externalNativeBuild {
cmake {
arguments "-DLND_JNILIBS_PATH=/your/path/here"
}
}
}iOS/macOS:
Download the latest liblnd-ios.zip or liblnd-macos.zip file from
smolcars/react-native-turbo-lnd/releases
and unzip it. Then place Lndmobile.xcframework in
<project root>/node_modules/react-native-turbo-lnd/{ios|macos}/Lndmobile.xcframework.
Then rerun pod install so CocoaPods picks up the vendored XCFramework
automatically.
If your iOS app target is Objective-C-only and the linker fails with
__swift_FORCE_LOAD_$_swiftCompatibility56, add an empty Swift file to the
app target and choose No if Xcode asks to create a bridging header. Apps
that already contain Swift usually do not need any extra setup.
Windows:
Download or build liblnd.dll.
Place it in the package-owned Windows folder:
<project root>/node_modules/react-native-turbo-lnd/windows/liblnd.dllThe autolinked react-native-turbo-lnd project will search upward from both
the consuming solution and the package's own Windows project for liblnd.dll,
generate an import library from it during the Windows build, link that
generated import library, and stage liblnd.dll for deployment. By default
the generated .def/.lib artifacts are written under the consuming app's
windows/generated-liblnd directory.
If your workspace layout is unusual, you can override the paths explicitly in
MSBuild with LndDllPath. If you already have a known-good import library and
want to use that instead, you can also set LndImportLibPath explicitly. When
LndImportLibPath is set, the build skips import-library generation from
liblnd.dll; if you also want the DLL copied into the app output, keep
LndDllPath set as well.
- Done!
Usage
import { Button, View } from "react-native";
import { DocumentDirectoryPath } from "@dr.pogodin/react-native-fs";
import { start, getInfo } from "react-native-turbo-lnd";
export default function App() {
const onPressStart = async () => {
const lndDir = `${RNFS.DocumentDirectoryPath}/lnd`;
await start(
`--lnddir="${lndDir}" --noseedbackup --nolisten --bitcoin.active --bitcoin.mainnet --bitcoin.node=neutrino --feeurl="https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json" --routing.assumechanvalid --tlsdisableautofill --neutrino.connect=192.168.10.120:19444`
);
}
const onPressGetInfo = async () => {
const info = await getInfo({});
console.log("syncedToChain", info.syncedToChain);
}
return (
<View>
<Button title="start" onPress={onPressStart} />
<Button title="getInfo" onPress={onPressGetInfo} />
</View>
)
}
Building your own lnd binaries
[!NOTE] If you wish to compile your own lnd binaries, you can follow the instructions here. The lnd CGO backend is still a work in progress and subject to change.
Electrobun
If you wish to use the Electrobun backend, wire it up through an app-local Bun entrypoint plus your renderer build config.
On the Bun side, create the shared RPC instance and pass it to your
BrowserWindow. Create an app-local wrapper module around
defineTurboLndElectrobunRPC() so you can add your own requests/messages in
one place:
// src/bun/index.ts
import { BrowserWindow } from "electrobun/bun";
import { defineTurboLndElectrobunRPC } from "react-native-turbo-lnd/electrobun/bun-rpc";
export function defineAppRPC() {
return defineTurboLndElectrobunRPC({
// Add your own RPC here
requests: {
__Ping: async () => ({ ok: true, now: Date.now() }),
},
messages: {
__Log: (payload: unknown) => {
console.log("[electrobun] __Log", payload);
},
},
});
}
const appRpc = defineAppRPC();
new BrowserWindow({
title: "TurboLnd Electrobun App",
url: "views://mainview/index.html",
rpc: appRpc,
});In your bundler, alias react-native-turbo-lnd to the Electrobun view
entrypoint so your app code can import from react-native-turbo-lnd. For
Vite:
// vite.config.ts
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()],
resolve: {
alias: [
{
find: /^react-native-turbo-lnd$/,
replacement: "react-native-turbo-lnd/electrobun/view",
},
{
find: /^react-native-turbo-lnd\/core$/,
replacement: "react-native-turbo-lnd/electrobun/view-core",
},
],
},
});Then inside the view, import LND methods from react-native-turbo-lnd as
usual, and use react-native-turbo-lnd/electrobun/custom-rpc for your
app-defined requests/messages:
import { getInfo, start } from "react-native-turbo-lnd";
import {
invokeElectrobunRequest,
sendElectrobunMessage,
} from "react-native-turbo-lnd/electrobun/custom-rpc";
await start('--lnddir="/path/to/lnd/" --noseedbackup --nolisten');
const info = await getInfo({});
const pong = await invokeElectrobunRequest<{ ok: boolean; now: number }>(
"__Ping"
);
sendElectrobunMessage("__Log", {
syncedToChain: info.syncedToChain,
pong,
});react-native-turbo-lnd defaults Electrobun to the napi backend. You can
override that with TURBOLND_ELECTROBUN_BACKEND=bunffi, but bunffi is still
unstable and experimental.
For desktop runtimes, install the shared library for the current platform:
- Windows: place
liblnd.dllwhere your runtime/addon can load it - Linux: place
liblnd.sowhere your runtime/addon can load it - macOS: place
liblnd.dylibwhere your runtime/addon can load it
The static Apple XCFramework in liblnd-macos.zip is for React Native Apple builds
and cannot be loaded directly by the Electrobun desktop runtimes. Use
liblnd-macos-dylib.zip on macOS instead.
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT
Made with create-react-native-library
