LNURL — семейство процедур, по которым Lightning-кошелёк и веб-сервис обмениваются данными для определённой задачи. Lightning используют для быстрых платежей в биткоинах; счёт в этой сети — запрос на оплату с данными, нужными кошельку для платежа. Из ссылки кошелёк узнаёт, нужно ли подготовить платёж, получить выводимые средства или подтвердить вход. Сама ссылка ещё не является счётом или доказательством поступления денег.
Представьте Анну, которая сканирует код для поддержки автора, затем код для получения денег по ваучеру и, наконец, код входа на сайт. Телефоном она пользуется одинаково, но каждый раз разрешает другое действие. LNURL различает эти задачи: payRequest означает оплату, withdrawRequest — вывод средств, login — вход. Отдельные процедуры описаны в документах LUD. Это необязательные соглашения между приложениями, а не изменения правил Bitcoin. Поддержка одной процедуры не означает, что кошелёк умеет работать со всеми остальными. [1] [7]
При payRequest сервис возвращает описание и допустимый диапазон сумм. Анна проверяет домен — веб-адрес сервиса, читает описание и выбирает сумму. После согласия с условиями кошелёк запрашивает конкретный Lightning-счёт BOLT 11 и перед оплатой сверяет его сумму с выбранной. Для этого служат адрес callback, пределы minSendable и maxSendable и описание metadata; сумма передаётся как amount, а счёт приходит в pr. Суммы выражены в msat, тысячных долях satoshi: 1000 msat = 1 sat. Один публичный QR может служить разным людям, но его сканирование не подтверждает оплату. [3]
В withdrawRequest направление меняется. Анна хочет вывести остаток из сервиса, а не заплатить ему. Поэтому её кошелёк создаёт счёт на получение денег, который должен оплатить сервис. Тот сообщает идентификатор k1, адрес callback и пределы minWithdrawable и maxWithdrawable в msat; после согласия кошелёк передаёт счёт в pr. Ответ OK означает, что сервис принял запрос, а не что Анна уже получила деньги. Кошелёк продолжает ждать поступления. Код вывода может работать как ваучер для любого, кто им владеет, поэтому его нельзя публиковать как обычный контакт для приёма платежей. [4]
На другом сайте Анна выбирает LNURL-auth. Кошелёк показывает домен и назначение запроса с tag login. С её согласия он подписывает одноразовый проверочный запрос k1 закрытым ключом для этого домена, linkingPrivKey. Сервис получает подпись и соответствующий открытый ключ linkingKey, с помощью которого можно проверить подпись. Закрытый ключ ему не передаётся. Сервис может узнать вернувшегося владельца ключа, но сама проверка не раскрывает его реальную личность. Кошелёк не передаёт сервису seed — исходное секретное значение для выведения ключей — или Seed Phrase, то есть слова восстановления. Технически используется подпись ECDSA на кривой secp256k1. Поле action может означать регистрацию, вход, привязку учётной записи или другую авторизацию, поэтому стоит читать подтверждение целиком. Подпись этого запроса сама по себе не является биткоин-платежом. [5]
Запрос, ответ сервиса и реальное движение денег — отдельные этапы. Потеряв соединение, Анна сначала проверяет исходный платёж в кошельке. Ещё одна попытка с новым счётом может привести к ещё одному платежу. Необязательная процедура LUD-21 добавляет адрес verify для проверки конкретного счёта: settled true сообщает о расчёте, settled false — о пока не оплаченном счёте. Одного OK недостаточно. Ответ может содержать preimage — исходное секретное значение, связанное с платежом. Кошелёк вычисляет из него хеш, то есть контрольное значение, и сравнивает его с хешем платежа в нужном счёте. Произвольного секретного значения недостаточно: оно должно соответствовать именно этому платежу. Проверка результата не обеспечивает доступность сервиса или входящую ликвидность — возможность направить деньги в кошелёк получателя. [6] [3] [4]
HTTPS защищает передачу между кошельком и сервисом, но не от самого сервиса. Тот может наблюдать запросы, время их отправки и повторное использование. При входе также важно полное доменное имя: смена поддомена может дать другой linkingKey, и сайт увидит другого пользователя. Переход в иной кошелёк тоже не гарантирует восстановления того же входа, поскольку приложения по-разному выводят ключи. Перед важным изменением проверьте восстановление доступа именно к этой учётной записи. LNURL не определяет, кто хранит ключи для распоряжения биткоинами; это зависит от кошелька и сервиса. [2] [5]
Базовая процедура LUD-01 представляет HTTPS или onion URL в формате Bech32. Это кодирование, а не шифрование адреса и не счёт BOLT 11. Кошелёк читает tag прямо из ссылки либо выполняет веб-запрос GET за данными и узнаёт тип операции из ответа JSON. Этот формат задаёт данным имена и структуру, понятные приложению. Поэтому изображение QR само по себе не устанавливает личность получателя. Важны содержимое ссылки и затем показанные домен, действие и условия. [2]
В процедуре оплаты metadata — текстовая строка, содержащая массив JSON. В нём обязательно описание text/plain; остальные типы необязательны. Кошелёк должен показать описание вместе с доменом и суммой, чтобы человек понимал, на что соглашается. Базовый LNURL интерпретирует JSON-тело ответа, а не только код состояния HTTP. Доступный сервер ещё не означает успешного запроса: в ответе может быть ERROR. Аналогично счёт, полученный в pr, ещё не оплачен. Приложение не должно сводить эти разные сведения к одной зелёной галочке. [2] [3]
Для полной картины прочитайте эту статью вместе с BOLT 11, BOLT 12, Lightning Network, Lightning Address, Приватность в Bitcoin, Satoshi. На эту статью также ссылаются BOLT 12, Lightning Address, Confirmo.