Skip to content

Commit 4ae942b

Browse files
Copilotntheile
andauthored
Fix UniFFI library-mode bindgen and add Kotlin bindings (#20)
* Initial plan * Fix UniFFI bindgen error and add Kotlin bindings - Remove #[uniffi::export] from trait impl blocks (causes "no interface LightningNode" error) - Add inherent method implementations for each node struct when uniffi feature is enabled - Keep LightningNode trait for non-uniffi use cases (Rust consumers) - Add cdylib to crate-type for library-mode bindgen - Create bindings/kotlin directory with uniffi-bindgen helper - Add build.sh script to generate Kotlin bindings - Create example Kotlin project demonstrating usage Co-authored-by: ntheile <1273575+ntheile@users.noreply.github.com> * Improve comments for UniFFI inherent impl blocks Address code review feedback by clarifying that inherent impl blocks are required because UniFFI cannot export trait impl blocks. Co-authored-by: ntheile <1273575+ntheile@users.noreply.github.com> * fix android example * add macro impl_lightning_node * fix tests * fix on_invoice_envents for uniffi * update kotlin example with on_invoice_events * update nodejs types * fix cln discrepency * add polymorphic LightningNode trait for uniffi * fix default invoice params * fix async list_offers --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ntheile <1273575+ntheile@users.noreply.github.com> Co-authored-by: nicktee <ntheile@gmail.com>
1 parent 0f36a41 commit 4ae942b

46 files changed

Lines changed: 2692 additions & 225 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[workspace]
2+
resolver = "2"
23
members = [
34
"crates/lni",
45
"bindings/lni_nodejs",
6+
"bindings/kotlin",
57
]

bindings/kotlin/.gitignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Generated Kotlin bindings
2+
src/main/kotlin/uniffi/
3+
4+
# Gradle
5+
.gradle/
6+
build/
7+
!gradle/wrapper/gradle-wrapper.jar
8+
9+
# Kotlin
10+
*.class
11+
*.jar
12+
*.war
13+
*.nar
14+
*.ear
15+
*.zip
16+
*.tar.gz
17+
*.rar
18+
19+
# IDE
20+
.idea/
21+
*.iml
22+
*.ipr
23+
*.iws
24+
.project
25+
.classpath
26+
.settings/
27+
bin/
28+
29+
# Build outputs
30+
target/
31+
out/
32+
33+
# Local configuration
34+
local.properties
35+
36+
# Native libraries (generated)
37+
*.so
38+
*.dylib
39+
*.dll

bindings/kotlin/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "lni-kotlin-bindgen"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[[bin]]
8+
name = "uniffi-bindgen"
9+
path = "uniffi-bindgen.rs"
10+
11+
[dependencies]
12+
uniffi = { version = "0.29.0", features = ["cli"] }

bindings/kotlin/README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# LNI Kotlin Bindings
2+
3+
Kotlin bindings for the Lightning Node Interface (LNI) library, generated using UniFFI.
4+
5+
## Overview
6+
7+
This package provides Kotlin bindings for LNI, allowing you to interact with various Lightning Network node implementations from Kotlin/Android applications.
8+
9+
## Supported Nodes
10+
11+
- **BlinkNode** - Blink Lightning service
12+
- **StrikeNode** - Strike Lightning service
13+
- **PhoenixdNode** - Phoenixd daemon
14+
- **LndNode** - LND (Lightning Network Daemon)
15+
- **ClnNode** - Core Lightning (CLN)
16+
- **NwcNode** - Nostr Wallet Connect
17+
- **SpeedNode** - Speed Lightning service
18+
19+
## Building
20+
21+
### Prerequisites
22+
23+
- Rust toolchain (stable)
24+
- Cargo
25+
26+
### Generate Kotlin bindings
27+
28+
```bash
29+
./build.sh --release
30+
```
31+
32+
This will:
33+
1. Build the LNI library with UniFFI support
34+
2. Generate Kotlin bindings in `src/main/kotlin/uniffi/lni/`
35+
36+
## Usage
37+
38+
### Basic Example
39+
40+
```kotlin
41+
import uniffi.lni.*
42+
43+
// Create a Strike node
44+
val config = StrikeConfig(
45+
apiKey = "your-api-key",
46+
baseUrl = "https://api.strike.me/v1"
47+
)
48+
val node = StrikeNode(config)
49+
50+
// Get node info
51+
val info = node.getInfo()
52+
println("Node alias: ${info.alias}")
53+
54+
// Create an invoice
55+
val invoiceParams = CreateInvoiceParams(
56+
invoiceType = InvoiceType.BOLT11,
57+
amountMsats = 21000L, // 21 sats
58+
description = "Test invoice"
59+
)
60+
val transaction = node.createInvoice(invoiceParams)
61+
println("Invoice: ${transaction.invoice}")
62+
63+
// Don't forget to clean up
64+
node.close()
65+
```
66+
67+
### Using NWC (Nostr Wallet Connect)
68+
69+
```kotlin
70+
import uniffi.lni.*
71+
72+
val config = NwcConfig(
73+
nwcUri = "nostr+walletconnect://pubkey?relay=wss://relay.example.com&secret=..."
74+
)
75+
val node = NwcNode(config)
76+
77+
val info = node.getInfo()
78+
println("Connected to: ${info.alias}")
79+
80+
node.close()
81+
```
82+
83+
## Integration with Android
84+
85+
See the `example/` directory for a complete Android example project.
86+
87+
### Adding to your Android project
88+
89+
1. Copy the generated `lni.kt` file to your project
90+
2. Add the native library (`.so` file) to your `jniLibs` directory
91+
3. Add required dependencies:
92+
93+
```gradle
94+
dependencies {
95+
implementation "net.java.dev.jna:jna:5.13.0@aar"
96+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"
97+
}
98+
```
99+
100+
## License
101+
102+
Same license as the main LNI project.

bindings/kotlin/build.sh

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/bin/bash
2+
3+
# Build script for generating Kotlin bindings using UniFFI
4+
#
5+
# This script:
6+
# 1. Builds the lni library with uniffi feature
7+
# 2. Uses uniffi-bindgen to generate Kotlin bindings from the shared library
8+
# 3. Optionally builds for Android targets
9+
#
10+
# Usage: ./build.sh [--release] [--android]
11+
# ./build.sh --release --android # Build for Android in release mode
12+
13+
set -e
14+
15+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16+
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
17+
EXAMPLE_DIR="$SCRIPT_DIR/example"
18+
19+
# Parse arguments
20+
BUILD_TYPE="debug"
21+
BUILD_ANDROID=false
22+
23+
for arg in "$@"; do
24+
case $arg in
25+
--release)
26+
BUILD_TYPE="release"
27+
;;
28+
--android)
29+
BUILD_ANDROID=true
30+
;;
31+
esac
32+
done
33+
34+
echo "Building LNI library with UniFFI feature ($BUILD_TYPE)..."
35+
36+
cd "$ROOT_DIR"
37+
38+
# Build for host platform (needed for uniffi-bindgen)
39+
if [ "$BUILD_TYPE" == "release" ]; then
40+
cargo build --package lni --features uniffi --release
41+
LIB_PATH="$ROOT_DIR/target/release"
42+
else
43+
cargo build --package lni --features uniffi
44+
LIB_PATH="$ROOT_DIR/target/debug"
45+
fi
46+
47+
# Build for Android targets if requested
48+
if [ "$BUILD_ANDROID" = true ]; then
49+
echo ""
50+
echo "Building for Android targets..."
51+
52+
# Android target configurations: (rust_target, jni_dir)
53+
ANDROID_TARGETS=(
54+
"aarch64-linux-android:arm64-v8a"
55+
"armv7-linux-androideabi:armeabi-v7a"
56+
"x86_64-linux-android:x86_64"
57+
"i686-linux-android:x86"
58+
)
59+
60+
# Create jniLibs directories
61+
JNILIBS_DIR="$EXAMPLE_DIR/app/src/main/jniLibs"
62+
63+
for target_pair in "${ANDROID_TARGETS[@]}"; do
64+
RUST_TARGET="${target_pair%%:*}"
65+
JNI_DIR="${target_pair##*:}"
66+
67+
echo " Building for $RUST_TARGET..."
68+
69+
if [ "$BUILD_TYPE" == "release" ]; then
70+
cargo build --package lni --features uniffi --release --target "$RUST_TARGET"
71+
ANDROID_LIB_PATH="$ROOT_DIR/target/$RUST_TARGET/release/liblni.so"
72+
else
73+
cargo build --package lni --features uniffi --target "$RUST_TARGET"
74+
ANDROID_LIB_PATH="$ROOT_DIR/target/$RUST_TARGET/debug/liblni.so"
75+
fi
76+
77+
# Copy to jniLibs
78+
mkdir -p "$JNILIBS_DIR/$JNI_DIR"
79+
cp "$ANDROID_LIB_PATH" "$JNILIBS_DIR/$JNI_DIR/"
80+
echo " Copied to $JNILIBS_DIR/$JNI_DIR/liblni.so"
81+
done
82+
83+
echo "Android builds complete!"
84+
fi
85+
86+
# Find the shared library (Linux: .so, macOS: .dylib)
87+
if [ -f "$LIB_PATH/liblni.so" ]; then
88+
LIB_FILE="$LIB_PATH/liblni.so"
89+
elif [ -f "$LIB_PATH/liblni.dylib" ]; then
90+
LIB_FILE="$LIB_PATH/liblni.dylib"
91+
else
92+
echo "Error: Could not find liblni.so or liblni.dylib in $LIB_PATH"
93+
exit 1
94+
fi
95+
96+
echo "Found library: $LIB_FILE"
97+
98+
# Build the uniffi-bindgen tool
99+
echo "Building uniffi-bindgen..."
100+
cargo build --package lni-kotlin-bindgen
101+
102+
# Create output directory
103+
OUTPUT_DIR="$SCRIPT_DIR/src/main/kotlin"
104+
mkdir -p "$OUTPUT_DIR"
105+
106+
echo "Generating Kotlin bindings..."
107+
cargo run --package lni-kotlin-bindgen -- generate --library "$LIB_FILE" --language kotlin --out-dir "$OUTPUT_DIR"
108+
109+
echo ""
110+
echo "Kotlin bindings generated successfully in: $OUTPUT_DIR"
111+
echo ""
112+
echo "Generated files:"
113+
ls -la "$OUTPUT_DIR"

