Интеграция с Eclair (Lightning)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Интеграция с Eclair (Lightning)
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Интеграция с Eclair (Lightning)

Eclair — реализация Lightning Network на Scala от ACINQ. В отличие от LND с его монолитной архитектурой, Eclair строго следует BOLT спецификациям и известен производственной надёжностью: на нём работает Phoenix wallet (мобильный Lightning кошелёк ACINQ) и несколько крупных сервисов. Если ваш стек JVM-based или вы уже работаете с ACINQ экосистемой — это естественный выбор.

Запуск и конфигурация

Требования

Eclair требует Bitcoin Core ноды для доступа к blockchain данным. Нейтрино (упрощённый режим) Eclair не поддерживает — нужна полная нода.

eclair.conf (Typesafe Config формат):

eclair {
  chain = "mainnet"
  server.port = 9735
  api.enabled = true
  api.port = 8080
  api.password = "your-api-password"
  
  bitcoind {
    host = "localhost"
    rpcport = 8332
    rpcuser = "bitcoinrpc"
    rpcpassword = "rpcpassword"
    zmqblock = "tcp://127.0.0.1:28334"
    zmqtx = "tcp://127.0.0.1:28335"
  }
  
  # Политика комиссий для routing
  router.path-finding.default.max-fee-flat-sat = 21
  router.path-finding.default.max-fee-proportional = 0.01 // 1%
  
  # Лимиты каналов
  max-htlc-value-in-flight-msat = 100000000000  // 1 BTC в msat
}

HTTP API: основные операции

Eclair предоставляет REST API (form-encoded POST запросы, не JSON body — это часто вызывает путаницу):

# Информация о ноде
curl -u :your-password http://localhost:8080/getinfo

# Открыть канал
curl -u :your-password http://localhost:8080/open \
  -d nodeId=<peer_pubkey> \
  -d fundingSatoshis=1000000 \
  -d pushMsat=0

# Создать invoice
curl -u :your-password http://localhost:8080/createinvoice \
  -d description="Payment for order 123" \
  -d amountMsat=50000000 \
  -d expireIn=3600
  
# Отправить платёж
curl -u :your-password http://localhost:8080/payinvoice \
  -d invoice=lnbc500u1p... \
  -d blocking=true

TypeScript клиент

import axios from "axios";
import FormData from "form-data";

class EclairClient {
  private readonly http = axios.create({
    baseURL: `http://${this.host}:${this.port}`,
    auth: { username: "", password: this.password },
  });

  async createInvoice(params: {
    amountMsat: number;
    description: string;
    expireIn?: number;
  }): Promise<{ serialized: string; paymentHash: string }> {
    const form = new FormData();
    form.append("amountMsat", params.amountMsat.toString());
    form.append("description", params.description);
    if (params.expireIn) form.append("expireIn", params.expireIn.toString());

    const { data } = await this.http.post("/createinvoice", form, {
      headers: form.getHeaders(),
    });
    return data;
  }

  async payInvoice(invoice: string, maxFeeMsat?: number): Promise<PaymentResult> {
    const form = new FormData();
    form.append("invoice", invoice);
    form.append("blocking", "true"); // ждём результата
    if (maxFeeMsat) form.append("maxFeeFlatMsat", maxFeeMsat.toString());

    const { data } = await this.http.post("/payinvoice", form, {
      headers: form.getHeaders(),
    });
    return data;
  }

  async getPayment(paymentHash: string): Promise<PaymentStatus> {
    const form = new FormData();
    form.append("paymentHash", paymentHash);
    const { data } = await this.http.post("/getsentinfo", form, {
      headers: form.getHeaders(),
    });
    return data[0];
  }
}

WebHooks: real-time события

Eclair поддерживает WebHook нотификации о событиях — это основной способ реагировать на входящие платежи без polling:

