Bitcoin Lightning Network Solutions Development
Lightning Network is not just "fast Bitcoin payments". It's a payment channel protocol that enables what's impossible on Bitcoin base layer: micropayments of few satoshis, subsecond transactions, streaming payments (pay per second for content or service). But behind this stands nontrivial engineering: liquidity management, routing, channel capacity, HTLC mechanics. A developer who just "connected LND" is not ready for production load.
Fundamental mechanism: how payment channels work
A channel is a 2-of-2 multisig on Bitcoin base layer with commitment transactions. When Alice and Bob open a channel for 0.1 BTC, one funding transaction goes on-chain. Then they exchange off-chain commitment transactions, redistributing 0.1 BTC between them. Current channel state is the latest pair of commitment transactions.
Security is ensured by punishment: if someone tries to close channel with old state (where they have more money), the other party can during to_self_delay blocks take ALL channel funds via revocation secret. This justice transaction mechanism ensures safety.
HTLC (Hash Time-Locked Contract) — mechanism for multi-hop payments. Recipient generates preimage R, publishes H = SHA256(R). Sender builds HTLC chain through intermediate nodes: "get funds if you present preimage to hash H before timeout T". When recipient reveals R — payment "unrolls" back along chain, each hop gets its fee.
Onion routing (Sphinx): each node on path sees only previous and next hop, not entire route. Privacy by default.
Choosing node implementation
LND (Lightning Labs, Go)
Most popular implementation. REST and gRPC API, active development, large ecosystem of tools.
# Basic run (with Bitcoin Core backend)
lnd --bitcoin.active --bitcoin.mainnet \
--bitcoin.node=bitcoind \
--bitcoind.rpchost=localhost \
--bitcoind.rpcuser=user --bitcoind.rpcpass=pass \
--bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333 \
--bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332 \
--restlisten=0.0.0.0:8080 \
--tlsextraip=0.0.0.0
gRPC API via lnrpc:
conn, _ := grpc.Dial("localhost:10009", grpc.WithTransportCredentials(creds))
client := lnrpc.NewLightningClient(conn)
// Create invoice
invoice, _ := client.AddInvoice(ctx, &lnrpc.Invoice{
Memo: "Order #12345",
Value: 1000, // satoshi
Expiry: 3600, // 1 hour
Private: true, // use private route hints
})
// invoice.PaymentRequest — BOLT-11 string for QR code
CLN (Core Lightning, Blockstream/Rusty Russell)
Minimalist, plugin architecture. Each plugin is separate process, communicating via JSON-RPC. Allows writing business logic in any language.
# CLN plugin in Python
from pyln.client import Plugin
plugin = Plugin()
@plugin.hook("invoice_payment")
def on_payment(payment, plugin, **kwargs):
# Called on each received payment
plugin.log(f"Received {payment['msat']} msat")
process_payment(payment)
return {"result": "continue"}
plugin.run()
Eclair (ACINQ, Scala)
Production-ready, powers Phoenix wallet. Well documented. Optimal if your stack is JVM/Scala.
Choice for production
- LND — for most cases. Mature API, lndhub compatibility, active ecosystem.
- CLN — if you need plugin architecture and maximum customization.
- Eclair — for JVM stack or if working with ACINQ (Phoenix, Strike integrations).
Liquidity management: main operational task
Lightning node is not "run and forget". Channel liquidity requires constant management.
Inbound vs outbound liquidity
Outbound capacity — how much you can send. Created when you open channel and put BTC there.
Inbound capacity — how much you can receive. Created when someone opens channel to you, or through loop-out operations.
For merchant node (receive payments) — need inbound capacity. For routing node — need balance on both sides.
Circular rebalancing
If channel with Alice is drained (Alice has all balance) and with Bob is full (we have all balance), can send payment to self through route us → Alice → ... → Bob → us:
# LND: circular rebalance
lncli payinvoice --allow_self_payment \
--last_hop <bob_pubkey> \
--outgoing_chan_id <our_channel_with_bob> \
<self_invoice>
Rebalancing automation: charge-lnd (config-based rules), balanceofsatoshis (bos tool), or custom script.
Loop (Lightning Loop)
Lightning Loop from LND lets move liquidity between on-chain and off-chain without closing channels:
- Loop Out: withdraw from Lightning to on-chain. Restores inbound capacity.
- Loop In: introduce on-chain funds to Lightning. Restores outbound capacity.
loopClient := looprpc.NewSwapClientClient(conn)
resp, _ := loopClient.LoopOut(ctx, &looprpc.LoopOutRequest{
Amt: 1_000_000, // satoshi
Dest: "bc1q...", // on-chain address
MaxSwapRoutingFee: 1000,
MaxMinerFee: 5000,
})
Pool (Channel Leasing)
Lightning Pool — liquidity market. Can lease inbound capacity for period or lease your liquidity. Relevant for merchant nodes needing guaranteed inbound capacity.
Routing and fees
Fee policy
For routing node, fee policy is balance between attractiveness and profitability:
lncli updatechanpolicy \
--base_fee_msat 1000 \ # 1 sat fixed fee
--fee_rate 0.000001 \ # 0.0001% of amount
--time_lock_delta 40 \ # CLTV delta
--chan_point <funding_txid>:<output_index>
Dynamic fee management: raise fee on low-outbound channels (prevent further drain), lower on surplus-outbound (attract routing). Tools: charge-lnd with strategies, LNDg (dashboard + automation).
Probing and pathfinding
LND uses Dijkstra for path finding considering capacity, fee, CLTV requirements, historical success rate. Pathfinding accounts for recent failures — channel with error gets penalty in scoring.
MPP (Multi-Path Payments) — split large payment into several paths in parallel. Increases success probability for large amounts:
// LND MPP via SendPaymentV2
req := &routerrpc.SendPaymentRequest{
PaymentRequest: bolt11,
MaxParts: 10, // up to 10 parts
TimeoutSeconds: 60,
FeeLimitMsat: 10000, // 10 sat max fee
}
BOLT-11 and BOLT-12 invoices
BOLT-11 — standard invoice format. Contains: recipient (pubkey or via private route hints), amount, expiry, payment hash, description.
BOLT-12 Offers — new standard (not all implementations support):
- Reusable: one offer for multiple payments (ideal for donations)
- No amount specified (payer chooses amount)
- Privacy: each payment gets unique invoice, offer doesn't expose node pubkey directly
# CLN: create BOLT-12 offer
lightning-cli offer any "Donation to my project"
# Returns: lno1pg257... — permanent QR code string
Watchtower: breach protection
If your node was offline, counterparty can try closing channel with old (favorable) state. Watchtower — service that monitors chain for you and publishes justice transaction if detects breach.
LND has built-in watchtower client and server. For production nodes — connect to multiple external watchtowers:
lncli wtclient add <watchtower_pubkey>@<host>:<port>
Alternative: Eye of Satoshi — open watchtower server for CLN.
Application integration
Accepting Lightning payments
import { AuthenticatedLnd } from "lightning";
import { createInvoice, subscribeToInvoices } from "lightning";
const subscription = subscribeToInvoices({ lnd });
subscription.on("invoice_updated", async (invoice) => {
if (!invoice.is_confirmed) return;
await db.orders.markPaid({
paymentHash: invoice.id,
paidAt: new Date(invoice.confirmed_at),
amountSat: invoice.received,
});
await notifyUser(invoice.description);
});
async function createPaymentRequest(orderAmount: number): Promise<string> {
const { request } = await createInvoice({
lnd,
tokens: orderAmount,
description: `Order payment`,
expires_at: new Date(Date.now() + 3600_000).toISOString(),
});
return request; // BOLT-11 string
}
Streaming payments
Pay per unit of time — unique Lightning capability:
// Send 1 sat per second (via keysend)
async function streamPayment(recipientPubkey: string, durationSec: number) {
for (let i = 0; i < durationSec; i++) {
await sendPayment({
lnd,
destination: recipientPubkey,
tokens: 1, // 1 sat
is_allowing_self_payment: false,
});
await delay(1000);
}
}
L402 protocol (HTTP 402 Payment Required) — standard for pay-per-request API: client gets 402 with Lightning invoice, pays, includes preimage in next request header.
Operational questions
Backups: channel.backup file contains data for Static Channel Backup (SCB) — fund recovery on node loss via cooperative close. Automatic backup on every change — mandatory.
Key security: LND wallet.db contains private keys. HSM or Vault for production. Never store on same machine as hot server without extra protection.
Monitoring: LND Prometheus exporter — standard tool. Key metrics: channel balance per channel, pending HTLCs, routing fee income, channel count, uptime.
| Component | Technology |
|---|---|
| Lightning node | LND v0.18+ or CLN v24+ |
| Bitcoin node | Bitcoin Core (IBD ~1 week) or Neutrino (lightweight) |
| API integration | lightning npm package (LND) or pylightning (CLN) |
| Liquidity | Lightning Pool + Loop |
| Monitoring | LND Prometheus exporter + Grafana |
| Backup | Automatic SCB to S3/cloud |
Timeline: production node setup with monitoring and basic integration — 2–4 weeks. Complete solution with liquidity management and custom business logic — 2–4 months.