bindings/kotlin/example/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# LNI Kotlin Example
2+
3+
This is an example Kotlin/Android project demonstrating how to use the LNI Kotlin bindings.
4+
5+
## Project Structure
6+
7+
```
8+
example/
9+
├── app/
10+
│ ├── src/main/
11+
│ │ ├── kotlin/com/lni/example/
12+
│ │ │ └── Main.kt # Example usage
13+
│ │ └── jniLibs/ # Native libraries go here
14+
│ │ ├── arm64-v8a/liblni.so
15+
│ │ ├── armeabi-v7a/liblni.so
16+
│ │ ├── x86/liblni.so
17+
│ │ └── x86_64/liblni.so
18+
│ └── build.gradle.kts
19+
├── settings.gradle.kts
20+
└── build.gradle.kts
21+
```
22+
23+
## Setup
24+
25+
1. First, build the LNI Kotlin bindings:
26+
```bash
27+
cd ../
28+
./build.sh --release
29+
```
30+
31+
2. Build native libraries for your target architectures (e.g., for Android):
32+
```bash
33+
# Example for arm64-v8a
34+
cargo build --package lni --features uniffi --release --target aarch64-linux-android
35+
# Example Mac Apple Silicon
36+
cargo build --package lni --features uniffi --release --target aarch64-linux-android
37+
cp ../../target/aarch64-linux-android/release/liblni.so app/src/main/jniLibs/arm64-v8a/
38+
```
39+
40+
3. Build the example:
41+
```bash
42+
./gradlew build
43+
```
44+
45+
## Running
46+
47+
For JVM-based execution (testing on desktop):
48+
```bash
49+
./gradlew run
50+
```
51+
52+
For Android:
53+
1. `cd .. && ./build.sh --release --android 2>&1`
54+
2. Import the project into Android Studio and Open `lni/bindings/kotlin/example`
55+
3. File → Sync Project with Gradle Files
56+
4. Build → Clean Project
57+
5. Build and run on an emulator or device
58+
59+
## Usage Examples
60+
61+
See `app/src/main/kotlin/com/lni/example/Main.kt` for examples of:
62+
- Creating nodes (Strike, Blink, NWC, etc.)
63+
- Getting node info
64+
- Creating invoices
65+
- Paying invoices
66+
- Listing transactions

0 commit comments

Comments
 (0)