Fri. Jul 30th, 2021
Телеграм-бот для автоматизации обменника криптовалюты / Хабр

Вместо предисловия

В этой статье я буду в общих чертах рассказывать про то, в каком направлении нужно двигаться, чтобы сделать полуавтоматический обменник криптовалюты с возможностью управлять сделками с любого устройства в любой точке планеты 24/7. Вы не найдете здесь деталей реалиализации, т.к. этот материал предназначен скорее для получения базового набора знаний, необходимых для запуска такого стартапа. Результат вы можете посмотреть на exbtc.pro

Полуавтоматический обменник криптовалюты.

Как-то очень давно я у же немного писал про использование телеграм-бота для автоматизации некоторых процессов. Надо сказать, что уже не мало времени прошло, но я продолжаю использовать некоторые идеи, что были изложены в том небольшом материале.

Обмен криптовалюты сегодня – это уже не просто реальность, в какой-то мере это уже потребность. Время беспощадно и теперь цифровое золото становится очень важной частью активов миллионов людей. Обменники в интернете бывает нескольких видов, основные из которых:

Мы поговорим про полуавтоматический вариант с возможностью расширения до p2p обменника, потому как это довольно простой и удобный способ.

Необходимый набор навыков.

Говоря довольно простой, я наверное выражаюсь несовсем корректно. В наше время навыки, которыми должен обладать разработчик, оцениваются в тысячи часов времени, которое он должен потратить на свое обучение. Я сегодня буду предельно краток, так что давайте сразу перейдем к делу. Для реализации задачи нам понадобится следующий набор иснтрументов:

  1. Linux, zsh, vim, systemd

  2. nginx, ssl

  3. ES6, Material Ui, React, eslint, webpack, scss

  4. python3, asyncio, aiohttp, peewee

  5. postgresql

  6. telegram bot api

  7. docker

И такие паттерны как:

  1. MVC – шаблон архитектуры системы

  2. Abstract Factory, Factory Method, Builder, Facade, Prototype – генерация объектов

  3. Scheduler – многопоточный постановщик задач

  4. Event Listner, State – события, сосстояния

  5. Proxy – заместитель для балансировки нагрузки

В общих чертах это вроде как все, что должно пригодится, согласитесь не мало. Давайте пробежимся теперь немного более подробно, чтобы понимать как все это барахло должно быть настроено, чтобы даже работать.

Теперь я начинаю с фронта

Если вы попробуете поискать в сети с чего начинать веб разработку – с фронтенда или с бэкэнда, вы наверное не найдете ничего более дельного, чем информация о том, что все это лучше делать параллельно и каких-то особых протоколов на этот счет нет. Т.е. фронтендер делает свою работу, бэкэндер свою, они встречаются на созвонах и в чате, обсуждают все проблемы: все хорошо. Но что, если вы собираетесь делать и фронт и бэк самостоятельно (например в случае небольшого приложения как криптообменник) – какая будет точка отправления?

Начинать лучше с фронта, потому как он может работать на моковых данных и бэкэнд ему собственно нужен только абсолютно гипотетически. Фронтенд – независимое приложение, он должен работать корректно в разных браузерах, на разных устройствах. Мы будем делать Single Page Application, а значит нам потребуется протокол взаимодействия, давайте выберем json-rpc. Для транспортного протокола используем tcp,а на прикладном уровне остановимся на http.

Дальше все довольно не трудно. Ставим Node Package Manager, создаем новое реакт приложение, добавляем туда react router,настраиваем eslint для форматирования кода, node-sass для возможности использования css препроцессора, webpack для сборки проекта.

Правильная структура проекта – залог успеха. Компоненты делаем модульными – файлы стилей лежат внутри дирректории рядом с компонентом. Компоненты по мере возможностей реализуем как stateless. Я бы пожалуй еще рекоммендовал дважды задуматься перед внедерением redux в приложение – делайте это только если вы точно уверены, что вам это нужно.

