lightening_wallet 0.5.6
lightening_wallet: ^0.5.6 copied to clipboard
High-performance Lightning wallet for Flutter using Rust FFI with LDK-node. Supports Bitcoin on-chain and Lightning Network payments.
Flutter Lightning Wallet (Rust FFI) #
A high-performance Lightning wallet library for Flutter, built with Rust and using dart:ffi for native bindings. This library provides Bitcoin and Lightning Network functionality through a unified Dart API.
Features #
- High Performance: All wallet logic runs in native Rust code
- Bitcoin Wallet: BIP39/BIP32 HD wallet with native address derivation
- Lightning Network: LDK-node integration for Lightning payments
- UTXO Management: Native UTXO tracking with caching
- Transaction Building: Coin selection and transaction signing
- Payment History: SQLite-based payment database
- Event Streaming: Real-time wallet events
- Cross-platform: Supports Android, iOS, macOS, Linux, and Windows
Architecture #
lightening_wallet/
├── rust/ # Rust core library
│ ├── src/
│ │ ├── lib.rs # C FFI bindings
│ │ ├── coordinator.rs # Main orchestrator
│ │ ├── wallet/ # Bitcoin wallet logic
│ │ ├── ldk/ # LDK-node integration
│ │ ├── storage/ # SQLite & caching
│ │ └── events.rs # Event system
│ └── Cargo.toml
├── lib/ # Dart API
│ ├── lightening_wallet.dart # Main export
│ └── src/
│ ├── bindings.dart # FFI bindings
│ ├── lightning_wallet.dart # High-level API
│ └── models.dart # Data models
├── android/ # Android plugin config
├── ios/ # iOS plugin config & headers
├── macos/ # macOS plugin config & headers
├── linux/ # Linux plugin config (CMake)
├── windows/ # Windows plugin config (CMake)
└── scripts/ # Build scripts
Installation #
Prerequisites #
- Flutter 3.10+
- Rust 1.70+ with
cargo - Android NDK (if building for Android)
- Xcode (if building for iOS/macOS)
cargo-ndkfor Android builds:cargo install cargo-ndkzigandcargo-zigbuildfor cross-compiling Linux/Windows from macOS:brew install zig cargo install cargo-zigbuild
Add to your project #
Add to your pubspec.yaml:
dependencies:
lightening_wallet:
path: /path/to/lightening_wallet
Or if published to pub.dev:
dependencies:
lightening_wallet: ^0.1.42
Build the native library #
Before using the plugin, you need to build the Rust library for your target platforms.
Android
# Using the build script (recommended)
./scripts/build-android.sh
# Or manually with cargo-ndk
cd rust
cargo ndk -t arm64-v8a -t armeabi-v7a -t x86_64 -t x86 \
-o ../android/src/main/jniLibs build --release
Requirements:
- Android NDK installed (set
ANDROID_NDK_HOMEenvironment variable) cargo-ndkinstalled:cargo install cargo-ndk- Rust Android targets:
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android
iOS
# Using the build script (recommended)
./scripts/build-ios.sh
This will:
- Build for iOS device (aarch64-apple-ios)
- Build for iOS simulators (x86_64-apple-ios, aarch64-apple-ios-sim)
- Create a universal XCFramework
Requirements:
- Xcode with command line tools
- Rust iOS targets:
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
macOS
./scripts/build-macos.sh
This builds a universal static library (arm64 + x86_64) at macos/liblightening_wallet_macos.a.
Requirements:
- Xcode with command line tools
- Rust macOS targets:
rustup target add aarch64-apple-darwin x86_64-apple-darwin
Linux
./scripts/build-linux.sh
This builds linux/liblightening_wallet.so. When cross-compiling from macOS, uses cargo-zigbuild.
Requirements:
- Rust Linux target:
rustup target add x86_64-unknown-linux-gnu - For cross-compilation from macOS:
zigandcargo-zigbuild
Windows
./scripts/build-windows.sh
This builds windows/lightening_wallet.dll. When cross-compiling from macOS, uses cargo-zigbuild.
Requirements:
- Rust Windows target:
rustup target add x86_64-pc-windows-gnu - For cross-compilation from macOS:
zigandcargo-zigbuild
Usage #
Initialize the library #
import 'package:lightening_wallet/lightening_wallet.dart';
void main() {
// Initialize the native library (required before any other calls)
LightningWallet.initialize();
runApp(MyApp());
}
Generate a new wallet #
// Generate a new BIP39 mnemonic
final result = LightningWallet.generateMnemonic();
if (result.success) {
final mnemonic = result.data!;
print('Mnemonic: $mnemonic');
}
Initialize wallet #
final initResult = LightningWallet.initializeWallet(
userId: 'user123',
mnemonic: mnemonic,
network: BitcoinNetwork.testnet,
dbPath: '/path/to/wallet/data',
);
if (initResult.success) {
print('Wallet initialized!');
} else {
print('Error: ${initResult.error}');
}
Get balance #
final balanceResult = LightningWallet.getBalance('user123');
if (balanceResult.success) {
final balance = balanceResult.data!;
print('On-chain confirmed: ${balance.onchainConfirmed} sats');
print('Lightning balance: ${balance.lightningBalance} sats');
print('Total: ${balance.total} sats');
}
Sync wallet #
final syncResult = LightningWallet.sync('user123');
if (syncResult.success) {
print('Wallet synced!');
}
Get receiving address #
final addressResult = LightningWallet.getReceivingAddress('user123');
if (addressResult.success) {
print('Receive to: ${addressResult.data}');
}
List payment history #
final paymentsResult = LightningWallet.listPayments(
'user123',
limit: 10,
offset: 0,
);
if (paymentsResult.success) {
for (final payment in paymentsResult.data!) {
print('${payment.paymentType}: ${payment.amountSats} sats');
}
}
Poll for events #
final eventsResult = LightningWallet.getEvents('user123');
if (eventsResult.success) {
for (final event in eventsResult.data!) {
switch (event.eventType) {
case 'BalanceUpdated':
print('Balance updated!');
break;
case 'PaymentReceived':
print('Payment received!');
break;
case 'SyncCompleted':
print('Sync completed!');
break;
}
}
}
Disconnect wallet #
LightningWallet.disconnect('user123');
API Reference #
Dart API (LightningWallet) #
All methods are static and return a WalletResponse<T> wrapper with success, data, and error fields.
Wallet Lifecycle
static void initialize()
Initialize the native library bindings. Must be called before any other methods.
LightningWallet.initialize();
static WalletResponse<String> generateMnemonic()
Generate a new 24-word BIP39 mnemonic phrase.
Returns: Space-separated string of 24 BIP39 words.
static WalletResponse<void> initializeWallet({...})
Initialize a wallet instance (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId |
String |
Yes | Unique identifier for this wallet instance |
mnemonic |
String |
Yes | 24-word BIP39 mnemonic phrase |
network |
BitcoinNetwork |
Yes | bitcoin, testnet, or regtest |
dbPath |
String |
Yes | Path to store wallet data |
esploraUrl |
String? |
No | Custom Esplora server URL |
static WalletResponse<void> initializeWalletAsync({...})
Initialize a wallet instance (non-blocking). Use getInitStatus() to poll for completion.
Parameters: Same as initializeWallet().
static WalletResponse<InitStatus> getInitStatus(String userId)
Get the current initialization status for async initialization.
Returns: InitStatus with status (not_started, pending, initializing, completed, failed), progress, and error.
static WalletResponse<void> clearInitStatus(String userId)
Clear the initialization status (for retry after failure).
static WalletResponse<void> disconnect(String userId)
Disconnect and cleanup the wallet. Stops the Lightning node and releases resources.
Balance and Sync
static WalletResponse<WalletBalance> getBalance(String userId)
Get the current wallet balance.
Returns: WalletBalance with:
onchain- On-chain balance in satoshislightning- Lightning channel balance in satoshistotal- Sum of both balances
static WalletResponse<void> sync(String userId)
Sync the wallet with the blockchain (blocking).
static WalletResponse<String> syncAsync(String userId)
Sync the wallet (non-blocking). Returns operation ID.
static WalletResponse<void> restartNode(String userId)
Restart the Lightning node to reconnect peers. Useful after opening new channels.
Addresses
static WalletResponse<String> getReceivingAddress(String userId)
Generate a fresh on-chain receiving address (BIP84 native SegWit).
Returns: A bech32 Bitcoin address.
static WalletResponse<String> getNodeId(String userId)
Get the Lightning node's public key.
Returns: 33-byte hex-encoded public key.
Payment History
static WalletResponse<List<Payment>> listPayments(String userId, {int? limit, int? offset})
List payment history from database.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
int? |
No | Maximum payments to return (0 = all) |
offset |
int? |
No | Number of payments to skip |
Returns: List of Payment objects.
static WalletResponse<List<Payment>> getOnchainTransactions(String userId)
Get on-chain transaction history by querying Esplora directly.
static WalletResponse<String> getOnchainTransactionsAsync(String userId)
Get on-chain transactions (non-blocking). Returns operation ID.
Events
static WalletResponse<List<WalletEvent>> getEvents(String userId)
Drain pending wallet events from the event queue. Events are removed after being returned.
Returns: List of WalletEvent with eventType, data, and timestamp.
Event Types:
BalanceUpdated- Balance changedPaymentReceived- Incoming payment completedPaymentSent- Outgoing payment completedPaymentFailed- Payment failedChannelOpened- New channel openedChannelClosed- Channel closedSyncCompleted- Blockchain sync completed
Peer Management
static WalletResponse<void> connectPeer(String userId, {required String nodeId, required String address, required int port})
Connect to a Lightning Network peer (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
nodeId |
String |
Yes | 33-byte hex-encoded public key |
address |
String |
Yes | IP address or hostname |
port |
int |
Yes | TCP port (typically 9735) |
static WalletResponse<String> connectPeerAsync(String userId, {required String nodeId, required String address, required int port})
Connect to a peer (non-blocking). Returns operation ID.
static WalletResponse<void> disconnectPeer(String userId, String nodeId)
Disconnect from a Lightning Network peer.
static WalletResponse<List<Peer>> listPeers(String userId)
List all connected peers.
Returns: List of Peer with nodeId, address, port, and isConnected.
Channel Management
static WalletResponse<String> openChannel(String userId, {...})
Open a new Lightning channel (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
counterpartyNodeId |
String |
Yes | Peer's 33-byte hex public key |
channelValueSats |
int |
Yes | Total channel capacity in sats |
pushMsat |
int |
No | Amount to push to peer (default: 0) |
peerAddress |
String? |
No | Peer address if not connected |
peerPort |
int? |
No | Peer port if not connected |
Returns: Hex-encoded channel ID.
static WalletResponse<String> openChannelAsync(String userId, {...})
Open a channel (non-blocking). Returns operation ID. Same parameters as openChannel().
static WalletResponse<void> closeChannel(String userId, String channelId, {bool force = false})
Close a Lightning channel (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
channelId |
String |
Yes | Hex-encoded channel ID |
force |
bool |
No | Force close unilaterally (default: false) |
static WalletResponse<String> closeChannelAsync(String userId, String channelId, {bool force = false, String? peerAddress, int? peerPort})
Close a channel (non-blocking). Returns operation ID. Optionally provide peer address for cooperative close.
static WalletResponse<List<Channel>> listChannels(String userId)
List all Lightning channels.
Returns: List of Channel with:
channelId- Unique channel identifiercounterpartyNodeId- Peer's public keychannelValueSats- Total channel capacitybalanceSats- Local balanceinboundCapacitySats- Available inbound liquidityoutboundCapacitySats- Available outbound liquidityisUsable- Whether channel can route paymentsisPublic- Whether channel is announced to networkshortChannelId- Short channel ID (if confirmed)
Invoice Management
static WalletResponse<InvoiceInfo> createInvoice(String userId, {int? amountSats, String? description, int expirySecs = 3600})
Create a BOLT11 Lightning invoice.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amountSats |
int? |
No | Invoice amount (null for "any amount") |
description |
String? |
No | Human-readable description |
expirySecs |
int |
No | Expiry time in seconds (default: 3600) |
Returns: InvoiceInfo with bolt11, paymentHash, amountSats, description, createdAt, expiresAt.
Payment Operations
static WalletResponse<PaymentResult> payInvoice(String userId, String bolt11, {int? amountSats})
Pay a BOLT11 Lightning invoice (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
bolt11 |
String |
Yes | BOLT11-encoded invoice |
amountSats |
int? |
No | Amount for "any amount" invoices |
Returns: PaymentResult with payment details.
static WalletResponse<String> payInvoiceAsync(String userId, String bolt11, {int? amountSats})
Pay an invoice (non-blocking). Returns operation ID.
static WalletResponse<PaymentResult> sendKeysend(String userId, {required String destinationPubkey, required int amountSats, Map<int, List<int>>? customRecords})
Send a spontaneous keysend payment (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
destinationPubkey |
String |
Yes | Destination node's 33-byte hex public key |
amountSats |
int |
Yes | Amount to send in satoshis |
customRecords |
Map<int, List<int>>? |
No | TLV custom records (Podcasting 2.0) |
Podcasting 2.0 TLV Types:
const podcastTlv = 7629169; // Podcast name
const episodeTlv = 7629171; // Episode GUID
const actionTlv = 7629173; // Action (stream/boost)
const timestampTlv = 7629175; // Timestamp in episode
const appNameTlv = 7629177; // App name
static WalletResponse<String> sendKeysendAsync(String userId, {...})
Send keysend (non-blocking). Returns operation ID. Same parameters as sendKeysend().
static WalletResponse<PaymentResult> payLightningAddress(String userId, {required String lightningAddress, required int amountSats, String? comment})
Pay a Lightning Address (LNURL-pay) (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
lightningAddress |
String |
Yes | Lightning Address (e.g., [email protected]) |
amountSats |
int |
Yes | Amount to send in satoshis |
comment |
String? |
No | Optional payment comment |
static WalletResponse<String> payLightningAddressAsync(String userId, {...})
Pay Lightning Address (non-blocking). Returns operation ID.
static WalletResponse<String> sendOnchain(String userId, {required String address, required int amountSats, int feeRateSatPerVbyte = 0})
Send an on-chain Bitcoin transaction (blocking).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
address |
String |
Yes | Destination Bitcoin address |
amountSats |
int |
Yes | Amount to send in satoshis |
feeRateSatPerVbyte |
int |
No | Fee rate (0 = use default) |
Returns: Transaction ID (txid) as hex string.
static WalletResponse<String> sendOnchainAsync(String userId, {...})
Send on-chain (non-blocking). Returns operation ID.
Fee Estimation
static WalletResponse<FeeEstimate> estimateOnchainFee(String userId, {required int amountSats, required int feeRateSatPerVbyte})
Estimate the fee for an on-chain transaction.
Returns: FeeEstimate with:
feeSats- Estimated fee in satoshisfeeRateSatPerVbyte- Fee rate usedestimatedVbytes- Estimated transaction sizetotalSats- Total amount including fee
static WalletResponse<RecommendedFeeRates> getRecommendedFeeRates(String userId)
Get recommended fee rates for different confirmation speeds (blocking).
Returns: RecommendedFeeRates with:
fastSatPerVbyte- Fast (1-2 blocks)mediumSatPerVbyte- Medium (3-6 blocks)slowSatPerVbyte- Slow (7+ blocks)
static WalletResponse<String> getRecommendedFeeRatesAsync(String userId)
Get fee rates (non-blocking). Returns operation ID.
Async Operation Management
All *Async methods return an operation ID. Use these methods to poll for results:
static WalletResponse<OperationStatus> getOperationStatus(String operationId)
Get the status of an async operation.
Returns: OperationStatus with:
operationId- The operation IDoperationType- Type of operationstatus-pending,running,completed,failed,not_foundprogress- Progress message (if available)result- Result data (if completed)error- Error message (if failed)
Helper properties:
isPending,isRunning,isCompleted,isFailed,isNotFoundisInProgress- true if pending or runningisDone- true if completed or failed
static WalletResponse<void> clearOperationStatus(String operationId)
Clear the status of an operation to free memory. Call after you're done polling.
Types #
WalletResponse #
Generic response wrapper for all API calls.
class WalletResponse<T> {
final bool success; // Whether the operation succeeded
final T? data; // Result data (if success)
final String? error; // Error message (if failed)
}
WalletBalance #
Balance information for the wallet.
class WalletBalance {
final int onchain; // On-chain balance in satoshis
final int lightning; // Lightning channel balance in satoshis
int get total; // Sum of both balances
}
InitStatus #
Initialization status for async wallet initialization.
class InitStatus {
final String status; // "not_started", "pending", "initializing", "completed", "failed"
final String? progress; // Progress message
final String? error; // Error message (if failed)
// Helper getters
bool get isNotStarted;
bool get isPending;
bool get isInitializing;
bool get isCompleted;
bool get isFailed;
bool get isInProgress; // true if pending or initializing
}
Payment #
Payment record for both Lightning and on-chain transactions.
class Payment {
final String paymentHash; // Unique payment identifier
final String paymentType; // 'sent', 'received', 'onchain_sent', 'onchain_received'
final String status; // 'pending', 'completed', 'failed'
final int amountSats; // Payment amount in satoshis
final int? feeSats; // Fee paid (if applicable)
final String? bolt11; // Original BOLT11 invoice
final String? preimage; // Lightning payment preimage
final int timestamp; // Unix timestamp
final String? description; // Payment description/memo
final String? destination; // Destination node ID or address
final String? txid; // On-chain transaction ID
}
Channel #
Lightning channel information.
class Channel {
final String channelId; // Unique channel identifier
final String counterpartyNodeId; // Peer's public key
final int channelValueSats; // Total channel capacity
final int balanceSats; // Local balance
final int inboundCapacitySats; // Available for receiving
final int outboundCapacitySats; // Available for sending
final bool isUsable; // Can route payments
final bool isPublic; // Announced to network
final String? shortChannelId; // Short channel ID (if confirmed)
}
Peer #
Connected Lightning peer information.
class Peer {
final String nodeId; // Peer's public key
final String? address; // IP address or hostname
final int? port; // TCP port
final bool isConnected; // Connection status
}
InvoiceInfo #
BOLT11 invoice creation result.
class InvoiceInfo {
final String bolt11; // BOLT11-encoded invoice
final String paymentHash; // Unique payment identifier
final int? amountSats; // Invoice amount (null for "any amount")
final String? description; // Invoice description
final int createdAt; // Unix timestamp of creation
final int expiresAt; // Unix timestamp of expiry
}
PaymentResult #
Payment result from paying an invoice or sending keysend.
class PaymentResult {
final String paymentHash; // Unique payment identifier
final String paymentType; // 'sent', 'received', etc.
final int amountSats; // Payment amount
final int? feeSats; // Fee paid
final String status; // 'pending', 'completed', 'failed'
final int timestamp; // Unix timestamp
final String? description; // Payment description
final String? destination; // Destination node/address
final String? preimage; // Payment preimage (proof of payment)
final String? bolt11; // Original invoice
}
FeeEstimate #
On-chain fee estimate.
class FeeEstimate {
final int feeSats; // Estimated fee in satoshis
final int feeRateSatPerVbyte; // Fee rate used (sat/vbyte)
final int estimatedVbytes; // Estimated transaction size
final int totalSats; // Total amount including fee
}
RecommendedFeeRates #
Recommended fee rates for different confirmation speeds.
class RecommendedFeeRates {
final int fastSatPerVbyte; // Fast (1-2 blocks)
final int mediumSatPerVbyte; // Medium (3-6 blocks)
final int slowSatPerVbyte; // Slow (7+ blocks)
}
WalletEvent #
Real-time wallet event.
class WalletEvent {
final String eventType; // Event type string
final Map<String, dynamic> data; // Event-specific data
final int timestamp; // Unix timestamp
}
OperationStatus #
Status of an async operation.
class OperationStatus {
final String operationId; // The operation ID
final String operationType; // Type of operation
final String status; // "pending", "running", "completed", "failed", "not_found"
final String? progress; // Progress message
final dynamic result; // Result data (if completed)
final String? error; // Error message (if failed)
// Helper getters
bool get isPending;
bool get isRunning;
bool get isCompleted;
bool get isFailed;
bool get isNotFound;
bool get isInProgress; // true if pending or running
bool get isDone; // true if completed or failed
}
BitcoinNetwork #
Supported Bitcoin networks.
enum BitcoinNetwork {
bitcoin, // Mainnet (real funds)
testnet, // Testnet (test funds)
regtest, // Regtest (local testing)
}
Rust FFI Reference #
The native Rust library exposes C-compatible FFI functions. All functions return JSON strings with the format:
{"success": true, "data": {...}}
// or
{"success": false, "error": "error message"}
Core Functions #
| C Function | Parameters | Description |
|---|---|---|
wallet_initialize |
user_id, mnemonic, network, db_path |
Initialize wallet instance |
wallet_generate_mnemonic |
None | Generate 24-word BIP39 mnemonic |
wallet_get_balance |
user_id |
Get wallet balance |
wallet_sync |
user_id |
Sync with blockchain |
wallet_get_receiving_address |
user_id |
Get new receiving address |
wallet_list_payments |
user_id, limit, offset |
List payment history |
wallet_get_events |
user_id |
Drain pending events |
wallet_disconnect |
user_id |
Disconnect and cleanup |
wallet_free_string |
ptr |
Free allocated string memory |
Peer Functions #
| C Function | Parameters | Description |
|---|---|---|
wallet_connect_peer |
user_id, node_id, address, port |
Connect to peer |
wallet_disconnect_peer |
user_id, node_id |
Disconnect from peer |
wallet_list_peers |
user_id |
List connected peers |
Channel Functions #
| C Function | Parameters | Description |
|---|---|---|
wallet_open_channel |
user_id, counterparty_node_id, channel_value_sats, push_msat, peer_address, peer_port |
Open channel |
wallet_close_channel |
user_id, channel_id, force |
Close channel |
wallet_list_channels |
user_id |
List all channels |
Invoice Functions #
| C Function | Parameters | Description |
|---|---|---|
wallet_create_invoice |
user_id, amount_sats, description, expiry_secs |
Create BOLT11 invoice |
Payment Functions #
| C Function | Parameters | Description |
|---|---|---|
wallet_pay_invoice |
user_id, bolt11, amount_sats |
Pay BOLT11 invoice |
wallet_send_keysend |
user_id, destination_pubkey, amount_sats, custom_records_json |
Send keysend payment |
wallet_send_onchain |
user_id, address, amount_sats |
Send on-chain transaction |
wallet_get_node_id |
user_id |
Get node public key |
Android JNI Functions #
For Android, the library also exports JNI-compatible functions:
| JNI Function | Equivalent C Function |
|---|---|
Java_..._nativeInitialize |
wallet_initialize |
Java_..._nativeGenerateMnemonic |
wallet_generate_mnemonic |
Java_..._nativeGetBalance |
wallet_get_balance |
Java_..._nativeSyncWallet |
wallet_sync |
Java_..._nativeGetReceivingAddress |
wallet_get_receiving_address |
Java_..._nativeListPayments |
wallet_list_payments |
Java_..._nativeGetEvents |
wallet_get_events |
Java_..._nativeDisconnect |
wallet_disconnect |
Rust Module Reference #
WalletCoordinator (coordinator.rs) #
Main orchestrator that manages wallet components.
impl WalletCoordinator {
pub fn new(db_path: &str) -> Result<Self, CoordinatorError>;
pub fn initialize(&self, mnemonic: &str, network: BitcoinNetwork) -> Result<(), CoordinatorError>;
pub fn sync(&self) -> Result<(), CoordinatorError>;
pub fn get_lightning_node(&self) -> Arc<LightningNode>;
pub fn get_database(&self) -> Arc<Database>;
pub fn get_event_emitter(&self) -> Arc<EventEmitter>;
pub fn disconnect(&self) -> Result<(), CoordinatorError>;
}
KeyManager (wallet/keys.rs) #
BIP39/BIP32 HD wallet key management.
impl KeyManager {
pub fn from_mnemonic(mnemonic: &str, network: Network) -> Result<Self, KeyError>;
pub fn generate_mnemonic() -> String;
pub fn get_lightning_seed(&self) -> Result<[u8; 32], KeyError>; // Derives at m/535'/0'
}
LightningNode (ldk/node.rs) #
LDK-node wrapper for Lightning Network operations.
impl LightningNode {
// Lifecycle
pub fn new() -> Self;
pub fn initialize(&self, entropy: [u8; 32], network: Network, storage_path: &str, esplora_server: Option<&str>) -> Result<(), LightningError>;
pub fn start(&self) -> Result<(), LightningError>;
pub fn stop(&self) -> Result<(), LightningError>;
pub fn sync_wallets(&self) -> Result<(), LightningError>;
// Peer Management
pub fn connect_peer(&self, params: ConnectPeerParams) -> Result<(), LightningError>;
pub fn disconnect_peer(&self, node_id: &str) -> Result<(), LightningError>;
pub fn list_peers(&self) -> Result<Vec<PeerInfo>, LightningError>;
pub fn get_node_id(&self) -> Result<String, LightningError>;
// Channel Management
pub fn open_channel(&self, params: OpenChannelParams) -> Result<String, LightningError>;
pub fn close_channel(&self, params: CloseChannelParams) -> Result<(), LightningError>;
pub fn list_channels(&self) -> Result<Vec<ChannelInfo>, LightningError>;
// Invoices
pub fn create_invoice(&self, params: CreateInvoiceParams) -> Result<InvoiceInfo, LightningError>;
// Payments
pub fn pay_invoice(&self, params: PayInvoiceParams) -> Result<PaymentInfo, LightningError>;
pub fn send_keysend(&self, params: KeysendParams) -> Result<PaymentInfo, LightningError>;
pub fn send_onchain(&self, params: SendOnChainParams) -> Result<String, LightningError>;
pub fn list_payments(&self) -> Result<Vec<PaymentInfo>, LightningError>;
// Balance
pub fn get_onchain_address(&self) -> Result<String, LightningError>;
pub fn get_spendable_onchain_balance(&self) -> Result<u64, LightningError>;
pub fn get_total_onchain_balance(&self) -> Result<u64, LightningError>;
}
Database (storage/db.rs) #
SQLite storage for payment history.
impl Database {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, DatabaseError>;
pub fn list_payments(&self, limit: Option<usize>, offset: Option<usize>) -> Result<Vec<Payment>, DatabaseError>;
}
EventEmitter (events.rs) #
Bounded event queue for real-time notifications.
impl EventEmitter {
pub fn new(capacity: usize) -> Self;
pub fn emit(&self, event: WalletEvent);
pub fn drain_events(&self) -> Vec<WalletEvent>;
}
Podcasting20Builder (ldk/podcasting.rs) #
Fluent builder for Podcasting 2.0 value-for-value TLV records.
impl Podcasting20Builder {
pub fn new() -> Self;
pub fn podcast(self, name: &str) -> Self; // TLV 7629169
pub fn episode(self, guid: &str) -> Self; // TLV 7629171
pub fn action(self, action: &str) -> Self; // TLV 7629173
pub fn timestamp(self, timestamp: u64) -> Self; // TLV 7629175
pub fn app_name(self, name: &str) -> Self; // TLV 7629177
pub fn custom(self, key: u64, value: &str) -> Self;
pub fn custom_bytes(self, key: u64, value: Vec<u8>) -> Self;
pub fn build(self) -> HashMap<u64, Vec<u8>>;
}
// Usage example:
let custom_records = Podcasting20Builder::new()
.podcast("My Podcast")
.episode("episode-guid-123")
.action("stream")
.app_name("MyApp")
.build();
Error Types #
CoordinatorError #
pub enum CoordinatorError {
AlreadyInitialized, // Wallet already initialized
KeyError(String), // Key derivation/management error
StorageError(String), // Database/storage error
LightningError(String), // Lightning node error
}
KeyError #
pub enum KeyError {
InvalidMnemonic(String), // Invalid BIP39 mnemonic
Derivation(String), // BIP32 derivation failed
InvalidNetwork(String), // Network mismatch
}
LightningError #
pub enum LightningError {
NotInitialized, // Node not initialized
AlreadyInitialized, // Node already initialized
LdkError(String), // LDK-node error
NetworkError(String), // Network communication error
PeerError(String), // Peer connection error
ChannelError(String), // Channel operation error
PaymentError(String), // Payment failed
InvoiceError(String), // Invoice creation/parsing error
StorageError(String), // Storage error
}
DatabaseError #
pub enum DatabaseError {
Connection(String), // Database connection failed
Query(String), // Query execution error
NotFound(String), // Record not found
}
Development #
Run Rust tests #
cd rust
cargo test
Build Rust library (debug) #
cd rust
cargo build
Format Rust code #
cd rust
cargo fmt
Lint Rust code #
cd rust
cargo clippy
Regenerate FFI bindings #
If you modify the C header file, regenerate bindings:
dart run ffigen
Troubleshooting #
Android: Library not found #
Make sure you've built the native library and the .so files are in android/src/main/jniLibs/:
android/src/main/jniLibs/
├── arm64-v8a/liblightening_wallet.so
├── armeabi-v7a/liblightening_wallet.so
├── x86_64/liblightening_wallet.so
└── x86/liblightening_wallet.so
iOS: Framework not found #
Ensure the XCFramework was built correctly:
./scripts/build-ios.sh
Check that ios/LighteningWallet.xcframework exists.
macOS: Library not found #
Ensure the static library was built:
./scripts/build-macos.sh
Check that macos/liblightening_wallet_macos.a exists.
iOS/macOS CI Builds: "Build input file cannot be found" #
When building in CI environments, you may encounter this error:
Build input file cannot be found: '.../LighteningWallet.xcframework/ios-arm64/liblightening_wallet.a'
Cause: The podspec uses a CocoaPods script_phase to download the native binaries from GitLab releases before compilation. However, the user_target_xcconfig linker flags reference these files, and Xcode validates that referenced files exist before running script phases.
Workaround: Download the native binaries in your CI pipeline before running flutter build or pod install. Add this to your CI configuration:
For iOS:
# After flutter pub get, before pod install
LW_VERSION=$(grep -A 10 "lightening_wallet:" pubspec.lock | grep "version:" | head -1 | awk '{print $2}' | tr -d '"')
PLUGIN_DIR="$HOME/.pub-cache/hosted/pub.dev/lightening_wallet-${LW_VERSION}/ios"
if [ ! -d "$PLUGIN_DIR/LighteningWallet.xcframework" ]; then
curl -L -f "https://gitlab.com/elementfm/flutter-lightening-wallet-rs/-/releases/v${LW_VERSION}/downloads/LighteningWallet.xcframework.zip" -o "$PLUGIN_DIR/framework.zip"
unzip -o "$PLUGIN_DIR/framework.zip" -d "$PLUGIN_DIR"
rm "$PLUGIN_DIR/framework.zip"
fi
For macOS:
# After flutter pub get, before build
LW_VERSION=$(grep -A 10 "lightening_wallet:" pubspec.lock | grep "version:" | head -1 | awk '{print $2}' | tr -d '"')
PLUGIN_DIR="$HOME/.pub-cache/hosted/pub.dev/lightening_wallet-${LW_VERSION}/macos"
if [ ! -f "$PLUGIN_DIR/liblightening_wallet_macos.a" ]; then
curl -L -f "https://gitlab.com/elementfm/flutter-lightening-wallet-rs/-/releases/v${LW_VERSION}/downloads/liblightening_wallet_macos.a" -o "$PLUGIN_DIR/liblightening_wallet_macos.a"
fi
This is only needed for CI. Local development builds work correctly because the script phase has time to download the binaries before subsequent builds reference them.
Linux: Library not found #
Ensure the shared library was built:
./scripts/build-linux.sh
Check that linux/liblightening_wallet.so exists.
Windows: DLL not found #
Ensure the DLL was built:
./scripts/build-windows.sh
Check that windows/lightening_wallet.dll exists.
License #
MIT
Credits #
This library integrates and builds upon: