Making a telegram bot to save messages to the blockchain

Hi, I'm Dmitry and I want to share with you how I made my telegram bot for saving messages from chats to the blockchain in java. In general, the idea was to learn how to quickly and conveniently immortalize some especially important messages so that they would remain unchanged and regardless of what happens to the chat where they were posted or even to Telegram itself.

What we will learn:

  1. (Part 1) Write a warning message when a bot is added to a chat

  2. send a greeting message to the chat when the bot is given admin rights and starts working

  3. read messages from chats or private conversations

  4. (Part 2) process messages from chats he is connected to or from private conversations

  5. process commands

  6. (Part 3) make a transaction for the blockchain and write a response to the message that the transaction has been created

  7. check the transaction confirmation in the blockchain and change the previously sent response to the new message

Firstly, What is blockchain? Imagine that there is a magic book-chronicle, and a wizard-chronicler who can make entries in it. And that there are many such chronicles and each has its own chronicler. And the magic is that if an entry is made in one of them, then it magically appears in all the chronicles and it can no longer be deleted or changed from there. And everyone sees this entry and can always find it on a given page. For example, you come to the chronicler and say – “I have my poem that I want to immortalize and give to the world, but so that my authorship is taken into account!” The wizard says – “Okay, and how many lines are in your poem?” – “100!” – you answer. “Then it will cost 5 magic coins,” he says. “Shake on it!” You give him the coins, and the wizard enters your poem into the magic chronicle and it immediately appears in all the magic chronicles at once on the current page – with the signature of the wizard who entered it and with your signature as the author.

Secondly, Why do you need to save chat messages in the blockchain? First of all, to be independent of changes in the Telegram chat – a message already recorded in the blockchain cannot be deleted or changed. For example (case 1), as you know, Pavel Durov was detained in France the day before in order to gain access to Telegram chats. But what if your chat is accessed from the outside and all messages are deleted or distorted? In your defense, you can always get the original messages if they were saved in the blockchain. The second point (case 2) is to save for history, so that in years you can know that the data has remained unchanged.

We've sorted out the blockchain, let's move on…

First, create an account for your bot, where you set its name and get access keys. This can be done by calling the official Telegram bot manager – @BotFather.

Now let's start writing code

To work with the bot I used the library com.pengrad.telegrambot https://github.com/pengrad/java-telegram-bot-api?tab=readme-ov-file#creating-your-bot

We create an instance of the bot like this:

import com.pengrad.telegrambot.TelegramBot;
…
       TelegramBot bot = new TelegramBot(botToken);
       // Спросить бота о его настройках:
       System.out.println(bot.execute(new GetMe()));

Where botToken – This is the access key received from @BotFather.

Forwarding messages to chat

The bot can send messages to the chat by its unique number, both simple text and beautifully formatted (for example, using Markdown). The code is as follows:

    protected BaseResponse sendSimpleText(long chatId, String textToSend) {
        SendMessage message = new SendMessage(chatId, textToSend);
        return sendMessage(message);
    }

    protected BaseResponse sendMarkdown(long chatId, String textToSend) {
        SendMessage message = new SendMessage(chatId, textToSend);
        message.parseMode(ParseMode.Markdown);
        return sendMessage(message);
    }

Receiving events from chat

In order not to bother with the domain name, we will use the polling mode of the telegram service, receiving all updates and events from the world of telegram chats from it:

       // Подписка на обновления
        bot.setUpdatesListener(updates -> {
            // Обработка обновлений
            try {
                updates.forEach(update -> onUpdateReceived(update));
                // return id of last processed update or confirm them all
                // Создание Обработчика ошибок
            } catch (Exception e) {
                log.error("On TELEGRAM Updates error {}", e.toString());
            }
            return UpdatesListener.CONFIRMED_UPDATES_ALL;
        }, e -> {
            if (e.response() != null) {
                // Ошибка из Телеграма
                log.warn("TELEGRAM ERR: " + e.response().errorCode() + " - " + e.response().description());
            } else {
                // Как видно проблема сети
                e.printStackTrace();
            }
        });

Now we need to set the processing in the function onUpdateReceived and that's it!

