Интеграция Lightning Network платежей на сайт

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Интеграция Lightning Network платежей на сайт
Средний
~2-3 дня
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1286
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    902
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1122
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    859

Интеграция Lightning Network платежей на сайт

Lightning Network решает реальную проблему Bitcoin как платёжного средства: on-chain транзакции дорогие ($1–20 комиссии при нагрузке) и медленные (10–60 минут до достаточного числа подтверждений). LN даёт мгновенные микроплатежи за доли цента. Для e-commerce это практически применимо — если правильно интегрировать.

Ключевое решение, которое нужно принять сразу: управлять собственной LN-нодой или использовать custody сервис. Собственная нода — полный контроль, нет комиссий посредника, но нужно управлять каналами и ликвидностью. Custody (Strike, OpenNode, BTCPay Cloud) — проще, но вы доверяете третьей стороне.

Архитектура: собственная LN-нода

Для серьёзного e-commerce — LND (Lightning Network Daemon) или Core Lightning (CLN). LND более распространён, лучше документирован, активно поддерживается Lightning Labs.

Инфраструктура:

  • Bitcoin full node (Bitcoin Core) — обязательно, LND требует синхронизированной ноды
  • LND нода подключена к Bitcoin Core через ZMQ
  • PostgreSQL или bbolt для LND state (bbolt по умолчанию, PostgreSQL для high-availability)
# Минимальный lnd.conf для production
[Application Options]
alias=MyShop-LN
color=#FF6600
maxpendingchannels=5

[Bitcoin]
bitcoin.active=1
bitcoin.mainnet=1
bitcoin.node=bitcoind

[Bitcoind]
bitcoind.rpchost=localhost
bitcoind.rpcuser=bitcoinrpc
bitcoind.rpcpass=strongpassword
bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332
bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333

[protocol]
protocol.wumbo-channels=true  # каналы > 0.16 BTC

Управление каналами и ликвидностью

Это главная операционная сложность LN. Платёж проходит только если есть маршрут с достаточной ликвидностью. Для получения платежей нужна инбаунд ликвидность (входящая). Для отправки — аутбаунд (исходящая).

Клиент → [Lightning Network маршрут] → Ваша нода
                                            ↓
                                    Получить платёж — нужна inbound ликвидность

Стратегии для получения inbound ликвидности:

  1. Купить inbound через Lightning Pool (маркетплейс ликвидности от Lightning Labs)
  2. Открыть каналы с хорошо связанными нодами (ACINQ, Kraken, Bitfinex) — они откроют встречный канал
  3. Submarine swaps через Loop In (Lightning Labs Loop): отправляете on-chain BTC, получаете inbound ликвидность
// Lightning Labs Loop In для пополнения inbound ликвидности
// Использует submarine swaps: on-chain → LN
const loopdClient = new LoopClient(LOOPD_HOST)

async function increaseInboundLiquidity(amountSats: number): Promise<void> {
    const quote = await loopdClient.loopInQuote({ amt: amountSats })
    console.log(`Loop In quote: ${quote.swap_fee_sat} sats fee, ${quote.miner_fee_sat} sats miner fee`)

    await loopdClient.loopIn({
        amt: amountSats,
        max_swap_routing_fee: quote.swap_fee_sat,
        max_miner_fee: quote.miner_fee_sat,
        external_htlc: false,
    })
}

Создание инвойсов и обработка платежей

LND предоставляет gRPC API. Для Node.js — @lightningpolar/lnd или прямая работа через @grpc/grpc-js:

import { createLnRpc, createInvoicesRpc } from '@lightningpolar/lnd'

const lnRpc = await createLnRpc({
    server: 'localhost:10009',
    tls: fs.readFileSync('/home/bitcoin/.lnd/tls.cert'),
    macaroon: fs.readFileSync('/home/bitcoin/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon'),
})

interface CreateInvoiceResult {
    paymentRequest: string   // bolt11 invoice
    paymentHash: string      // для отслеживания статуса
    expiresAt: Date
}

