Бот будет полезен тем, кто дорабатывает сервисы для приёма криптовалюты или хочет получить собственный криптовалютный кошелёк в Telegram.
6К открытий9К показов
В интернет-коммерции сейчас активно развивается автоматизация мессенджеров. Полезные боты растут, как грибы после дождя. Тут вам и магазины, и онлайн-помощники, инструменты для аналитики, и прочие важные и полезные решения. Современный бот в телеграмме может полноценно заменить целый сайт и вывести бизнес на новый уровень. Даже криптовалютный кошелек можно создать с помощью бота. Этим и займемся.
Во всех перечисленных сервисах нет проверки KYC и свободная регистрация. Blockchain.info требует получение токена для работы, он условно без проверки, но его получение может занять несколько дней или даже недель.
Выбор пал на сервис Apirone, потому что тут нет ограничений на создание кошельков и адресов.
Итак, наш бот будет уметь:
создавать криптовалютный кошелек в нужной валюте,
получать баланс,
генерировать криптовалютный адрес,
обрабатывать обратную связь (колбэк) от криптовалютного процессинга,
делать перевод имеющихся средств.
Вся обработка колбэков от телеграма уже реализована в php-telegram-bot .
Создаем через @BotFather нового бота, получаем идентификатор бота и ключ API. Далее разворачиваем php-telegram-bot с помощью Composer. Надо заметить, что для работы бота требуется SSL сертификат и действующее доменное имя. В конфиг composer.json добавляем дополнительно библиотеку monolog, которая требуется для отладки приложений. В секции autoload сразу укажем, что для классов будем использовать директорию Classes в папке проекта.
Запускаем composer update для создания базовой структуры. Создаем ее и добавляем туда папку Apirone и в нее файл ApironeWallet.php, в котором реализуем класс взаимодействия с криптопроцессингом.
В нем реализованы следующие функции:
getWallets($user_id, $currencyId = null) //получить кошельки для telegram Пользователя
addWallet($user_id, $wallet, $address) //add generated wallet into DB
postWallet($user_id, $currency) //get wallet from Apirone
createWallets($user_id) //create all available wallets
getCurrencyId($currency,$units = null) //get currency id from DB
getAddress($chat_id, $user_id, $currency) //outputs wallet from DB
getAvailableCurrencies() //collect available currencies from DB
getCurrencyById($id, $units = null) // return currency by Id
getBalance($chat_id, $user_id, $wallet_id = null) // get wallet or wallets balance
checkAddress($currency, $address) // validate crypto address
estimate($user_id, $currencyName, $address, $amount) // pre-calculation of crypto transaction
transfer($user_id, $currencyName, $address, $amount) // transfer funds
explorerUrl($currency, $tx) // get explorer link
Подробно работу этих функций смотрим в примере. Создадим MySQL базу данных, она будет нужна для работы интерактивных диалогов. В нее требуется добавить три таблицы: apirone_currencies, apirone_transactions и apirone_users.
Настроим config.php:
<?php
return [
// Add you bot's API key and name
'api_key' => 'key',
'bot_username' => 'botName', // Without "@"
// When using the getUpdates method, this can be commented out
'webhook' => [
'url' => 'https://example.com/hook.php',
],
'apirone_secret' => 'secret',
'apirone_callback' => 'http://example.com/callback.php',
// All command related configs go here
'commands' => [
// Define all paths for your custom commands
'paths' => [
__DIR__ . '/Commands',
],
// Define all IDs of admin users
'admins' => [
00000,
],
// Enter your MySQL database credentials
'mysql' => [
'host' => 'localhost',
'user' => 'telegram_bot',
'password' => 'password',
'database' => 'telegram_bot',
],
//Logging (Debug, Error and Raw Updates)
'logging' => [
'debug' => __DIR__ . '/php-telegram-bot-debug.log',
'error' => __DIR__ . '/php-telegram-bot-error.log',
'update' => __DIR__ . '/php-telegram-bot-update.log',
],
// Set custom Upload and Download paths
'paths' => [
'download' => __DIR__ . '/Download',
'upload' => __DIR__ . '/Upload',
],
// Requests Limiter (tries to prevent reaching Telegram API limits)
'limiter' => [
'enabled' => true,
],
];
С телеграмом будем общаться с помощью вебхуков (Webhook). Для этого set.php и unset.php – включение и отключение колбэков. hook.php принимает сами колбэки из телеграма:
$telegram->handle();
Установка и удаление вебхука выполняются в две функции:
В корне проекта нужна папка Commands, в нее запишем наши кастомные команды и изменим существующие. Из изменений в базовых классах нас интересует взаимодействие с меню не только через команды, начинающихся со слэша, но и просто текстовые команды. Для этого в папке Commands добавляем папку ServiceMessages и в ней создаем GenericmessageCommand.php , в который путем перечисления вносим нужные команды и реакции на них:
// Fetch conversation command if it exists and execute it.
if ($conversation->exists() && $command = $conversation->getCommand()) {
return $this->telegram->executeCommand($command);
}
if($type === "text") {
$text = $message->getText(true);
if (stripos($text, 'Receive') === 0) {
return $this->telegram->executeCommand('receive');
}
if (stripos($text, 'Menu') === 0) {
return $this->telegram->executeCommand('menu');
}
if (stripos($text, 'Balance') === 0) {
return $this->telegram->executeCommand('balance');
}
if (stripos($text, 'Send') === 0) {
return $this->telegram->executeCommand('send');
}
return $this->replyToChat(
'Command not found'
);
}
Также добавляем наши четыре кастомные команды BalanceCommand.php , MenuCommand.php , ReceiveCommand.php и SendCommand.php.
Каждой команде делаем описание, использование по умолчанию, присваиваем версию.
SendCommand.php будет интерактивным. В нем бот спросит криптовалюту, адрес для перевода средств и сумму платежа.
$this->conversation = new Conversation($user_id, $chat_id, $this->getName());
// Load any existing notes from this conversation
$notes = &$this->conversation->notes;
…
// Every time a step is achieved the state is updated
if($text === 'Cancel') {
$state = 4;
$notes['answer'] = 'Cancel';
}
if($text === 'Send') {
$text = '';
}
switch ($state) {
case 0:
$currencies = $apirone->getAvailableCurrencies();
if ($text === '' || !in_array(strtoupper($text), $currencies, true)) {
...
$data['reply_markup'] = (new Keyboard(
[$currencies[0],$currencies[1]],
[$currencies[2],$currencies[3],$currencies[4]],
['Cancel']))
->setResizeKeyboard(true)
->setOneTimeKeyboard(true)
->setSelective(true);
$result = Request::sendMessage($data);
break;
}
$notes['currency'] = strtolower($text);
$text = '';
case 1:
if ($text === ''|| !$apirone->checkAddress($notes['currency'], $text)) {
$notes['state'] = 1;
$this->conversation->update();
$data['text'] = 'Type address for transfer:';
if ($text !== '') {
...
break;
}
$notes['address'] = $text;
$text = '';
// No break!
case 2:
…
case 3:
if ($text === '' || !in_array($text, ['Ok', 'Cancel'], true)) {
$notes['state'] = 3;
$this->conversation->update();
$currency = $apirone->getCurrencyId($notes['currency'], true);
$estimate = $apirone->estimate($user_id, $notes['currency'], $notes['address'], $notes['amount']);
if(isset($estimate['message'])) {
$data['text'] = 'Message from Apirone:'. PHP_EOL. '*'.$estimate['message'].'*' .PHP_EOL. 'Operation cancelled.';
$data['parse_mode'] = 'markdown';
$data['reply_markup'] = (new Keyboard(['Receive', 'Send'],
['Balance']))
->setResizeKeyboard(true)
->setOneTimeKeyboard(true)
->setSelective(true);
$this->conversation->stop();
} else {
$data['reply_markup'] = (new Keyboard(['Ok', 'Cancel']))
->setResizeKeyboard(true)
->setOneTimeKeyboard(true)
->setSelective(true);
$data['text'] = 'Please double check that all data correct. Send "Ok" message in answer. If you want to stop sending type "Cancel"'. PHP_EOL;
...
if ($text !== '') {
$data['text'] = 'Simply type Ok or Cancel.';
}
}
$result = Request::sendMessage($data);
break;
}
$notes['answer'] = $text;
// No break!
case 4:
$this->conversation->update();
unset($notes['state']);
if($notes['answer'] === 'Ok') {
$transfer = $apirone->transfer($user_id, $notes['currency'], $notes['address'], $notes['amount']);
if(isset($transfer['message'])) {
$data['text'] = 'Message from Apirone:'. PHP_EOL. '*'.$transfer['message'].'*' .PHP_EOL. 'Operation cancelled.';
...
$this->conversation->stop();
} else {
$data['text'] = 'Transfer successfully complete.'.PHP_EOL.
'Transactions:'. PHP_EOL ;
foreach ($transfer['txs'] as $tx) {
$data['text'].= $tx .PHP_EOL. $apirone->explorerUrl($notes['currency'], $tx).PHP_EOL;
};
}
}
...
$result = Request::sendMessage($data);
$this->conversation->stop();
break;
}
return $result;
Создаем StartCommand.php И в нем при первом обращении генерируем данные для нашей базы данных
$message = $this->getMessage();
$user_id = $message->getFrom()->getId();
$apirone = new ApironeWallet;
$apirone->createWallets($user_id);
return $this->replyToChat(
'Welcome to Apirone wallet bot! You are ready to use BTC,BCH,DOGE and LTC wallets right now' . PHP_EOL .
'Type /menu to start using it now!'
);
В корне проекта создаем callback.php . Здесь будет приниматься колбэк от процессинга:
В итоговом результате имеем простого бота, который в дальнейшем можно будет трансформировать и дорабатывать, т.к. заложена серьезная база в виде php-telegram-bot.
При написании бота было изучено достаточно источников. И как оказалось, готовых примеров реализаций ботов на просторах интернета очень мало. Данный бот будет полезен тем, кто хочет дорабатывать свои сервисы для приема криптовалюты или хочет получить свой собственный криптовалютный кошелек в телеграме.
DOOM теперь доступен в Telegram: Axiom Game Labs представила новый порт культовой игры, позволяющий играть в шутер прямо в мессенджере через специального бота
Ретроперспектива недели на Tproger. Во втором выпуске — Евгений Антонов, старший технический менеджер проектов в Yandex Infrastructure и IT-консультант, рассказывает о реструктуризации, подводных дата-центрах Microsoft и секретах управления IT-командами.