// eclair.conf
eclair.api.webhooks = [
  {
    id = "my-backend"
    url = "https://your-backend.com/eclair/webhook"
    secret = "webhook-secret-for-hmac"
  }
]

Типы событий:

type EclairEvent =
  | { type: "payment-received"; paymentHash: string; amount: number; timestamp: number }
  | { type: "payment-sent"; paymentHash: string; amount: number; feesPaid: number }
  | { type: "payment-failed"; paymentHash: string; failures: string[] }
  | { type: "channel-opened"; channelId: string; remotePubkey: string; capacity: number }
  | { type: "channel-closed"; channelId: string; reason: string };

Обработчик webhook с верификацией подписи:

app.post("/eclair/webhook", (req, res) => {
  const signature = req.headers["x-eclair-hmac"];
  const expectedSig = createHmac("sha256", WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest("hex");

  if (signature !== expectedSig) {
    return res.status(401).send("Invalid signature");
  }

  const event: EclairEvent = req.body;

  if (event.type === "payment-received") {
    handleIncomingPayment(event.paymentHash, event.amount);
  }

  res.sendStatus(200);
});

Особенности Eclair по сравнению с LND

BOLT-12 поддержка — Eclair реализует BOLT-12 Offers раньше и полнее, чем LND. Если вам нужны reusable payment codes или offline платёжные схемы — Eclair преимущество.

Trampoline routing — механизм делегирования pathfinding на промежуточный узел. Критично для мобильных клиентов (Phoenix использует это): лёгкий клиент не хочет хранить полный граф сети. Eclair — одна из немногих реализаций с production поддержкой Trampoline.

# Отправить через trampoline
curl -u :password http://localhost:8080/payinvoice \
  -d invoice=lnbc... \
  -d trampolineNodeId=<trampoline_pubkey> \
  -d blocking=true

API стиль: form-encoded вместо JSON. Это не баг, это design decision. Генерировать form data из существующих JSON структур — одна лишняя строка.

Metrologia: Eclair экспортирует метрики через встроенный Kamon instrumentation. Prometheus endpoint включается конфигурацией:

kamon.prometheus.embedded-server.port = 9095

Типичные сценарии интеграции

Merchant платежи

  1. Пользователь выбирает "оплата Lightning" → POST /createinvoice → QR код / BOLT-11 строка
  2. Webhook payment-received → обновить статус заказа в БД
  3. Дублирующий polling через /getreceivedinfo для надёжности (на случай missed webhook)

Массовые выплаты

async function bulkPayout(payments: { invoice: string; maxFeeMsat: number }[]) {
  const results = await Promise.allSettled(
    payments.map((p) => eclairClient.payInvoice(p.invoice, p.maxFeeMsat))
  );

  const failed = results
    .map((r, i) => ({ result: r, payment: payments[i] }))
    .filter((r) => r.result.status === "rejected");

  // Логируем ошибки, retry с exponential backoff
  for (const { payment, result } of failed) {
    logger.error("Payment failed", { invoice: payment.invoice, reason: result });
  }
}

Канальная политика для routing ноды

Eclair позволяет устанавливать индивидуальные fee политики на канал:

# Обновить политику для конкретного канала
curl -u :password http://localhost:8080/updaterelayfee \
  -d channelId=<channel_id> \
  -d feeBaseMsat=1000 \
  -d feeProportionalMillionths=100  # 0.01%

Мониторинг production ноды

Ключевые метрики для Eclair:

  • channels.count по состоянию (NORMAL, CLOSING, OFFLINE)
  • payment.sent.success_rate — % успешных исходящих платежей
  • payment.received.count / amount — входящий поток
  • router.graph.nodes и channels — размер сети виден ноде

Grafana дашборд с этими метриками — стандартная операционная необходимость для любой Lightning ноды с более чем несколькими каналами.

Срок интеграции Eclair в существующий backend (прием и отправка платежей, webhook обработка, мониторинг): 3–5 недель.