При работе с фронтом важно всегда помнить об области видимости переменных, потому как современный фронтенд это сложное многопоточное, асинхронное приложение. При этом при правильной организации файлов и компонентов, react и material ui позволяют делать все достаточно быстро. Если у вас нет готового дизайна – просто выберите сайт обменника, который вам нравится и не стесняясь копируйте его, превнося свои изменения – в дальнейшем ваш обменник все равно еще претерпит кучу изменений и не стоит беспокоится о том как это смотрится на текущей стадии.

Вот так может выглядеть ваш реакт компонент, отвечающий за рендеринг главной страницы:

Бэкэнд – это сложно, но куда веселее

Бэкэнд тоже должен быть асинхронным. P2P приложения должны быть ориентированы под высокую нагрузку, а значит сразу стоит закладывать немного больше, чем может показаться нужным. Мы будем делать монолитный бэкэнд, потому как серверная часть не будет очень большой. Микросервисы это здорово, но не всегда необходимо, и в данном случае мы не будем использовать этот подход.

asyncio позволяет работать с петлей событий, что в свою очередь предоставляет возможность асинхронного программирования и управления заданиями. В нашем случае у нас будет несколько заданий, которые должны будут работать независимо и параллельно основному приложению. Это задание на обновление курсов BTC/USD и USD/RUB, и задание, которое будет отменять устаревшие заявки на обмен валюты. Курсы вылют можно получать get запросом из апи всех популярных бирж, например coinbase, kraken, bitmex. Благо aiohttp clientпозволяет это делать в несколько строчек:

Для того, чтобы сериализовывать данные, необходимые фронту для построения интерфейса, сервер должен использовать объектно-ориентированную модель данных, проще говоря – нужно поделить наш обменник на модели, а эти модели сложить в таблицы бд, чтобы можно было строить к ней запросы.

При создании моделей стоит особое внимание уделить инкапсуляции и наследованию – хорошей идеей будет сразу создать BaseModel, в которую поменстить, например, поля created_at, updated_at и, например, datetime_serializer, который вам точно пригодится, а остальные модели наследовать от этой модели:

Для взаимодействия с блокчейн придется получить API KEY, например на blockchain.com. Хочу сразу отметить, что тут есть своего рода “подводный камень”. Как работает блокчейн апи? После того, как создается транзакция, для ее завершения необходимы подтверждения от майнеров. Каждое подтверждение – это своего рода события, информацию о котором вы будете получать на свой сервер. В этом событии есть адрес кошелька, на который поступает криптовалюта. Теперь предположим, что для покупки криптовалюты в нашем обменнике мы всем пользователям будем предоставлять одинаковый кошелек для перевода. Это было бы довольно удобно, так как все биткоины были бы сосредоточены у нас на одном адресе, одной суммой. На первый взгляд. Но в таком случае при поступлении средств от пользователя на кошелек и последующих веб хуках от блокчейн на callback_url, мы не сможем определить от какого конкретно пользователя поступил платеж. Можно конечно использовать параметр в webhook url но есть еще один интересный нюанс. Нам важно знать курс по которому была совершена та или иная транзакция.Опять же, есть вариант хранить свзяь между транзакицей и курсом, но есть и альтернативное решение. Оно состоит в том, что каждому пользователю системы должен генерироваться свой уникальный BTC кошелек. И в случае, когда этот самый пользователь хочет совершить сделку в нашем обменном пункте и продавть свои кровные BTC, мы будем скидывать ему его уникальный адрес.

Дальше может покзаться, что целесообразно со всех этих адресов собирать все деньги на master wallet, но это не так, ведь за каждый перевод вы будете платить комиссию майнерам. К слову эту комиссию нужно считать ручками. Получить информацию от сети можно в любой момент:

Таким образом получается, что баланс нашего обменника сосредоточен децентрализованно на разных кошельках всех пользователей. При каждой транзакции мы записываем курс, по которому она была осуществлена, а ее статус (так же как впрочем и статус документа по этой транзакции) мы меняем в зависимости от подтверждений blockchain.К слову сразу имеет смысл подумать над реализацией классов Billing и Processing, для создания и проводки документов.

