Module 3: Lightning Application Development

Building on Lightning

You now understand how Lightning works at the protocol level: payment channels, commitment transactions, HTLCs, and routing. Now it's time to build applications that leverage this technology.

In this module, you'll learn how to interact with Lightning nodes via APIs, create invoices, handle payments, and build a real Lightning-powered application.

Lightning Implementations

There are three major Lightning implementations, each with different design philosophies and features:

Implementation Language Developer Best For
LND Go Lightning Labs Production apps, well-documented APIs
Core Lightning (CLN) C Blockstream Plugin architecture, lightweight
Eclair Scala ACINQ Mobile (Eclair Mobile), Scala ecosystem

For this module, we'll focus on LND as it has the most extensive API documentation and is widely used in production applications.

LND Architecture

LND provides multiple interfaces for developers:

  • gRPC API: High-performance remote procedure calls
  • REST API: HTTP JSON endpoints (easier to use)
  • CLI: Command-line interface (lncli)

Setting Up Your Development Environment

1. Install LND

# Download LND
wget https://github.com/lightningnetwork/lnd/releases/download/v0.17.0-beta/lnd-darwin-amd64-v0.17.0-beta.tar.gz

# Extract and install
tar -xzf lnd-darwin-amd64-v0.17.0-beta.tar.gz
sudo mv lnd-darwin-amd64-v0.17.0-beta/* /usr/local/bin/

2. Configure LND for Testnet

Create ~/.lnd/lnd.conf:

[Application Options]
listen=0.0.0.0:9735
rpclisten=0.0.0.0:10009
restlisten=0.0.0.0:8080

[Bitcoin]
bitcoin.active=true
bitcoin.testnet=true
bitcoin.node=neutrino

[Neutrino]
neutrino.connect=faucet.lightning.community

3. Start LND

# Start LND
lnd

# In another terminal, create a wallet
lncli create

# Check status
lncli getinfo

Note: This uses Neutrino (SPV mode) for quick setup. For production, you should connect to your own Bitcoin full node.

Lightning Invoices (BOLT 11)

Lightning invoices are encoded payment requests that contain:

  • Payment hash
  • Amount (in satoshis or millisatoshis)
  • Expiry time
  • Description
  • Routing hints (optional)

Creating an Invoice via CLI

# Create invoice for 10,000 satoshis
lncli addinvoice --amt 10000 --memo "Payment for coffee"

# Output:
{
    "r_hash": "a1b2c3d4e5f6...",
    "payment_request": "lntb100u1p3abcd...",
    "add_index": "1"
}

Creating an Invoice via REST API

// JavaScript example using fetch
const createInvoice = async (amount, memo) => {
    const response = await fetch('https://localhost:8080/v1/invoices', {
        method: 'POST',
        headers: {
            'Grpc-Metadata-macaroon': MACAROON_HEX,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            value: amount,
            memo: memo,
            expiry: 3600 // 1 hour
        })
    });

    const invoice = await response.json();
    return invoice.payment_request;
};

// Usage
const paymentRequest = await createInvoice(10000, "Coffee payment");
console.log(`Pay here: ${paymentRequest}`);

Decoding an Invoice

# Decode invoice to see details
lncli decodepayreq lntb100u1p3abcd...

# Output shows:
{
    "destination": "03abc...",
    "payment_hash": "a1b2c3...",
    "num_satoshis": "10000",
    "timestamp": "1696867200",
    "expiry": "3600",
    "description": "Payment for coffee",
    "cltv_expiry": "40"
}

Sending Lightning Payments

Pay an Invoice via CLI

# Pay invoice
lncli payinvoice lntb100u1p3abcd...

# Check payment status
lncli listpayments

Pay via REST API

const payInvoice = async (paymentRequest) => {
    const response = await fetch('https://localhost:8080/v1/channels/transactions', {
        method: 'POST',
        headers: {
            'Grpc-Metadata-macaroon': MACAROON_HEX,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            payment_request: paymentRequest
        })
    });

    const payment = await response.json();
    return payment;
};

// Usage
const result = await payInvoice('lntb100u1p3abcd...');
if (result.payment_preimage) {
    console.log('Payment successful!');
    console.log('Preimage:', result.payment_preimage);
}

Monitoring Payment Status

// Subscribe to invoice updates via WebSocket
const subscribeToInvoices = () => {
    const ws = new WebSocket('wss://localhost:8080/v1/invoices/subscribe');

    ws.onmessage = (event) => {
        const invoice = JSON.parse(event.data);
        console.log('Invoice update:', invoice);

        if (invoice.state === 'SETTLED') {
            console.log('Payment received!', invoice.value, 'sats');
            // Update your database, fulfill order, etc.
        }
    };
};

subscribeToInvoices();

Code Project: Lightning Invoice Generator

Build a simple web application that generates Lightning invoices and monitors payments in real-time.

Project Requirements:

  1. Create a form that accepts amount and description
  2. Generate Lightning invoice using LND REST API
  3. Display invoice as QR code (use qrcode.js)
  4. Subscribe to invoice updates via WebSocket
  5. Show "Payment Received" when invoice is settled
  6. Display payment history

Starter Code:

<!DOCTYPE html>
<html>
<head>
    <title>Lightning Invoice Generator</title>
    <script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>
</head>
<body>
    <h1>⚡ Lightning Invoice Generator</h1>

    <form id="invoice-form">
        <input type="number" id="amount" placeholder="Amount (sats)" required>
        <input type="text" id="memo" placeholder="Description" required>
        <button type="submit">Generate Invoice</button>
    </form>

    <div id="invoice-display"></div>
    <canvas id="qr-code"></canvas>

    <script>
        const LND_REST_URL = 'https://localhost:8080';
        const MACAROON = 'your_macaroon_hex_here';

        document.getElementById('invoice-form').addEventListener('submit', async (e) => {
            e.preventDefault();
            const amount = document.getElementById('amount').value;
            const memo = document.getElementById('memo').value;

            // TODO: Call LND API to create invoice
            // TODO: Display invoice and generate QR code
            // TODO: Subscribe to invoice updates
        });
    </script>
</body>
</html>

Challenge: Add support for multi-currency (USD → BTC conversion via API) and invoice expiry countdown!

Advanced Lightning Development

1. Channel Management

Programmatically manage channels:

Open Channel

lncli openchannel --node_key 03abc... --local_amt 1000000

Close Channel

lncli closechannel --funding_txid abc123 --output_index 0

List Channels

lncli listchannels

2. Keysend (Spontaneous Payments)

Send payments without an invoice (push payments):

lncli sendpayment --dest 03abc... --amt 1000 --keysend

3. Submarine Swaps

Atomic swaps between on-chain and Lightning using HTLCs. Useful for:

  • Moving funds from on-chain to Lightning
  • Withdrawing Lightning funds to cold storage
  • Trustless exchange between BTC and L-BTC

4. LNURL

Higher-level protocol for Lightning interactions:

  • LNURL-pay: Simplified payment requests
  • LNURL-withdraw: Let users withdraw from your service
  • LNURL-auth: Login with Lightning

Production Best Practices

Security

  • Never expose macaroons in client-side code
  • Use invoice macaroons (limited permissions) for invoice generation
  • Run LND behind a secure proxy with HTTPS
  • Regularly backup channel.backup file

Reliability

  • Run watchtowers to monitor for breach attempts
  • Set up monitoring and alerts for channel states
  • Maintain multiple channels for redundancy
  • Implement automatic channel rebalancing

Liquidity Management

  • Monitor inbound vs outbound liquidity
  • Use circular rebalancing to maintain balanced channels
  • Consider Loop Out/In for liquidity management
  • Open channels to well-connected routing nodes

Key Takeaways

  • Three major Lightning implementations: LND, Core Lightning, Eclair
  • LND provides gRPC, REST, and CLI interfaces for developers
  • BOLT 11 invoices encode payment requests with hash, amount, and metadata
  • Subscribe to invoice updates via WebSocket for real-time payment monitoring
  • Macaroons provide capability-based authentication for LND APIs
  • Production apps need proper security, monitoring, and backup strategies
  • Advanced features: keysend, submarine swaps, LNURL protocols
  • Liquidity management is crucial for reliable payment routing

Additional Resources