Идея. Nostr Wallet Connect (NWC) — это протокол (NIP-47), позволяющий приложениям безопасно управлять Lightning-кошельком пользователя через сеть Nostr-релеев. По аналогии с «USB-C» NWC даёт единый «штекер» между кошельком и огромным числом приложений: от клиентов Nostr до сайтов с «запами», подписок и paywall. Пользователь один раз подключает кошелёк (сканирует URI/QR), после чего приложение может запрашивать платёж, выпуск инвойса, баланс и историю — с теми ограничениями, которые задал сам пользователь.
NWC работает с Lightning (LN)-операциями. Он не предполагает прямых L1-биткоин-транзакций, но может сосуществовать с ними в одном кошельке.
Как это устроено (по шагам)
- Кто есть кто.
- Клиент — приложение (веб/мобильное/настольное), которому нужно отправить платёж или выписать счёт.
- Wallet service — сервис-мост, у которого есть доступ к API кошелька/ноды пользователя и который говорит с клиентом по Nostr.
- Релей — Nostr-узел(ы), через который клиент и wallet service обмениваются шифрованными событиями.
- Подключение.
- Кошелёк выдаёт URI-строку вида nostr+walletconnect://
?relay=wss://...&secret=<32-byte hex>[&lud16=...] . - Приложение получает URI (скан QR/вставка), сохраняет его и использует при любых действиях.
- Обмен сообщениями (события Nostr).
- Info: кошелёк публикует replaceable событие kind 13194 с перечнем поддерживаемых команд и шифрования.
- Request: клиент шлёт зашифрованный запрос kind 23194 (например, pay_invoice).
- Response: кошелёк отвечает kind 23195 (успех/ошибка + результат).
- Notifications: кошелёк может присылать уведомления kind 23197 (или 23196 для старых клиентов), например payment_received.
- Шифрование и ключи.
- Контент запросов/ответов E2E-зашифрован (рекомендуется NIP-44 v2, для старых клиентов поддерживается NIP-04).
- Для приватности используется отдельная пара ключей на каждое подключение; основной Nostr-ключ пользователя не светится.
Релеи для NWC лучше выбирать «устойчивые к простоям» (не закрывают соединение по неактивности и хранят события до их потребления). Кастодиальные/хаб-кошельки часто используют собственные релеев.
URI подключения
Формат:
nostr+walletconnect://
- 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 записей за страницу).
- Учитывайте таймауты инвойсов и показывайте пользователю статусы (отправлено/в пути/погашено).
- Покрывайте «узкие места» тестами: нестабильный релей, долгий ответ ноды, частичный отказ.
Это «кошелёк-как-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-событие.
