LND (Lightning Network Daemon) Integration

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
LND (Lightning Network Daemon) Integration
Medium
~2-3 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1217
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1046
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Integration with LND (Lightning Network Daemon)

Lightning Network solves specific Bitcoin problem: on-chain transactions cost money and require confirmations. LND (Lightning Network Daemon from Lightning Labs) is the most widespread LN node implementation. LND integration is needed when you want to accept instant Bitcoin payments with fees in few satoshis, or build app on top of Lightning. This is not "connect to API" — it's running and maintaining payment infrastructure.

What LND is and how it works

LND is a software Lightning Network node. Requires:

  • Synchronized Bitcoin node (Bitcoind or neutrino light mode)
  • Open payment channels with network partners
  • Liquidity management: your side of channel needs funds for outgoing payments, opposite side for incoming

Payment channels are 2-of-2 multisig contracts on Bitcoin L1. LND manages channel state off-chain, publishing to blockchain only on open and close.

Invoice-based payments. Receiver creates invoice (BOLT-11 ticket), payer pays it. Invoice contains payment hash — HTLC mechanism guarantees atomicity.

Connecting to LND: gRPC vs REST

LND provides two APIs: gRPC (main, complete) and REST (wrapper). For production — gRPC.

Authentication through TLS certificate + macaroon (capability-based token):

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import fs from 'fs';

const TLS_CERT = fs.readFileSync('/home/bitcoin/.lnd/tls.cert');
const MACAROON = fs.readFileSync('/home/bitcoin/.lnd/data/chain/bitcoin/mainnet/admin.macaroon');

// Create channel with TLS + macaroon
const sslCreds = grpc.credentials.createSsl(TLS_CERT);
const macaroonCreds = grpc.credentials.createFromMetadataGenerator((_, callback) => {
  const metadata = new grpc.Metadata();
  metadata.add('macaroon', MACAROON.toString('hex'));
  callback(null, metadata);
});

const credentials = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds);

const packageDef = protoLoader.loadSync('rpc.proto', { keepCase: true });
const lnrpc = grpc.loadPackageDefinition(packageDef) as any;

const lightning = new lnrpc.lnrpc.Lightning('localhost:10009', credentials);

Macaroon is not just a token, it's capability-based authorization. You can create invoice.macaroon (only invoice creation), readonly.macaroon (read-only), custom with IP and time restrictions. Don't give admin.macaroon to apps — only minimum necessary permissions.

Main operations

Creating invoice (receiving payment)

function addInvoice(amountSats: number, memo: string): Promise<Invoice> {
  return new Promise((resolve, reject) => {
    lightning.AddInvoice({
      value: amountSats,           // amount in satoshis
      memo,                        // description (visible to payer)
      expiry: 3600,                // validity period in seconds
    }, (err: any, response: any) => {
      if (err) reject(err);
      else resolve({
        paymentRequest: response.payment_request,  // BOLT-11 string
        rHash: response.r_hash.toString('hex'),     // payment hash
        addIndex: response.add_index.toString(),
      });
    });
  });
}

BOLT-11 string starts with lnbc (mainnet) or lntb (testnet). This is what user scans with wallet.

Tracking incoming payments

Two approaches:

PollingLookupInvoice by r_hash. Simple but not optimal.

Streaming subscriptionsSubscribeInvoices streams all updates in real-time:

function subscribeInvoices(onSettled: (invoice: SettledInvoice) => void) {
  const stream = lightning.SubscribeInvoices({
    settle_index: 0,  // from start, or from specific index for catch-up
  });

  stream.on('data', (invoice: any) => {
    if (invoice.state === 1) {  // SETTLED = paid
      onSettled({
        rHash: invoice.r_hash.toString('hex'),
        amountPaidSats: Number(invoice.amt_paid_sat),
        settledAt: Number(invoice.settle_date),
        memo: invoice.memo,
      });
    }
  });

  stream.on('error', (err: Error) => {
    // Reconnect logic
    setTimeout(() => subscribeInvoices(onSettled), 5000);
  });
}

Important: persist settle_index. On app restart subscribe from last processed settle_index, or you'll miss payments received during downtime.

Outgoing payments

async function sendPayment(paymentRequest: string): Promise<string> {
  return new Promise((resolve, reject) => {
    const routerStub = new lnrpc.routerrpc.Router('localhost:10009', credentials);
    
    const stream = routerStub.SendPaymentV2({
      payment_request: paymentRequest,
      timeout_seconds: 60,
      fee_limit_sat: 100,  // max fee in satoshis
      max_parts: 4,        // MPP: split into multiple parts if needed
    });
    
    stream.on('data', (payment: any) => {
      if (payment.status === 2) {  // SUCCEEDED
        resolve(payment.payment_preimage.toString('hex'));
      } else if (payment.status === 3) {  // FAILED
        reject(new Error(`Payment failed: ${payment.failure_reason}`));
      }
    });
  });
}

SendPaymentV2 (router RPC) is preferable to old SendPayment — supports MPP (Multi-Path Payments), better error handling.

Liquidity management

This is ongoing task that never ends. Problems:

Inbound liquidity. To receive payments you need liquidity on partner's channel side. New node often can't receive payments. Solutions:

  • Lightning Service Providers (Bitrefill Thor, Loop In, Amboss Magma) — paid inbound rental
  • Open channel to partner: ask partner to open channel to you

Channel rebalancing. Over time channels become "skewed" — all funds on one side. lnd loop out — submarine swap for rebalancing: exits Lightning funds to on-chain, redistributes. Used automatically by tools like charge-lnd or bos (Balance of Satoshis).

Fee policy. For routing other payments through your node, base_fee + fee_rate charged. Proper fee setup affects routing efficiency.

LNURL and wallet integration

LNURL is protocol extensions on top of LN. Key types:

LNURL-pay — user scans QR, wallet automatically requests invoice of needed amount. Don't need to know amount beforehand:

// Backend endpoint for LNURL-pay
app.get('/.well-known/lnurlp/:username', async (req, res) => {
  res.json({
    callback: `https://yourdomain.com/lnurlp/${req.params.username}/pay`,
    maxSendable: 100_000_000,  // msats
    minSendable: 1_000,
    metadata: JSON.stringify([['text/plain', `Pay ${req.params.username}`]]),
    tag: 'payRequest',
  });
});

app.get('/lnurlp/:username/pay', async (req, res) => {
  const { amount } = req.query;  // in msats
  const invoice = await createInvoice(Number(amount) / 1000);
  res.json({ pr: invoice.paymentRequest, routes: [] });
});

Lightning Address — human-readable address like [email protected]. Implemented through LNURL-pay endpoint at /.well-known/lnurlp/{username}.

LNURL-withdraw — allows user to receive funds through LN. Use: payouts, cashback.

What's included in integration

Standard LND integration: setting up or connecting to existing LND node, gRPC client with TLS + macaroon auth, invoice creation, subscription to incoming payments with persistent settle_index, outgoing payment handling, LNURL-pay endpoint (if needed), basic error handling and reconnect logic.

Operational part (channel management, liquidity) — separate question, depends on payment flow scale.

Timeline: 1-2 weeks for backend integration into existing application.