Nostr Wallet Connect (NWC): «USB-C» для биткоин-кошельков

Идея. Nostr Wallet Connect (NWC) — это протокол (NIP-47), позволяющий приложениям безопасно управлять Lightning-кошельком пользователя через сеть Nostr-релеев. По аналогии с «USB-C» NWC даёт единый «штекер» между кошельком и огромным числом приложений: от клиентов Nostr до сайтов с «запами», подписок и paywall. Пользователь один раз подключает кошелёк (сканирует URI/QR), после чего приложение может запрашивать платёж, выпуск инвойса, баланс и историю — с теми ограничениями, которые задал сам пользователь.

NWC работает с Lightning (LN)-операциями. Он не предполагает прямых L1-биткоин-транзакций, но может сосуществовать с ними в одном кошельке.

Nostr Wallet Connect (NWC) - «USB-C» для биткоин-кошельков

Как это устроено (по шагам)

  • Кто есть кто.
    1. Клиент — приложение (веб/мобильное/настольное), которому нужно отправить платёж или выписать счёт.
    2. Wallet service — сервис-мост, у которого есть доступ к API кошелька/ноды пользователя и который говорит с клиентом по Nostr.
    3. Релей — Nostr-узел(ы), через который клиент и wallet service обмениваются шифрованными событиями.
  • Подключение.
    1. Кошелёк выдаёт URI-строку вида nostr+walletconnect://?relay=wss://...&secret=<32-byte hex>[&lud16=...].
    2. Приложение получает URI (скан QR/вставка), сохраняет его и использует при любых действиях.
  • Обмен сообщениями (события Nostr).
    1. Info: кошелёк публикует replaceable событие kind 13194 с перечнем поддерживаемых команд и шифрования.
    2. Request: клиент шлёт зашифрованный запрос kind 23194 (например, pay_invoice).
    3. Response: кошелёк отвечает kind 23195 (успех/ошибка + результат).
    4. Notifications: кошелёк может присылать уведомления kind 23197 (или 23196 для старых клиентов), например payment_received.
  • Шифрование и ключи.
    1. Контент запросов/ответов E2E-зашифрован (рекомендуется NIP-44 v2, для старых клиентов поддерживается NIP-04).
    2. Для приватности используется отдельная пара ключей на каждое подключение; основной Nostr-ключ пользователя не светится.
Релеи для NWC лучше выбирать «устойчивые к простоям» (не закрывают соединение по неактивности и хранят события до их потребления). Кастодиальные/хаб-кошельки часто используют собственные релеев.

URI подключения

Формат: nostr+walletconnect://?relay=[&relay=<...>]&secret=<32b_hex>[&lud16=]

  • relay — один или несколько wss-адресов релеев, где слушает wallet service.
  • secret — 32-байтный секрет клиента, из которого выводится его pubkey; именно эта пара ключей используется для шифрования/подписи обмена.
  • lud16 — опционально, Lightning-адрес пользователя (для автозаполнения профиля в некоторых клиентах).
В экосистеме встречается короткая схема nwc:..., но каноническая в NIP-47 — nostr+walletconnect://....

Команды NWC (ядро NIP-47)

Команда Назначение Важные поля/заметки
pay_invoice Оплатить BOLT11-инвойс invoice (строка), опц. amount в msat, metadata (комментарий/плательщик)
multi_pay_invoice Пакет платежей по нескольким инвойсам Атомарности нет: обрабатываются по одному; таймауты/лимиты учитывайте
pay_keysend Платёж без инвойса (keysend) Требует поддержки у кошелька/ноды
multi_pay_keysend Пакет keysend Как выше
make_invoice Выписать инвойс (запрос на приём) Сумма, описание, срок годности
lookup_invoice Узнать статус по хешу платежа/инвойса Для трекинга/погашения
list_transactions Получить список платежей/инвойсов Разбивайте на страницы; крупные ответы релеем могут быть отвергнуты
get_balance Узнать баланс канала/кошелька Обычно в msat
get_info Метаданные кошелька/ноды и поддерживаемые особенности Версия, методы, поддержка уведомлений, шифрования

Ошибки (поля ответа): RATE_LIMITED, NOT_IMPLEMENTED, INSUFFICIENT_BALANCE, QUOTA_EXCEEDED, RESTRICTED, UNAUTHORIZED, INTERNAL.

Бюджеты, автоплатежи и разрешения

Хотя лимиты не «зашиты» жёстко в протокол, кошельки часто позволяют для каждого соединения задать:

  • Бюджет (например, «до 100k сат/мес» или «до 5k сат/день»).
  • Порог автоплатежа (суммы, которые можно оплачивать без подтверждения).
  • Срок действия/квоты (истекает, требуется продление).
  • Список разрешённых методов (например, запрет list_transactions).
Это снижает риск переплат и делает подписки/микроплатежи удобнее: приложение отправляет запрос — кошелёк решает локально, нужно ли ручное подтверждение, и соблюдает бюджет.

Потоки «на пальцах»