Для продажи крипты нам необходим механизм ручного взаимодействия с этими документами: нужно искать документ с выгодным на текущий момент курсом, проверять текущий баланс кошелька из этого документа, и выполнять перевод с этого кошелька на кошелек, который указывает пользователь в своей заявке на покупку в нашем обменнике. И вот мы наконец подобрались к кульминации нашего материала: к нам снова на помощь приходит телеграм.

Telegram bot

Тут все совсем не трудно. Создаем бота у @BotFather, настраиваем, берём токен, кладем его в конфиг (делаем два конфига и два бота – один на прод, один на дев).

Из этого токена мы можем создать бота и использовать его для получения важных данных, а так же для запуска протокола rpc, не требующего дополнительной авторизации и шифрования.

Теперь мы можем слать сообщения в телеграм из нашего бэкэнда, для этого мы создадим приватный чат и добавим бота администратором туда. Далее нам потребуется создать вебхук и контроллер для его обработки (читайте об этом в предыдущем материале про мониторинг). В контроллере нам необходимо создать диспетчер запросов, который будет определять обработчик.

Запросы от тг могут быть разные, нам пока нужны будут только message и callback_query (reply клавиатура и inline клавиатура).

Далее мы будем отправлять в этот чат сообщения с кнопками, которые позволят контролировать значения в базе данных. Здесь обращу внимание на race condition, и трудно-уловимые ошибки, по этому всегда используйте atomic_db_query

async with objects.atomic() as atomic_db_query:
	try:
  	pass  # some database change
  except:  
		atomic_db_query.rollback()

Кнопки вы можете нажать после ручной модерации заявки – ну т.е. вы посмотрели, что деньги к вам на счет реально поступили, и только после этого нажали на кнопку, которая запустит механизм для завершения документооборота. Так же можно, например создать механизмsubscription, который позволит информировать подписавшихся пользователей на обновления курсов, например:

Это довольно удобно, ведь телеграм всегда под рукой, особенно после разблокировки . 24/7 все, кто находятся в приватной группе, смогут получать информационные сообщения, а так же управлять состоянием документов:

Настройка production

Нужно все это барахло завернуть в докер, настроить системный даемон для запуска юнита, в идеале конечно настроить CI-CD, но это все наверное уже детали.

В базовом варианте можно деплоится через гит, использовать переменные окружения для чтения конфигов, использовать ipython для проведения миграций в бд:

Нужно уметь использовать настраивать nginx, и понимать, как работает mod_rewrite.

location = /api/rates/rates.xml {
  rewrite .* /api/rates/ last;
}   

Кстати для добавления вашего обменника в мониторинги, вам понадобится xml выгрузки файла курсов, так что этот rewrite вам может еще пригодится.

Наверное вы захотите сделать какую-то админку – для этого отлично сгодится механизм Basic Auth и bootstrap admin template . Вам останется только пробросить в шаблоны необходимый контекст и немного поиграть с контролами:

Послевкусие

Это все сложновато, но в тоже время и не очень, если не наступать на грабли, которые, надо сказать, присутствуют. Не забывайте о JWT, SSL, CORS, и еще куче прелестей, которые по пути обязательно появятся у вас на пути. Но в целом это рабочая схема автоматизации механизмов, которые могут пригодится не только при создании обменника. Я не претендую на роль эксперта в этом деле, я лишь высказываю свои умозаключения, после довольно трудоемкого процесса прохождения через все вышесказанное. Не стоит принимать буквально – многое является весьма субъективным и не претендует на роль аксиомы. Я бы сказал бОльшая часть. Но под лежачий камень вода не течет, и лучшее решение на сегодня – это развитие и движение дальше.

Надеюсь кому-то покажется эта информация полезной. Просто захотелось немного поделиться переживаниями и опытом, полученным от процесса.

Дальнейшие развитие позиционируется как p2p платформа для совершения обмена. Буду рад любым вопросам и предложениям, и большое спасибо за потраченное время.

By admin

Leave a Reply

Your email address will not be published. Required fields are marked *