У Kaspa нет поля для заметок. Когда транзакция попадает в блокчейн, она содержит входы, выходы, подпись — и больше ничего. Нет места, куда можно прикрепить номер заказа, email клиента или идентификатор счёта.
Для мерчанта или проекта, принимающего KAS, это порождает конкретную инженерную задачу: как сопоставить входящий платёж с нужным заказом, не получая доступа к приватным ключам покупателя?
Ответ — трёхчастный паттерн: выводить уникальный адрес для каждого заказа из xpub, отслеживать поступления в наборе UTXO и подтверждать через DAA-оценку. Это тот самый паттерн, который мы заложили в нашу платёжную инфраструктуру, когда добавили KAS как канал оплаты. Он не требует кастодиального кошелька, стороннего процессора или доверия — только к ноде Kaspa, которую вы запускаете сами.
Проблема атрибуции
Расширенный публичный ключ (xpub) — это публичная половина HD-кошелька (иерархически-детерминированного). Он позволяет выводить неограниченную последовательность дочерних публичных ключей — и, соответственно, адресов — не раскрывая ни одного приватного ключа. Соответствующее дерево приватных ключей выводится из единого сида, который хранится отдельно.
В Bitcoin мерчанты иногда используют один адрес и сопоставляют платежи по сумме или времени. Это быстро ломается: суммы пересекаются, кошельки группируют транзакции, а сетевые задержки вносят неопределённость. Скорость Kaspa в десять блоков в секунду делает привязку по времени ещё менее надёжной.
Надёжный подход — один адрес на счёт. Поскольку каждый адрес — это уникальный дочерний индекс xpub, сопоставление однозначно: платёж пришёл на индекс 42 → это заказ №42.
Для генерации адреса приватный ключ не нужен. Достаточно одного только xpub.
Пошаговый алгоритм: платёжный поток
1. Выводим следующий адрес
Когда покупатель инициирует оплату, сервер читает из базы монотонно возрастающий счётчик (deriv_index) и выводит следующий дочерний публичный ключ из xpub. Стандартный подход следует конвенциям BIP-44:
child_pubkey = derive_child(xpub, index)
address = kaspa_p2pk_address(child_pubkey)
Сервер инкрементирует счётчик и сохраняет адрес вместе с записью заказа. Приватный ключ ему не нужен — достаточно одного xpub, который является артефактом только для чтения.
Это тот же класс HD-деривации, который лежит в основе зашифрованного профиля Desk в Kaspa Forge — другая строка разделения доменов, та же базовая математика. Для платёжных адресов стандартный путь xpub работает напрямую; для специфических ключей инструментов мы добавляем доменный префикс, чтобы предотвратить повторное использование ключей в разных контекстах.
2. Показываем страницу оплаты
Ответ содержит сгенерированный адрес, ожидаемую сумму в KAS и URI kaspa::
kaspa:kaspa:qz{...}?amount=328.39
Клиент рендерит QR-код из этого URI. Обратный отсчёт показывает оставшееся время действия — мы используем 20 минут. Страница начинает опрашивать эндпоинт статуса с коротким интервалом.
3. Фиксируем курс обмена
Kaspa торгуется на открытых рынках, поэтому курс KAS/USD может колебаться в течение окна оплаты. Сервер фиксирует курс в момент создания заказа (бесплатный эндпоинт CoinGecko с хардкодным запасным вариантом) и добавляет буфер волатильности — обычно 2% — чтобы покрыть разницу между котировкой и подтверждением.
expected_sompi рассчитывается единожды и замораживается:
expected_sompi = ceil($price × 1.02 / rate_usd × 100_000_000)
Это число сохраняется вместе с заказом и никогда не пересчитывается. Покупатель видит фиксированную сумму в KAS.
4. Следим за набором UTXO
Фоновый процесс опрашивает UTXO-индекс ноды Kaspa для всех активно отслеживаемых адресов. Цикл прост:
every N seconds:
utxos = node.getUtxosByAddresses(active_addresses)
for each monitored order:
received = sum(utxo.amount for utxo in utxos[order.address])
if received >= order.expected - tolerance:
→ fire signed callback
Мы выбрали опрос (getUtxosByAddresses с включённым utxoindex) вместо wRPC-подписки. Опрос устойчивее к переподключениям — если соединение наблюдателя с нодой обрывается и восстанавливается, следующий цикл опроса автоматически догоняет. Подписка может молча пропустить события в окне разрыва. Для платёжной системы пропуск поступления хуже, чем небольшая задержка от опроса.
Это тот же паттерн источника данных, который использует автономный наблюдатель Kaspa Safe для мониторинга хранилищ — другая логика срабатывания, тот же UTXO-индекс.
5. Считаем подтверждения
Kaspa использует DAA-оценку вместо простого счётчика высоты блоков. DAA (Difficulty Adjustment Algorithm) работает в окне 2 641 блока и производит монотонно возрастающую оценку, учитывающую как синие, так и объединённые красные блоки.
Чтобы посчитать подтверждения для платёжной транзакции:
confirmations = virtual_daa_score - tx_accepting_block_daa_score
Настраиваемый порог управляет отправкой коллбэка. При 10 блоках в секунду даже щедрое количество подтверждений разрешается за секунды. Мерчант может настроить это — больше подтверждений для крупных заказов, меньше для рутинных.
6. Обрабатываем частичные платежи
UTXO-модель Kaspa здесь помогает. Один адрес может накапливать поступления от нескольких транзакций, и наблюдатель суммирует все непотраченные выходы. Если покупатель отправил 200 KAS при ожидаемых 328:
{
"status": "partial",
"received_sompi": 20000000000,
"expected_sompi": 32839000000,
"shortfall_sompi": 12839000000
}
Страница оплаты показывает: «Оплачено 200 KAS — отправьте ещё 128.39 на тот же адрес.» Как только общая сумма достигает порога с достаточным количеством подтверждений, коллбэк срабатывает, и заказ завершается.
Деталь реализации: курс обмена фиксируется при первом поступлении, а не при создании заказа. Если покупатель отправляет частичный платёж, курс уже заморожен — заказ не истекает, пока он собирает остальное. Только заказы, не получившие ни одного поступления, истекают по таймеру.
7. Отправляем HMAC-коллбэк
Когда received ≥ expected − tolerance и confirmations ≥ threshold, наблюдатель отправляет подписанный HMAC HTTP POST в сервис управления заказами:
POST /api/kaspa/paid
{
"order_id": "...",
"address": "kaspa:qz{...}",
"txid": "abc123...",
"received_sompi": 32839000000,
"daa_score": 12345678
}
Authorization: HMAC-SHA256(body, shared_secret)
Принимающий сервис проверяет HMAC, переводит заказ в статус confirmed и запускает исполнение — в нашем случае это генерация лицензионного ключа и его отправка по email. Коллбэк идемпотентен по order_id; наблюдатель повторяет попытку при временных сбоях, но не отправляет повторно при успехе.
Как Kaspa Forge использует этот паттерн
Наша платёжная архитектура разделена на два сервиса на двух отдельных машинах:
- kaspa-gateway — располагается рядом с нодой Kaspa. Хранит xpub, генерирует адреса, запускает UTXO-наблюдатель и отправляет подписанные коллбэки. Он никогда не видит деталей заказа, кроме «отслеживай этот адрес на эту сумму».
- Сервис заказов — сервис заказов и исполнения. Запрашивает адреса, сохраняет заказы и завершает их при подтверждении оплаты. Он никогда не видит xpub и никаких приватных ключей.
Разделение намеренное: gateway — единственный сервис, который взаимодействует с криптологией, специфичной для Kaspa. Если сервис заказов скомпрометирован, злоумышленник не получает ни ключей, ни xpub — только публичные адреса и коллбэки, проверенные через HMAC. Если gateway скомпрометирован, злоумышленник получает xpub (который содержит только публичные ключи и не позволяет тратить средства) и может наблюдать входящие платежи, но не может перемещать средства.
Сид ни на одном из серверов не хранится. Он был сгенерирован офлайн, и xpub был извлечён однократно. Это та же дисциплина самостоятельного хранения, которой подчиняется хранилище Kaspa Safe: ключи генерируются и используются только там, где пользователь (или в данном случае — владелец ключа) контролирует устройство. Контракт хранилища, контракт Escrow и слой приёма платежей разделяют принцип: сторона, наблюдающая за блокчейном, никогда не обладает правом подписи.
Тот же движок HD-деривации, который генерирует платёжные адреса, также обеспечивает хранилище Kaspa Safe и зашифрованный профиль Desk — один сид, одна схема деривации, разные строки доменов. Ончейн-операции в Safe и Escrow бесплатны навсегда; только необязательные оповещения мониторинга взимают плату.
Компромиссы и честные ограничения
Опрос добавляет задержку. Наблюдатель видит поступление только в следующем цикле опроса. При скорости Kaspa в 10 блоков в секунду 10-секундный интервал опроса означает худший случай ~10 секунд дополнительной задержки после попадания транзакции в блок. Для страницы оплаты, которая уже считает секунды подтверждений, это приемлемо. Для торгового движка в реальном времени потребовалась бы подписка с тщательной логикой переподключения.
DAA-оценка не интуитивна. «3 подтверждения» при 10 блоках в секунду приходят быстрее секунды, что может казаться «неподтверждённым» для привыкших к десятиминутным блокам Bitcoin. Ваш интерфейс должен транслировать оценку в осмысленный статус — «подтверждено сетью», а не показывать необработанное число, которое выглядит преждевременно малым.
Повторное использование адреса возможно, но нежелательно. Протокол не запрещает вносить средства на ранее использованный адрес, и наблюдатель просуммирует все UTXO независимо от этого. Но один адрес на заказ сохраняет чистоту учёта. Повторное использование делает неоднозначным, какой платёж какому заказу принадлежит постфактум.
Нет push-уведомлений от ноды. Текущая нода Kaspa не предлагает надёжного API подписки на входящие UTXO, устойчивого к перезапускам. Подсистема сети ретранслирует блоки и транзакции мемпула между пирами, но уведомления о поступлениях на конкретные адреса на уровне, достаточном для платёжной системы, требуют опроса на уровне приложения. Это прагматичный выбор, пока не появятся более богатые API нод.
xpub раскрывает все производные адреса. Любой, у кого есть xpub, может восстановить полный набор платёжных адресов и увидеть их историю в блокчейне. Для чекаута, где адрес всё равно показывается покупателю, это редко представляет проблему. Для конфиденциальных сценариев потребуется ротация xpub или ограничение окна деривации.
Нет автоматических возвратов. Если покупатель отправил 500 KAS при ожидаемых 328, излишек не возвращается автоматически. Заказ завершается на полную сумму. Возвраты, если они предлагаются, происходят вручную за пределами протокола. Это осознанный компромисс: автоматическая логика возвратов потребовала бы от платёжного сервиса хранить ключи для подписи, что нарушило бы модель самостоятельного хранения.
---
Паттерн xpub и наблюдателя не уникален для Kaspa — Bitcoin и другие UTXO-чейны используют ту же идею. Что делает его хорошо работающим на Kaspa — это скорость: десять блоков в секунду означает, что платёж проходит от трансляции до подтверждения за секунды, а не минуты, а UTXO-индекс реагирует на новые поступления почти мгновенно. Для любого проекта, принимающего KAS — будь то продажа ПО, маркетплейс или OTC-сделки — архитектура одна и та же: деривация, наблюдение, подтверждение, коллбэк. Никакого кастодиального хранения не требуется.
FAQ
Зачем генерировать уникальный Kaspa-адрес для каждого заказа?
Транзакции Kaspa не содержат поля для заметок или комментариев. Единственный надёжный способ привязать платёж к заказу — выдать покупателю новый адрес, сгенерированный из публичного расширенного ключа (xpub).
Нужен ли приватный сид для генерации платёжных адресов?
Нет. Расширенный публичный ключ (xpub) позволяет выводить дочерние публичные ключи — и, соответственно, адреса — без доступа к какому-либо приватному ключу. Сид может храниться на автономной машине или аппаратном кошельке.
Как наблюдатель узнаёт о поступлении платежа?
Наблюдатель опрашивает UTXO-индекс ноды для всех отслеживаемых адресов. Когда сумма непотраченных выходов достигает или превышает ожидаемую сумму с достаточным количеством подтверждений, он отправляет подписанный коллбэк.
Что происходит, если покупатель отправил меньше ожидаемого?
Наблюдатель фиксирует недостаток, и интерфейс сообщает покупателю точную сумму, которую нужно доплатить на тот же адрес. UTXO-модель Kaspa естественным образом суммирует все поступления на один адрес.
Как измеряются подтверждения в Kaspa?
Подтверждения подсчитываются по разности DAA-оценки между блоком принятия транзакции и виртуальным концом ноды. Скорость Kaspa в 10 блоков в секунду означает, что подтверждения приходят за считанные секунды.
Может ли наблюдатель украсть средства?
Нет. Наблюдатель хранит только публичные ключи. Он может сообщать о том, что видит в блокчейне, но не может подписывать или перемещать какие-либо UTXO. Только владелец соответствующего приватного ключа может тратить средства.
Держите KAS там, где кражу можно отменить
Ковенант-сейф в мейннете Kaspa: ваши ключи, ваши правила, наш инструмент. Ончейн — бесплатно, навсегда.
Создать сейф
