Інтеграція з LND (Lightning Network Daemon)
Lightning Network вирішує конкретну проблему Bitcoin: on-chain транзакції коштують грошей та вимагають підтверджень. LND (Lightning Network Daemon від Lightning Labs) — найпоширеніша реалізація LN-ноди. Інтеграція з LND потребується коли хочуть приймати миттєві Bitcoin-платежі з комісією в кілька сатоші, або будувати додаток поверх Lightning. Це не «підключити API» — це запустити та утримувати платіжну інфраструктуру.
Що таке LND та як він працює
LND — це програмний вузол Lightning Network. Для роботи потребує:
- Синхронізованої Bitcoin ноди (Bitcoind або
neutrinolight mode) - Відкритих payment channels з партнерами в мережі
- Liquidity management: на вашій стороні каналу повинні бути кошти для вихідних платежів, на протилежній — для вхідних
Payment channels — це 2-of-2 multisig контракти на Bitcoin L1. LND управляє станом каналів off-chain, публікуючи в блокчейн тільки при відкритті та закритті.
Invoice-based платежі. Отримувач створює invoice (BOLT-11 счёт), плацьник його оплачує. Invoice містить payment hash — HTLC-механізм гарантує атомарність.
Підключення до LND: gRPC vs REST
LND надає два API: gRPC (основний, повний) та REST (обертка). Для production — gRPC.
Аутентифікація через TLS-сертифікат + macaroon (capability-based токен):
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');
// Створюємо channel з 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 — не просто токен, це capability-based авторизація. Можна створити invoice.macaroon (тільки створення счётів), readonly.macaroon (тільки читання), кастомний з обмеженнями по IP та часу. Не давайте admin.macaroon додаткам — тільки мінімально необхідні права.
Основні операції
Створення invoice (приём платежу)
function addInvoice(amountSats: number, memo: string): Promise<Invoice> {
return new Promise((resolve, reject) => {
lightning.AddInvoice({
value: amountSats, // сума в сатоші
memo, // опис (видно плацьнику)
expiry: 3600, // строк дії в секундах
}, (err: any, response: any) => {
if (err) reject(err);
else resolve({
paymentRequest: response.payment_request, // BOLT-11 рядок
rHash: response.r_hash.toString('hex'), // payment hash
addIndex: response.add_index.toString(),
});
});
});
}
BOLT-11 рядок починається з lnbc (mainnet) або lntb (testnet). Це те що користувач сканує гаманцем.
Відслідковування вхідних платежів
Два підходи:
Polling — LookupInvoice по r_hash. Просто, але не оптимально.
Streaming subscriptions — SubscribeInvoices стримить всі оновлення в реальному часі:
function subscribeInvoices(onSettled: (invoice: SettledInvoice) => void) {
const stream = lightning.SubscribeInvoices({
settle_index: 0, // з початку, або з конкретного індекса для catch-up
});
stream.on('data', (invoice: any) => {
if (invoice.state === 1) { // SETTLED = оплачено
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 логіка
setTimeout(() => subscribeInvoices(onSettled), 5000);
});
}
Важливо: персистивна settle_index. При перезапуску додатку підписуйтесь з останнього обробленого settle_index, інакше пропустите платежі отримані під час downtime.
Вихідні платежи
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_parts: 4, // MPP: розбити на кілька частин якщо потребується
});
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) переважніший за старий SendPayment — підтримує MPP (Multi-Path Payments), краще обробляє помилки.
Liquidity management
Це операційна задача яка ніколи не закінчується. Проблеми:
Inbound liquidity. Для приёму платежів потребується ліквідність на стороні партнера каналу. Нова нода часто не може приймати платежи. Рішення:
- Lightning Service Providers (Bitrefill Thor, Loop In, Amboss Magma) — платна оренда inbound
- Відкрити канал навстріч: попросити партнера відкрити канал до вас
Channel rebalancing. Зі часом канали «перекашуються» — всі кошти на одній стороні. lnd loop out — submarine swap для ребалансування: виводить Lightning кошти в on-chain, перерозподіляє. Використовується автоматично інструментами типу charge-lnd або bos (Balance of Satoshis).
Fee policy. За маршрутизацію чужих платежів через вашу ноду взимається base_fee + fee_rate. Правильна настройка комісій впливає на ефективність маршрутизації.
LNURL та інтеграція з гаманцями
LNURL — протокол розширень поверх LN. Ключові типи:
LNURL-pay — користувач сканує QR, гаманець автоматично запитує invoice потрібного номіналу. Не потребує знати суму заздалегідь:
// Backend endpoint для 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; // у msats
const invoice = await createInvoice(Number(amount) / 1000);
res.json({ pr: invoice.paymentRequest, routes: [] });
});
Lightning Address — людиночитаний адрес вида [email protected]. Реалізується через LNURL-pay endpoint на /.well-known/lnurlp/{username}.
LNURL-withdraw — дозволяє користувачу отримати кошти через LN. Застосування: виплати, кешбак.
Що входить в інтеграцію
Стандартна інтеграція з LND: настройка або підключення до існуючої LND-ноди, gRPC клієнт з TLS + macaroon аутентифікацією, створення invoice, підписка на вхідні платежи з персистентною settle_index, обробка вихідних платежів, LNURL-pay endpoint (по необхідності), базова обробка помилок та reconnect логіка.
Операційна частина (channel management, liquidity) — окремий питання, залежить від масштабу платіжного потоку.
Сроки: 1-2 тижні для backend інтеграції в існуючий додаток.