Let's make a simple handler of the form:

   protected void onUpdateReceived(Update update) {

        try {

            Chat chat;
            Chat origMessageChat;
            User from;
            User user;
            Long chatId;
            Long userId;
            String text;

            Integer updateId = update.updateId();
            String lang = "ru";

            ////////// MESSAGE
            Message message = update.message();
            String userName;
           if (message != null) {
                // сюда приходит если:
                // или прямой чат пользователя с ботом
                // или в чате группы/супергруппы (не канал) бот добавлен администратором

                chat = message.chat();
                chatId = chat.id();
                chatErrorId = chatId;
                System.out.println(message.text());

…
           }
        }
    }

Now, in order for the bot to be able to read messages in any chat, it must be invited to this chat and made an administrator – only then will it be able to receive notifications about events and messages in this chat. You can also write commands to the bot directly through a private chat with this bot.

If we run this program and invite the bot to any chat and make it an admin, then all messages from this chat will be printed in the system log.

In addition to chat messages, you will be able to receive events such as user rights granting, chat invitations, etc.

Let's now teach our bot to determine whether it was invited to the chat and granted administrator rights. To do this, insert the following into the handler code:

            // приглашения и удаления из групп
            ChatMemberUpdated myChatMember = update.myChatMember();
            if (myChatMember != null) {
                chat = myChatMember.chat(); // в каком чате действие произошло
                chatId = chat.id();
                chatErrorId = chat.id();
                from = myChatMember.from(); // кто это сделал

                log.warn("User from: " + GSON.toJson(from).toString());

                ChatMember newChatMember = myChatMember.newChatMember();
                user = newChatMember.user();
                ChatMember.Status oldStatus = myChatMember.oldChatMember().status();
                ChatMember.Status newStatus = newChatMember.status();
                if (oldStatus.equals(newStatus))
                    return;

                if (user.username().equals(botUserName)) {

                    if (newStatus.equals(ChatMember.Status.kicked) || newStatus.equals(ChatMember.Status.left)) {
                        // нас удалили из группы
                        Integer untilDate = newChatMember.untilDate(); // 0 - просто удалили
                        log.error("kicked from " + chat.title() + " by User " + from.username());

                        // Конкретный пользователь известен только когда удаляют администратора! Иначе бот кикает и не понятно кто тебя кикнул
                        if (!from.isBot())
                            sendSimpleText(from.id(), from.username() + ", спасибо за использование наших услуг в чате \"" + chat.title() + "\". Надеемся на продолжение сотрудничества в будущем.");

                    } else if (newStatus.equals(ChatMember.Status.administrator)) {
                        // нас сделали администратором
                        // Тут известен конкретный пользователь кто пригласил
                        if (!from.isBot())
                            sendSimpleText(from.id(), from.username() + ", спасибо за допуск меня к работе в чате \"" + chat.title() + "\". Надеюсь быть полезным...");

                    } else if (newStatus.equals(ChatMember.Status.member)) {
                        // нас внесли в группу или понизили из админа до обычного пользователя
                        if (!from.isBot())
                            sendSimpleText(from.id(), from.username() + ", моя работа в чате \"" + chat.title() + "\" прекращена. Жду назначения администраторам снова...");

                    }

                    log.info("status:" +  newStatus.name());

                } else {
                    // Это не про меня
                }

            }

Private chat with a bot

You can also tell when someone is chatting with a bot in a private conversation (when someone is chatting directly with a bot). A private chat can be defined as follows:

if (chat.type().equals(Chat.Type.Private))

Processing forwarded messages from channels

An interesting mode, when the discussion chat and the news channel are linked. Then messages from the channel automatically fall into the discussion chat. You can catch them like this:

                if (Boolean.TRUE.equals(message.isAutomaticForward())) {
                    // это сообщение пришло из канала к которому привязан данный чат (супергруппа)
                    // это основной чат откуда пришло сообщение - с именем и правильным UserName
                    origMessageChat = message.senderChat();

So, in the first part of the article we figured out how to send messages to chats, how to read them and how to determine that the bot was added to the chat and given administrator rights.

The full code of the telegram bot (super-class and subclass implementing sending transactions to the blockchain) is located in Gillab repositories Erachain project – inside the blockchain node. You can call the bot in the telegram messenger by the name @blockchain_storage_bot – you can see how it works to better understand the bot code.

Write questions in the comments – we will make the second part of the article

Similar Posts

Leave a Reply

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