async function createInvoice(
    amountSats: number,
    description: string,
    orderId: string,
    expirySeconds = 3600
): Promise<CreateInvoiceResult> {
    const invoice = await lnRpc.addInvoice({
        value: amountSats,
        memo: description,
        expiry: expirySeconds,
        // Кастомные данные для матчинга с заказом
        r_preimage: generatePreimage(),
    })

    // Сохраняем связь payment_hash → order_id
    await db('ln_invoices').insert({
        order_id: orderId,
        payment_hash: Buffer.from(invoice.r_hash).toString('hex'),
        payment_request: invoice.payment_request,
        amount_sats: amountSats,
        expires_at: new Date(Date.now() + expirySeconds * 1000),
        status: 'pending',
    })

    return {
        paymentRequest: invoice.payment_request,
        paymentHash: Buffer.from(invoice.r_hash).toString('hex'),
        expiresAt: new Date(Date.now() + expirySeconds * 1000),
    }
}

Отслеживание оплаты: Subscribe Invoice Stream

Не нужно поллить статус — LND предоставляет streaming RPC:

async function watchInvoicePayment(paymentHash: string): Promise<void> {
    const stream = lnRpc.subscribeInvoices({})

    stream.on('data', async (invoice) => {
        const hash = Buffer.from(invoice.r_hash).toString('hex')
        if (hash !== paymentHash) return

        if (invoice.state === 'SETTLED') {
            await db('ln_invoices')
                .where({ payment_hash: paymentHash })
                .update({ status: 'paid', paid_at: new Date(), amount_paid_sats: invoice.amt_paid_sat })

            const order = await db('ln_invoices')
                .where({ payment_hash: paymentHash })
                .select('order_id')
                .first()

            await fulfillOrder(order.order_id)
            stream.destroy()
        }

        if (invoice.state === 'CANCELED') {
            await db('ln_invoices')
                .where({ payment_hash: paymentHash })
                .update({ status: 'expired' })
            stream.destroy()
        }
    })
}

Custody альтернативы: OpenNode и BTCPay Server

Если управление нодой и ликвидностью не входит в ваши планы — два пути:

OpenNode — custody LN платёжный провайдер. REST API, webhook на оплату, автоматический settle в BTC или fiat. Берёт 1% комиссии.

async function createOpenNodeCharge(
    amountUsd: number,
    orderId: string,
    callbackUrl: string
): Promise<string> {
    const res = await fetch('https://api.opennode.com/v1/charges', {
        method: 'POST',
        headers: {
            Authorization: process.env.OPENNODE_API_KEY!,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            amount: amountUsd,
            currency: 'USD',  // конвертирует в BTC автоматически
            order_id: orderId,
            callback_url: callbackUrl,
            success_url: `${BASE_URL}/order/${orderId}/success`,
        }),
    })
    const charge = await res.json()
    return charge.data.lightning_invoice.payreq  // bolt11
}

BTCPay Server — self-hosted, открытый исходный код. Управляет LND нодой за вас, предоставляет Greenfield API, нет комиссии посредника. Деплоится через Docker за 15 минут, требует VPS с 2GB+ RAM.

UX: QR-код и WebSocket обновление

На странице оплаты: QR-код с lightning:BOLT11_INVOICE, таймер истечения, WebSocket соединение для мгновенного обновления статуса без перезагрузки страницы.

// WebSocket endpoint для статуса платежа
wss.on('connection', (ws, req) => {
    const paymentHash = new URLSearchParams(req.url?.split('?')[1]).get('hash')

    const unsubscribe = subscribeToPaymentStatus(paymentHash, (status) => {
        ws.send(JSON.stringify({ status }))
        if (status === 'paid') {
            ws.close()
            unsubscribe()
        }
    })

    ws.on('close', unsubscribe)
})

Полная интеграция со своей LND нодой: 1 неделя (включая настройку ноды, channel management, фронтенд). С BTCPay Server: 2-3 дня. С OpenNode API: 1-2 дня.