Пишем собственный платежный шлюз Bitcoin
UPDATE. Заопенсорсил платежный шлюз: github.com/Overtorment/Cashier-BTC
По разным причинам существующие платежные шлюзы (такие как Bitpay) вас могут не устраивать. В этой статье мы рассмотрим создание собственного Bitcoin шлюза с нуля.
Предполагается что читатель знаком с устройством сети биткоин. Если нет, то рекомендую эти статьи: “Как на самом деле работает протокол Биткоин” и “Биткойн: введение для разработчиков”
Условно, нашу предполагаемую систему я бы разделил на 4 части:
Для выполнения указаных операций нам понадобится подобрать набор програмных решений, которые упростят нам жизнь.
Самые популярные и используемые решения могут выполнять все или почти все указанные выше операции, но ничего не мешает нам комбинировать решения, или даже написать свой велосипед для определенных этапов.
В общем, с этим может справится любая криптографическая библиотека поддерживающая эллиптическую криптографию.
Еще подойдут обычные биткоин библиотеки для работы с Bitcoin:
Самый “тяжеловесный” пункт.
Классическим решением является поднятие собственного эталонного полного узла Биткоин, он же — каноничный bitcoind. Это позволит нам общаться с ним по JSON-RPC. С ним мы сможем как получать информацию из сети, так и пушить транзакции.
На что стоит обратить внимание:
Альтернатива — имплементация полного узла на Ruby+PostgreSQL, Toshi. Неканоничная, но стремящаяся к полной совместимости реализация. Обратите внимание, из-за дополнительных индексов, база данных займет 220+ гигабайт места. Опять таки, требуется синхронизация с сетью.
Возможно, есть другие имплементации полного узла (мне неизвестны).
Еще одна альтернатива — использование публичного API провайдера. На его плечи ляжет получение информации из сети и трансляция транзакций.
Сейчас есть:
Лично я рекомендую подключить несколько решений с фейловером.
В зависимости от того, какую основную библиотеку мы выбрали, эта библиотека умеет или не умеет создавать и подписывать транзакции.
Можно написать самому.
Смотрите раздел “Работа с адресами”.
Результатом создания и подписи транзакций являются двоичные данные (hex), готовые к пушу в сеть. Пока сеть не увидит транзакцию, считайте, нет никакой транзакции. Когда сеть увидела транзакцию, она считается неподтвержденной. Транзакцию достаточно передать одному узлу биткоин, после чего за считаные секунды транзакцию увидит большая часть Биткоин сети.
Транслировать транзакции умеют некоторые клиентские либы из раздела “Работа с адресами” (через какието свои захардкодженые ендпоинты), или любой полный узел. Транслировать транзакцию можно даже руками, зайдя на специальную страничку Биткоин API провайдера и вбив транзакцию в специальную форму. Канонично, подтвержденной транзакцией является транзакция, включенная в 6 и больше последовательных блоков (или в 1-3. Неканонично, но быстрее). Транзакции с нулевой (или недостаточной) комиссией могут оставаться неподтвержденными долгое время (до месяца, в моей практике). Такие транзакции желательно периодически ретранслировать.
Предположим, у нас есть уникальный счет (invoice, order), представленый к оплате клиенту, и платить клиент будет в биткоинах.
Начнем с того, что надо сконвертировать валюту оригинального счета (USD например) в BTC. Задача это тривиальная и рассматривать мы ее не будем.
Далее. Стандартом де факто является генерация нового уникального адреса биткоин под каждый заказ (он же счет, он же invoice, он же ордер). Ожидается, что средства на этот счет переведет только наш клиент, только 1 раз, и только строго указанную сумму (можно больше, никто не обидится, но никак не меньше). Т.о. при поступлении средств на указанный биткоин адрес в нужном количестве, заказ считается оплаченным.
Вкратце, цепочка такая:
При поступлении биткоинов на адрес у вас есть варианты засчитать неподтвержденный или подтвержденный баланс.
Есть небольшой шанс что транзакция откатится, причем это может быть как по вине плательщика (который на самом деле злоумышленник), так и по независящим от него обстоятельствам.
Если вы имеете возможность “отобрать” предоставленный товар или услугу у клиента в случае выявленного факта отмены транзакции, я рекомендую засчитывать неподтвержденный баланс. Это будет означать почти мгновенный процесс оплаты для клиента (в противовес часа ожидания, например). А если какие то транзакции выявятся откаченными в итоге, запросить клиента о повторном платеже, угрожая отобрать услугу/товар.
Не ожидайте что подобный фрод вас тут же массово настигнет, откат транзакций это очень большая редкость, а “вручную” стимулировать подобный откат (на который кстати у злоумышленника нет никаких гарантий успеха) технически неподкованным клиентам нереально (в противовес чарджбекам по кредитным картам).
Еще один пример когда можно засчитывать неподтвержденный баланс — если на подготовку заказа клиента уходит больше одного часа (например обрабатывается корзина покупателя, готовится к отправке курьерской службой). Тут куча времени перепроверить баланс перед самой отправкой товаров.
Для остальных случаев можно ввести некий порог, выше которого обязательно ожидать подтвержденного баланса (например 0.25 BTC). Для максимальной надежности сделать его нулевым.
После закрытия ордера вы можете оставить биткоины на этом адресе до востребования, или для удобства перевести на единый “агрегационный” кошелек мерчанта. Будьте осторожны, в последнем случае вы можете скомпрометировать такой коммерческий показатель как “оборот”, т.к. транзакцию оплаты может отследить каждый платящий клиент.
Для переводов вам понадобится создавать, подписывать и транслировать транзакции, используя приватные ключи от адресов.
Пару слов о времени жизни ордера.
Если ваш товар или услуга жестко привязаны к эквиваленту в фиатной валюте (например USD), то типичный срок жизни ордера составляет 7-15 минут из-за волатильности курса.
Подходит когда вы не выставляете счета на оплату, а аккаунт юзера содержит некий единый баланс, который он пополняет и с которого тратит.
Тут понадобится сгенерить биткоин адрес на пользователя, и показывать ему, с просьбой пополнить на любую сумму.
В данном случае надо мониторить адрес на входящие транзакции, пополнять юзеру внутренний баланс при наличии оных.
В данном случае я рекомендую засчитывать только подтвержденные транзакции (от 3х блоков и выше).
В случае взлома злоумышленника будет интересовать только одно — приватные ключи от сгенерированых вами адресов, ведь они позволяют перевести средства с этих адресов куда угодно.
Я рекомендую хранить их изолировано от основной системы в некоем безопасном хранилище. В конечном итоге они вам понадобятся только когда вы сами захотите воспользоваться вырученными биткоинами (потратить, сконвертировать в нал etc).
При необходимости вырученые биткоины можно автоматически заводить на биржу и по API биржи продавать. Для этого нам понадобится создавать, подписывать и транслировать транзакции, используя приватные ключи от адресов.
Вот и все, надеюсь окажется полезным тем у кого появилась похожая задача.
Исправления неточностей и ошибок приветствуются в личку.
По разным причинам существующие платежные шлюзы (такие как Bitpay) вас могут не устраивать. В этой статье мы рассмотрим создание собственного Bitcoin шлюза с нуля.
Предполагается что читатель знаком с устройством сети биткоин. Если нет, то рекомендую эти статьи: “Как на самом деле работает протокол Биткоин” и “Биткойн: введение для разработчиков”
Условно, нашу предполагаемую систему я бы разделил на 4 части:
- Работа с адресами. Генерация пары публичного и приватного ключа (как известно, хеш публичного ключа является биткоин адресом, а соответствующий приватный ключ позволяет им распоряжаться)
- Получение информации из биткоин сети. Состояние транзакций, баланс на адресах.
- Создание и подпись транзакций. Формирование корректной транзакции, подпись ключом/ключами, преобразование в hex. Полученный hex готов к трансляции в сеть.
- Трансляция транзакций. Aka broadcast, send, push. Передача hex транзакции сети биткоин чтобы майнеры начали работу по включению транзакции в блокчейн.
Для выполнения указаных операций нам понадобится подобрать набор програмных решений, которые упростят нам жизнь.
Самые популярные и используемые решения могут выполнять все или почти все указанные выше операции, но ничего не мешает нам комбинировать решения, или даже написать свой велосипед для определенных этапов.
Работа с адресами
В общем, с этим может справится любая криптографическая библиотека поддерживающая эллиптическую криптографию.
Еще подойдут обычные биткоин библиотеки для работы с Bitcoin:
- pybitcointools (Vitalik Buterin) — python
- Bitcore (Bitpay) — javascript
- BitcoinJS — javascript
- BitcoinJ — java
- другие
Получение информации из биткоин сети
Самый “тяжеловесный” пункт.
Классическим решением является поднятие собственного эталонного полного узла Биткоин, он же — каноничный bitcoind. Это позволит нам общаться с ним по JSON-RPC. С ним мы сможем как получать информацию из сети, так и пушить транзакции.
На что стоит обратить внимание:
- После установки, синхронизация узла может занять длительное время. Только после синхронизации узел можно использовать.
- Займет немало места. Уже 40+ гигабайт.
- Мне лично неизвестно какую нагрузку по запросам сможет выдержать.
- Любые проблемы с падением/обновлением лягут на ваши плечи.
Альтернатива — имплементация полного узла на Ruby+PostgreSQL, Toshi. Неканоничная, но стремящаяся к полной совместимости реализация. Обратите внимание, из-за дополнительных индексов, база данных займет 220+ гигабайт места. Опять таки, требуется синхронизация с сетью.
Возможно, есть другие имплементации полного узла (мне неизвестны).
Еще одна альтернатива — использование публичного API провайдера. На его плечи ляжет получение информации из сети и трансляция транзакций.
Сейчас есть:
- chain.com
- blockchain.info/ru/api (не рекомендую)
- www.blockcypher.com
- chain.so/api
- coinalytics.co
- www.blocktrail.com
- coinkite.com/developers
- другие
Лично я рекомендую подключить несколько решений с фейловером.
Создание и подпись транзакций
В зависимости от того, какую основную библиотеку мы выбрали, эта библиотека умеет или не умеет создавать и подписывать транзакции.
Можно написать самому.
Смотрите раздел “Работа с адресами”.
Трансляция транзакций
Результатом создания и подписи транзакций являются двоичные данные (hex), готовые к пушу в сеть. Пока сеть не увидит транзакцию, считайте, нет никакой транзакции. Когда сеть увидела транзакцию, она считается неподтвержденной. Транзакцию достаточно передать одному узлу биткоин, после чего за считаные секунды транзакцию увидит большая часть Биткоин сети.
Транслировать транзакции умеют некоторые клиентские либы из раздела “Работа с адресами” (через какието свои захардкодженые ендпоинты), или любой полный узел. Транслировать транзакцию можно даже руками, зайдя на специальную страничку Биткоин API провайдера и вбив транзакцию в специальную форму. Канонично, подтвержденной транзакцией является транзакция, включенная в 6 и больше последовательных блоков (или в 1-3. Неканонично, но быстрее). Транзакции с нулевой (или недостаточной) комиссией могут оставаться неподтвержденными долгое время (до месяца, в моей практике). Такие транзакции желательно периодически ретранслировать.
Общие принципы работы платежного шлюза
Вариант 1
Предположим, у нас есть уникальный счет (invoice, order), представленый к оплате клиенту, и платить клиент будет в биткоинах.
Начнем с того, что надо сконвертировать валюту оригинального счета (USD например) в BTC. Задача это тривиальная и рассматривать мы ее не будем.
Далее. Стандартом де факто является генерация нового уникального адреса биткоин под каждый заказ (он же счет, он же invoice, он же ордер). Ожидается, что средства на этот счет переведет только наш клиент, только 1 раз, и только строго указанную сумму (можно больше, никто не обидится, но никак не меньше). Т.о. при поступлении средств на указанный биткоин адрес в нужном количестве, заказ считается оплаченным.
Вкратце, цепочка такая:
- ордер в системе ->
- генерируем соответствующий ордеру уникальный адрес биткоин ->
- показываем клиенту ->
- ждем оплату на адрес ->
- ордер закрыт (отмена по истечению срока годности или же поступление BTC и засчитываем факт оплаты)
При поступлении биткоинов на адрес у вас есть варианты засчитать неподтвержденный или подтвержденный баланс.
Есть небольшой шанс что транзакция откатится, причем это может быть как по вине плательщика (который на самом деле злоумышленник), так и по независящим от него обстоятельствам.
Если вы имеете возможность “отобрать” предоставленный товар или услугу у клиента в случае выявленного факта отмены транзакции, я рекомендую засчитывать неподтвержденный баланс. Это будет означать почти мгновенный процесс оплаты для клиента (в противовес часа ожидания, например). А если какие то транзакции выявятся откаченными в итоге, запросить клиента о повторном платеже, угрожая отобрать услугу/товар.
Не ожидайте что подобный фрод вас тут же массово настигнет, откат транзакций это очень большая редкость, а “вручную” стимулировать подобный откат (на который кстати у злоумышленника нет никаких гарантий успеха) технически неподкованным клиентам нереально (в противовес чарджбекам по кредитным картам).
Еще один пример когда можно засчитывать неподтвержденный баланс — если на подготовку заказа клиента уходит больше одного часа (например обрабатывается корзина покупателя, готовится к отправке курьерской службой). Тут куча времени перепроверить баланс перед самой отправкой товаров.
Для остальных случаев можно ввести некий порог, выше которого обязательно ожидать подтвержденного баланса (например 0.25 BTC). Для максимальной надежности сделать его нулевым.
После закрытия ордера вы можете оставить биткоины на этом адресе до востребования, или для удобства перевести на единый “агрегационный” кошелек мерчанта. Будьте осторожны, в последнем случае вы можете скомпрометировать такой коммерческий показатель как “оборот”, т.к. транзакцию оплаты может отследить каждый платящий клиент.
Для переводов вам понадобится создавать, подписывать и транслировать транзакции, используя приватные ключи от адресов.
Пару слов о времени жизни ордера.
Если ваш товар или услуга жестко привязаны к эквиваленту в фиатной валюте (например USD), то типичный срок жизни ордера составляет 7-15 минут из-за волатильности курса.
Вариант 2
Подходит когда вы не выставляете счета на оплату, а аккаунт юзера содержит некий единый баланс, который он пополняет и с которого тратит.
Тут понадобится сгенерить биткоин адрес на пользователя, и показывать ему, с просьбой пополнить на любую сумму.
В данном случае надо мониторить адрес на входящие транзакции, пополнять юзеру внутренний баланс при наличии оных.
В данном случае я рекомендую засчитывать только подтвержденные транзакции (от 3х блоков и выше).
- генерация адреса пользователю ->
- мониторинг транзакций на адрес ->
- пополнение внутреннего счета при наличии входящих транзакций
Несколько слов о безопасности
В случае взлома злоумышленника будет интересовать только одно — приватные ключи от сгенерированых вами адресов, ведь они позволяют перевести средства с этих адресов куда угодно.
Я рекомендую хранить их изолировано от основной системы в некоем безопасном хранилище. В конечном итоге они вам понадобятся только когда вы сами захотите воспользоваться вырученными биткоинами (потратить, сконвертировать в нал etc).
Что дальше?
При необходимости вырученые биткоины можно автоматически заводить на биржу и по API биржи продавать. Для этого нам понадобится создавать, подписывать и транслировать транзакции, используя приватные ключи от адресов.
Вот и все, надеюсь окажется полезным тем у кого появилась похожая задача.
Исправления неточностей и ошибок приветствуются в личку.