Оплата инвойса (zap, донат, покупка): 1) Клиент формирует pay_invoice и шлёт запрос 23194 на указанные в URI релеев. 2) Wallet service проверяет лимиты/разрешения и исполняет платёж в кошельке. 3) Возвращает response 23195 (успех/ошибка) и, при желании, присылает уведомление payment_sent.

Выписать счёт (приём платежа): 1) Клиент вызывает make_invoice (сумма/описание). 2) В ответ получает BOLT11 и (опционально) ждёт уведомление payment_received.

Подписка/повторяющиеся платежи: 1) Кошелёк/пользователь заранее устанавливает бюджет и пороги автоплатежей для соединения. 2) Приложение периодически отправляет pay_invoice — кошелёк списывает в рамках бюджета, не беспокоя пользователя.

Безопасность и приватность

  • Раздельные ключи на соединение. Не используйте основной Nostr-ключ. Удобно отзывать/регенерировать подключение без влияния на другие.
  • Шифрование контента. Предпочтительно NIP-44 v2; поддерживайте NIP-04 для «старых» клиентов. Проверяйте тег encryption в событиях.
  • Дедлайны. Запросы могут нести expiration — игнорируйте просроченные.
  • Релеи. Для кастодиальных сценариев уместен собственный релей; публичные релеевы видят метаданные (виды событий/теги), но не расшифровку.
  • Rate limiting и квоты. Сторона кошелька применяет антиспам и QUOTA_EXCEEDED на уровне соединения.
  • Разрешения по методам. Ограничивайте list_transactions/get_info, если приложение их не требует.
  • Отзыв. Любое соединение можно отключить/удалить из кошелька; храните журнал подключений.

Сравнение с альтернативами

Решение Как работает Плюсы Минусы
NWC (Nostr, NIP-47) Зашифрованный обмен через релеев, кошелёк «на проводе» Кроссплатформенно, оффлайн-устойчиво, бюджеты/автоплатежи, не нужен браузерный API Нужен релей и постоянно доступный wallet service
WebLN JS-API в браузере (расширение/встроенный кошелёк) Простой UX на вебе Привязан к браузеру/расширению, слабее вне веба
LNURL / Lightning Address HTTP-вызовы/адреса для pay/withdraw Массово поддерживается, удобно для разовых платежей Нет постоянной «связки» и бюджетов; авторизация иначе решается

Быстрый старт разработчикам

Подключение клиента

1) Получите от пользователя NWC-URI (скан QR).

2) Сохраните: wallet_pubkey, список relay, client_secret.

3) Скачайте и распарсьте Info (kind 13194) кошелька: методы, шифрование.

4) Для действия сформируйте JSON-контент: { «method»: «pay_invoice», «params»: { «invoice»: «…», «amount»: 123 } }

5) Зашифруйте контент (nip44_v2) и опубликуйте как kind 23194 с тегом [«p»,

<wallet_pubkey>].

6) Подпишитесь на ответы (kind 23195) и уведомления (23197) от кошелька.

Рекомендации

  • Держите выделенный релей или убедитесь, что выбранные релеевы не дропают «тихие» соединения.
  • Делайте идемпотентность запросов (повторы при сетевых помехах).
  • Пагинируйте list_transactions (не больше ~20 записей за страницу).
  • Учитывайте таймауты инвойсов и показывайте пользователю статусы (отправлено/в пути/погашено).
  • Покрывайте «узкие места» тестами: нестабильный релей, долгий ответ ноды, частичный отказ.
Частые вопросы (FAQ)

Это «кошелёк-как-API», не слишком ли опасно? Соединение выдаётся пользователем, ограничивается бюджетами и перечнем методов, использует отдельный ключ и может быть отозвано в один клик.

Как NWC относится к «запам» в Nostr? Отправка запов — это обычный Lightning-платёж. Клиент формирует pay_invoice и шлёт через NWC; кошелёк платит в рамках разрешений.

Можно ли принимать платежи через NWC? Да, командой make_invoice (иногда с метаданными для комментариев/привязки к контенту). Дальше — уведомление payment_received.

Нужен ли свой релей? Не обязательно. Но для кастодиальных/хаб-сервисов собственный релей повышает приватность и устойчивость.

Чем полезны уведомления? payment_received/payment_sent позволяют приложениям не опрашивать кошелёк. Для совместимости старых клиентов кошельки иногда дублируют уведомления в двух шифрованиях.

Чек-лист для внедрения
  • Используйте уникальные ключи на каждое соединение; не переиспользуйте основной Nostr-ключ.
  • Реализуйте бюджеты и пороги автоплатежей; показывайте пользователю остаток и период.
  • Поддержите NIP-44 v2 (и fallback NIP-04) + тег encryption в событиях.
  • Настройте rate limiting и понятные ошибки (QUOTA_EXCEEDED, RATE_LIMITED).
  • Пагинируйте большие ответы (list_transactions) и проверяйте лимиты полезной нагрузки релея.
  • Предусмотрите отзыв/ротацию подключений в один клик (UI кошелька).
  • Документируйте поддержанные методы в Info (13194) и обновляйте его как replaceable-событие.
См. также
Task Runner