Demystifying the Lightning Development Kit: A Beginner's Guide to Building Bitcoin Lightning Wallets
An Overview for Understanding the Lightning Development Kit
What is Lightning Dev Kit?
Lighting Dev Kit (LDK) is an open-source library used to integrate lightning network to a Bitcoin Wallet. LDK is written in Rust but through the power of language bindings, it can be used across various platforms to integrate the lightning network. LDK currently has bindings for Swift, Java/Kotlin and TypeScript. LDK allows developers to build a lightning node without worrying about implementing low-level lightning logic. It offers a high degree of flexibility and customization for various components of a Lightning application, such as persistence, networking, chain source, routing, key management, wallet, etc.
How to Setup the Development Environment for LDK?
Setting up the Test Network
LDK supports all the Bitcoin Networks however working on a local lightning network is the best when it comes to the development of lightning based applications. Polar is one of the applications that help us to create a lightning network locally. To get started, install Polar (and Docker which is one of its dependencies), and create a new Lightning Network.
You have got a fully working local Lightning Network now!
Using LDK in a Swift Project
In this article I will demonstrate using LDK in a Swift project.
Add ldk-swift package using the Swift Package Manager.
To import the package, use
import LightningDevKit
How to get an LDK Node Running?
LDK can look overwhelming at first but understanding it’s components can greatly assist you in smoothly integrating it into your project. The flowchart below can be helpful for implementing the various objects and get started.
Here is some brief information about the various objects:-
FeeEstimator: This estimates the fee required for the on-chain transactions made by LDK. The methods of this class are needed to be overridden and the fee estimation must be handled by the developer.
Logger: This logs important states and events. The methods of this class are needed to be overridden and the logging must be handled by the developer.
Broadcaster: This broadcasts a transaction to the Bitcoin Network. The methods of this class are needed to be overridden and the transaction broadcast must be handled by the developer.
Persist: This persists channel monitors which include crucial channel data. The methods of this class are needed to be overridden and persistence must be handled by the developer.
Filter: This keeps track of transactions and outputs which are of interest to the channels. The methods of this class are needed to be overridden and keeping track of the transactions and output must be handled by the developer. It is only needed if LDK is not provided with full blocks, i.e. if you're using BIP 157/158 or Electrum as your chain backend.
Chain Monitor: This tracks Channel Monitors and use them to monitor chain for lightning transactions relevant to the node and broadcasting transaction.
Network: The Bitcoin Network which you want LDK to use.
Network Graph: This is used to generate routes for sending payment. It is only required if you are not providing your own routes and want LDK to provide routes for sending payment.
Probabilistic Scoring Parameters: Parameters for configuring Probabilistic Scorer.
Probabilistic Scorer: This is an implementation of a Score, and it helps to find the best route for a payment. It uses a probabilistic model to score channels based on their effective capacity and liquidity penalty.
Multi Threaded Lockable Score: This is an implementation of Lockable Score, which supports multi-threading.
Keys Manager: This is a simple implementation of EntropySource, NodeSigner, and SignerProvider and it takes a 32 byte seed and starting time.
Channel Handshake Config: This provides configuration Parameters for initial Channel Handshake.
Channel Handshake Limit: This provides channel limits for initial Channel Creation.
User Config: This provides configuration Parameters for Channels.
Channel Manager Configuration Parameters: This is a set of parameters used to create a new Channel Manager Constructor.
Channel Manager Constructor: This is used to derive Channel Manager, Peer Manager, Peer Handler.
Channel Manager: This keeps track of a number of channels and sends messages to the appropriate channel, also tracking HTLC pre-images and forwarding onion packets appropriately.
Peer Manager: This manages the connection to other peers.
Peer Handler: This helps in creating new connections with peers.
Channel Manager Persister: This helps in persisting Channel Manager, Network Graph and Scorer.
Now, to sync our LDK node, we must monitor the transactions and outputs provided by the Filter. We can use the asConfirm property of the Chain Monitor and Channel Manager to notify LDK when relevant transactions have been confirmed on chain or unconfirmed during a chain re-organization. The asListen property can also be used depending upon the requirements.
How to use LDK?
LDK has a lot of functions, few of the important ones are listed below.
Get Node ID
channelManager.getOurNodeId()
Connect to a Peer
peerHandler.connect(address: address, port: port, theirNodeId: nodeId)
List Peers
peerManager.getPeerNodeIds()
Create Channel
channelManager.createChannel(theirNetworkKey: nodeId, channelValueSatoshis: amount, pushMsat: pushMsat, userChannelId: channelId, overrideConfig: userConfig)
List Channels
channelManager.listChannels()
Close Channel
channelManager.closeChannel(channelId: channelId, counterpartyNodeId: counterpartyNodeId)
Pay Invoice
Bindings.payInvoice(invoice: invoice, retryStrategy: Bindings.Retry.initWithTimeout(a: 15), channelmanager: channelManager)
Generate Invoice
Bindings.createInvoiceFromChannelmanager(channelmanager: channelManager, nodeSigner: keysManager.asNodeSigner(), logger: logger, network: currency, amtMsat: amount, description: description, invoiceExpiryDeltaSecs: expiry, minFinalCltvExpiryDelta: nil)
Event Handling
LDK has an Event Driven architecture and it is important for the developer to handle the events. It is highly recommended to read through each of the events in the documentation and handle it properly.
func handleEvent(event: LightningDevKit.Event) {
if let event = event.getValueAsPendingHtlcsForwardable() {
// Handle Event
} else if let event = event.getValueAsChannelPending() {
// Handle Event
} else if let event = event.getValueAsChannelPending() {
// Handle Event
} else if let event = event.getValueAsChannelReady() {
// Handle Event
} else if let event = event.getValueAsDiscardFunding() {
// Handle Event
} else if let event = event.getValueAsFundingGenerationReady() {
// Handle Event
} else if let event = event.getValueAsHtlcHandlingFailed() {
// Handle Event
} else if let event = event.getValueAsHtlcIntercepted() {
// Handle Event
} else if let event = event.getValueAsOpenChannelRequest() {
// Handle Event
} else if let event = event.getValueAsPaymentClaimable() {
// Handle Event
} else if let event = event.getValueAsPaymentClaimed() {
// Handle Event
} else if let event = event.getValueAsPaymentFailed() {
// Handle Event
} else if let event = event.getValueAsPaymentForwarded() {
// Handle Event
} else if let event = event.getValueAsPaymentPathFailed() {
// Handle Event
} else if let event = event.getValueAsPaymentPathSuccessful() {
// Handle Event
} else if let event = event.getValueAsPaymentSent() {
// Handle Event
} else if let event = event.getValueAsChannelClosed() {
// Handle Event
} else if let event = event.getValueAsProbeFailed() {
// Handle Event
} else if let event = event.getValueAsProbeSuccessful() {
// Handle Event
} else if let event = event.getValueAsSpendableOutputs() {
// Handle Event
}
}
So finally we have our fully working LDK Node! 🎉
How to seek help if stuck
Sometimes things don’t go the way we want it to be, in those situations it is best to get help from the community. The LDK Discord can be very helpful to get your issues resolved.