diff --git a/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-2.md b/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-2.md index 97ee45f685d..b15a425a77d 100644 --- a/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-2.md +++ b/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-2.md @@ -15,21 +15,21 @@ The bot will look like this: ### Source code -Sources are available on GitHub: +The sources are available on GitHub: * https://github.com/Gusarich/ton-bot-example ## 📖 What you'll learn You'll learn how to: - - create a Telegram bot in Python3 using Aiogram - - work with SQLITE databases - - work with public TON API + - Create a Telegram bot in Python3 using Aiogram, + - Work with SQLITE databases, + - Work with public TON API. ## ✍️ What you need to get started -Install [Python](https://www.python.org/) if you haven't yet. +Install [Python](https://www.python.org/) if you haven't already. -Also you need these PyPi libraries: - - aiogram - - requests +Install the required PyPi libraries: + - aiogram, + - requests. You can install them with one command in the terminal. ```bash @@ -38,10 +38,10 @@ pip install aiogram==2.21 requests ## 🚀 Let's get started! Create a directory for our bot with four files in it: - - `bot.py`—program to run a Telegram bot - - `config.py`—config file - - `db.py`—module to interact with the sqlite3 database - - `ton.py`— module to handle payments in TON + - `bot.py`— Program to run the Telegram bot, + - `config.py`— Configuration file, + - `db.py`— Module for interacting with the SQLite database, + - `ton.py`— Module for handling payments in TON. The directory should look like this: ``` @@ -52,10 +52,10 @@ my_bot └── ton.py ``` -Now let's begin writing code! +Now, let’s start coding! ## Config -Let's start with `config.py` because it is the smallest one. We just need to set a few parameters in it. +We'll begin with `config.py` since it's the smallest file. We just need to set a few parameters in it. **config.py** ```python @@ -71,16 +71,17 @@ else: ``` Here you need to fill in the values in the first three lines: - - `BOT_TOKEN` is your Telegram Bot token which you can get after [creating a bot](https://t.me/BotFather). - - `DEPOSIT_ADDRESS` is your project's wallet address which will accept all payments. You can just create a new TON Wallet and copy its address. - - `API_KEY` is your API key from TON Center which you can get in [this bot](https://t.me/tonapibot). + - `BOT_TOKEN`- Your Telegram bot token [creating a bot](https://t.me/BotFather). + - `DEPOSIT_ADDRESS` - Your project's wallet address for receiving payments. You can create a new TON Wallet and copy its address. + - `API_KEY` - Your API key from TON Center which you can get in [this bot](https://t.me/tonapibot). -You can also choose whether your bot will run on the testnet or the mainnet (4th line). +You can also choose whether your bot will run on the Testnet or the Mainnet (4th line). + +Once these values are set, we can move forward! -That's all for the Config file, so we can move forward! ## Database -Now let's edit the `db.py` file that will work with the database of our bot. +Now let's edit the `db.py` file to store user balances. Import the sqlite3 library. ```python @@ -93,7 +94,7 @@ con = sqlite3.connect('db.sqlite') cur = con.cursor() ``` -To store information about users (their balances in our case), create a table called "Users" with User ID and balance rows. +Create a table called **Users** with `uid` and `balance` columns to store information about users and their balances. ```python cur.execute('''CREATE TABLE IF NOT EXISTS Users ( uid INTEGER, @@ -102,7 +103,7 @@ cur.execute('''CREATE TABLE IF NOT EXISTS Users ( con.commit() ``` -Now we need to declare a few functions to work with the database. +Define helper functions to interact with the database: `add_user` function will be used to insert new users into the database. ```python @@ -139,24 +140,23 @@ def get_balance(uid): And that's all for the `db.py` file! -Now we can use these four functions in other components of the bot to work with the database. +Once this file is set up, we can use these functions in other parts of the bot. + ## TON Center API In the `ton.py` file we'll declare a function that will process all new deposits, increase user balances, and notify users. ### getTransactions method -We'll use the TON Center API. Their docs are available here: +We'll use the TON Center API. Their documentation is available here: https://toncenter.com/api/v2/ -We need the [getTransactions](https://toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get) method to get information about latest transactions of a given account. - -Let's have a look at what this method takes as input parameters and what it returns. +We need the [getTransactions](https://toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get) method to retrieve information about the latest transactions of a given account. +Let's review the input parameters this method requires and what it returns. -There is only one mandatory input field `address`, but we also need the `limit` field to specify how many transactions we want to get in return. - -Now let's try to run this method on the [TON Center website](https://toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get) with any existing wallet address to understand what we should get from the output. +The only mandatory input field is `address`, but we also need the `limit` field to specify how many transactions we want to retrieve. +Let's test this method on the [TON Center website](https://toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get) website using any existing wallet address to see what the output looks like. ```json { "ok": true, @@ -205,15 +205,13 @@ Well, so the `ok` field is set to `true` when everything is good, and we have an } ``` -We can see that information that can help us identify the exact transaction is stored in `transaction_id` field. We need the `lt` field from it to understand which transaction happened earlier and which happened later. - -The information about the coin transfer is in the `in_msg` field. We'll need `value` and `message` from it. +We can see that the key details for identifying a specific transaction are stored in the `transaction_id` field. We need the `lt` field from this to determine the chronological order of transactions. -Now we're ready to create a payment handler. +Now, we're ready to create a payment handler. ### Sending API requests from code -Let's begin with importing the required libraries and our two previous files: `config.py` and `db.py`. +Let's start by importing the required libraries along with the`config.py` and `db.py` files. ```python import requests import asyncio @@ -227,16 +225,15 @@ import config import db ``` -Let's think about how payment processing can be implemented. +Let's explore how payment processing can be implemented. -We can call the API every few seconds and check if there are any new transactions to our wallet address. +We can call the API every few seconds to check if new transactions have been received in our wallet. -For that we need to know what the last processed transaction was. The simplest approach would be to just save info about that transaction in some file and update it every time we process a new transaction. +To do this, we need to track the last processed transaction. The simplest approach is to save this transaction’s details in a file and update it every time a new transaction is processed. -What information about the transaction will we store in the file? Actually, we only need to store the `lt` value—logical time. -With that value we'll be able to understand what transactions we need to process. +What information should we store? We only need the `lt` (logical time) value, which will allow us to determine which transactions need to be processed. -So we need to define a new async function; let's call it `start`. Why does this function need to be asynchronous? That is because the Aiogram library for Telegram bots is also asynchronous, and it'll be easier to work with async functions later. +Next, we define an asynchronous function called `start`. Why async? Because the Aiogram library for Telegram bots is asynchronous, making it easier to work with async functions. This is what our `start` function should look like: ```python @@ -257,7 +254,7 @@ async def start(): ... ``` -Now let's write the body of while loop. We need to call TON Center API there every few seconds. +Within the `while` loop, we need to call the TON Center API every few seconds. ```python while True: # 2 Seconds delay between checks @@ -275,9 +272,9 @@ while True: ... ``` -After the call with `requests.get`, we have a variable `resp` that contains the response from the API. `resp` is an object and `resp['result']` is a list with the last 100 transactions for our address. +After making a `requests.get` call, the response is stored in the `resp` variable. The resp object contains a result list with the 100 most recent transactions for our address. -Now let's just iterate over these transactions and find the new ones. +Now, we iterate through these transactions and identify the new ones. ```python while True: @@ -298,12 +295,12 @@ while True: ... ``` -How do we process a new transaction? We need to: - - understand which user sent it - - increase that user's balance - - notify the user about their deposit +How to process a new transaction? We need to: + - Identify which user sent the transaction, + - Update that user's balance, + - Notify the user about their deposit. -Here is the code that will do all of that: +Below is the code that handles this: ```python while True: @@ -332,21 +329,20 @@ while True: parse_mode=ParseMode.MARKDOWN) ``` -Let's have a look at it and understand what it does. - -All the information about the coin transfer is in `tx['in_msg']`. We just need the 'value' and 'message' fields from it. +Let's analyze what it does: -First of all, we check if the value is greater than zero and only continue if it is. +All the information about the coin transfer is in `tx['in_msg']`. We just need the `value` and `message` fields. -Then we expect the transfer to have a comment ( `tx['in_msg']['message']` ), to have a user ID from our bot, so we verify if it is a valid number and if that UID exists in our database. +First, we check if value is greater than zero—if not, we ignore the transaction. -After these simple checks, we have a variable `value` with the deposit amount, and a variable `uid` with the ID of the user that made this deposit. So we can just add funds to their account and send a notification message. +Next, we verify that the ( `tx['in_msg']['message']` ) field contains a valid user ID from our bot and that the UID exists in our database. +After these checks, we extract the deposit amount `value` and the user ID `uid`. Then, we add the funds to the user’s account and send them a notification. Also note that value is in nanotons by default, so we need to divide it by 1 billion. We do that in line with notification: `{value / 1e9:.2f}` Here we divide the value by `1e9` (1 billion) and leave only two digits after the decimal point to show it to the user in a friendly format. -Great! The program can now process new transactions and notify users about deposits. But we should not forget about storing `lt` that we have used before. We must update the last `lt` because a newer transaction was processed. +Once a transaction is processed, we must update the stored `lt` value to reflect the most recent transaction. It's simple: ```python @@ -369,7 +365,7 @@ Our bot is now 3/4 done; we only need to create a user interface with a few butt ### Initialization -Open the `bot.py` file and import all the modules we need. +Open the `bot.py` file and import all necessary modules. ```python # Logging module import logging @@ -392,21 +388,21 @@ Let's set up logging to our program so that we can see what happens later for de logging.basicConfig(level=logging.INFO) ``` -Now we need to initialize the bot object and its dispatcher with Aiogram. +Next, we initialize the bot and dispatcher using Aiogram: ```python bot = Bot(token=config.BOT_TOKEN) dp = Dispatcher(bot) ``` -Here we use `BOT_TOKEN` from our config that we made at the beginning of the tutorial. +Here we use the `BOT_TOKEN` from our config file. -We initialized the bot but it's still empty. We must add some functions for interaction with the user. +At this point, our bot is initialized but still lacks functionality. We now need to define interaction handlers. ### Message handlers #### /start Command -Let's begin with the `/start` and `/help` commands handler. This function will be called when the user launches the bot for the first time, restarts it, or uses the `/help` command. +Let's begin with the `/start` and `/help` commands handlers. This function will be triggered when the user launches the bot for the first time, restarts it, or uses the `/help` command. ```python @dp.message_handler(commands=['start', 'help']) @@ -432,13 +428,13 @@ async def welcome_handler(message: types.Message): parse_mode=ParseMode.MARKDOWN) ``` -The welcome message can be anything you want. Keyboard buttons can be any text, but in this example they are labeled in the most clear way for our bot: `Deposit` and `Balance`. +The welcome message can be customized to anything you prefer. The keyboard buttons can also be labeled as needed, but in this example, we use the most straightforward labels for our bot: `Deposit` and `Balance`. #### Balance button -Now the user can start the bot and see the keyboard with two buttons. But after calling one of these, the user won't get any response because we didn't create any function for them. +Once the user starts the bot, they will see a keyboard with two buttons. However, pressing these buttons won't yield any response yet, as we haven't created functions for them. -So let's add a function to request a balance. +Let's add a function to check the user's balance. ```python @dp.message_handler(commands='balance') @@ -455,11 +451,11 @@ async def balance_handler(message: types.Message): parse_mode=ParseMode.MARKDOWN) ``` -It's pretty simple. We just get the balance from the database and send the message to the user. +The implementation is simple: we retrieve the balance from the database and send a message displaying it to the user. #### Deposit button -And what about the second `Deposit` button? Here is the function for it: +Let's implement the **Deposit** button. Here’s how it works: ```python @dp.message_handler(commands='deposit') @@ -483,13 +479,12 @@ async def deposit_handler(message: types.Message): parse_mode=ParseMode.MARKDOWN) ``` -What we do here is also easy to understand. -Remember when in the `ton.py` file we were determining which user made a deposit by commenting with their UID? Now here in the bot we need to ask the user to send a transaction with a comment containing their UID. +This step is crucial because, in `ton.py` we identify which user made a deposit by extracting their UID from the transaction comment. Now, within the bot, we must guide the user to include their UID in the transaction comment. ### Bot start -The only thing we have to do now in `bot.py` is to launch the bot itself and also run the `start` function from `ton.py`. +The final step in `bot.py` is to launch the bot and also start the `start` function from `ton.py`. ```python if __name__ == '__main__': @@ -503,9 +498,9 @@ if __name__ == '__main__': ex.start_polling() ``` -At this moment, we have written all the required code for our bot. If you did everything correctly, it must work when you run it with `python my-bot/bot.py` command in the terminal. +At this point, we have written all the necessary code for our bot. If everything is set up correctly, the bot should work when you run the following command in the terminal: `python my-bot/bot.py`. -If your bot doesn't work correctly, compare your code with code [from this repository](https://github.com/Gusarich/ton-bot-example). +If the bot does not function as expected, compare your code with the code [from this repository](https://github.com/Gusarich/ton-bot-example) to ensure there are no discrepancies. ## References diff --git a/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-js.md b/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-js.md index c155626d50f..f12ec1afe33 100644 --- a/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-js.md +++ b/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot-js.md @@ -2,13 +2,13 @@ description: At the end of the tutorial, you will write a beautiful bot that will be able to accept payments for your product directly in TON. --- -# Bot for sales of dumplings +# Bot for selling dumplings In this article, we'll create a simple Telegram bot for accepting payments in TON. ## 🦄 What it looks like -At the end of the tutorial, you will write a beautiful bot that will be able to accept payments for your product directly in TON. +By the end of the tutorial, you will have a fully functional bot that can accept payments for your product directly in TON. The bot will look like this: @@ -16,22 +16,22 @@ The bot will look like this: ## 📖 What you'll learn You'll learn how to: - - Create a Telegram bot in NodeJS using grammY - - Work with public TON Center API + - Create a Telegram bot in NodeJS using grammY, + - Work with the public TON Center API. -> Why do we use grammY? -Because grammY is a modern, young, high-level framework for comfortable & fast development of telegram bots on JS/TS/Deno, in addition to this grammY has great [documentation](https://grammy.dev) and an active community that can always help you. +> Why use grammY? +grammY is a modern, high-level framework designed for fast and efficient development of Telegram bots using JavaScript, TypeScript, or Deno. It features excellent [documentation](https://grammy.dev) and an active community ready to help. ## ✍️ What you need to get started Install [NodeJS](https://nodejs.org/en/download/) if you haven't yet. -Also you need these libraries: - - grammy - - ton - - dotenv +You will also need the following libraries: + - grammy, + - ton, + - dotenv. -You can install them with one command in the terminal. +You can install them with a single terminal command. ```bash npm2yarn npm install ton dotenv grammy @grammyjs/conversations ``` @@ -48,15 +48,15 @@ src ├── app.js .env ``` -* `bot/start.js` & `bot/payment.js` - files with handlers for telegram bot -* `src/ton.js` - file with business logic related to TON -* `app.js` - file for initializing and launching the bot +* `bot/start.js` & `bot/payment.js` - Handlers for the Telegram bot, +* `src/ton.js` - Business logic related to TON, +* `app.js` - Initializes and launches the bot. -Now let's begin writing code! +Now let's start writing the code! ## Config -Let's start with `.env`. We just need to set a few parameters in it. +Let's begin with `.env`. You need to set the following parameters: **.env** ``` @@ -67,39 +67,37 @@ OWNER_WALLET= ``` Here you need to fill in the values in the first four lines: - - `BOT_TOKEN` is your Telegram Bot token which you can get after [creating a bot](https://t.me/BotFather). - - `OWNER_WALLET` is your project's wallet address which will accept all payments. You can just create a new TON wallet and copy its address. - - `API_KEY` is your API key from TON Center which you can get from [@tonapibot](https://t.me/tonapibot)/[@tontestnetapibot](https://t.me/tontestnetapibot) for the mainnet and testnet, respectively. - - `NETWORK` is about on what network your bot will run - testnet or mainnet + - `BOT_TOKEN` - Your Telegram bot token, obtained after [creating a bot](https://t.me/BotFather). + - `OWNER_WALLET` - Your project's wallet address for receiving payments. You can create a new TON wallet and copy its address. + - `API_KEY` - Your API key from TON Center, available via [@tonapibot](https://t.me/tonapibot)/[@tontestnetapibot](https://t.me/tontestnetapibot) for the Mainnet and Testnet, respectively. + - `NETWORK` - The network on which your bot will operate: Testnet or Mainnet. -That's all for the config file, so we can move forward! +With the config file set up, we can move forward! ## TON Center API -In the `src/services/ton.py` file we'll declare a functions to verify the existence of a transaction and generate links for a quick transition to the wallet application for payment +In `src/services/ton.py`, we will define functions to verify transactions and generate payment links. ### Getting the latest wallet transactions -Our task is to check the availability of the transaction we need from a certain wallet. +Our goal is to check whether a specific transaction exists in a wallet. -We will solve it like this: -1. We will receive the last transactions that were received to our wallet. Why ours? In this case, we do not have to worry about what the user's wallet address is, we do not have to confirm that it is his wallet, we do not have to store this wallet anywhere. -2. Sort and leave only incoming transactions -3. Let's go through all the transactions, and each time we will check whether the comment and the amount are equal to the data that we have -4. celebrating the solution of our problem🎉 +How to solve it: +1. Retrieve the latest transactions for our wallet. Why our wallet? In this case, we do not have to worry about what the user's wallet address is, we do not have to confirm that it is their wallet, and we do not have to store this wallet. +2. Filter incoming transactions only. +3. Iterate through transactions and verify if the comment and amount match our data. +4. Celebrate the solution to our problem. #### Getting the latest transactions -If we use the TON Center API, then we can refer to their [documentation](https://toncenter.com/api/v2/) and find a method that ideally solves our problem - [getTransactions](https://toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get) +Using the TON Center API, we can refer to their [documentation](https://toncenter.com/api/v2/) and call the [getTransactions](https://toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get) method with just the wallet address. We also use the limit parameter to restrict the response to 100 transactions. -One parameter is enough for us to get transactions - the wallet address for accepting payments, but we will also use the limit parameter in order to limit the issuance of transactions to 100 pieces. - -Let's try to call a test request for the `EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N` address (by the way, this is the TON Foundation address) +For example, a test request for `EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N` (this is the TON Foundation address): ```bash curl -X 'GET' \ 'https://toncenter.com/api/v2/getTransactions?address=EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N&limit=100' \ -H 'accept: application/json' ``` -Great, now we have a list of transactions on hand in ["result"], now let's take a closer look at 1 transaction +Great, now we have a list of transactions on hand in `["result"]`, now let's take a closer look at 1 transaction. ```json @@ -134,26 +132,26 @@ Great, now we have a list of transactions on hand in ["result"], now let's take } ``` -From this json file, we can understand some information that can be usefull for us: +From this JSON file, we can extract some insights: -- This is an incoming transaction, since the "out_msgs" field is empty -- We can also get a comment of the transaction, its sender and the transaction amount +- The transaction is incoming, which is indicated by an empty `out_msgs` field. +- We can extract the transaction comment, sender, and amount. -Now we're ready to create a transaction checker +Now, we're ready to create a transaction checker. -### Work with TON +### Working with TON -Let's start by importing the necessary library TON +Start with importing the required TON library: ```js import { HttpApi, fromNano, toNano } from "ton"; ``` -Let's think about how to check if the user has sent the transaction we need. +Think about how to check if the user has sent the transaction we need. -Everything is elementary simple. We can just sort only incoming transactions to our wallet, and then go through the last 100 transactions, and if a transaction is found that has the same comment and amount, then we have found the transaction we need! +It's all very simple. We can simply sort only incoming transactions to our wallet, and then go through the last 100 transactions, and if there is a transaction with the same comment and amount, then we have found the transaction we need! -Let's start with initializing the http client, for convenient work with TON +Initialize the http client for convenient work with TON: ```js export async function verifyTransactionExistance(toWallet, amount, comment) { const endpoint = @@ -166,23 +164,23 @@ export async function verifyTransactionExistance(toWallet, amount, comment) { { apiKey: process.env.TONCENTER_TOKEN } ); ``` -Here we simply generate the endpoint url based on which network is selected in the config. And after that we initialize the http client. +Here we simply generate the endpoint url based on which network is selected in the configuration. And after that we initialize the http client. -So, now we can get the last 100 transactions from the owner's wallet +So, now we can get the last 100 transactions from the owner's wallet. ```js const transactions = await httpClient.getTransactions(toWallet, { limit: 100, }); ``` -and filter, leaving only incoming transactions (if the out_msgs of transaction is empty, we leave it) +Filter, leaving only incoming transactions (if the out_msgs of the transaction is empty, we leave it). ```js let incomingTransactions = transactions.filter( (tx) => Object.keys(tx.out_msgs).length === 0 ); ``` -Now we just have to go through all the transactions, and provided that the comment and the transaction value match, we return true +Now we just have to go through all the transactions. If a matching transaction is found, we return true. ```js for (let i = 0; i < incomingTransactions.length; i++) { let tx = incomingTransactions[i]; @@ -203,10 +201,10 @@ Now we just have to go through all the transactions, and provided that the comme return false; ``` -Note that value is in nanotons by default, so we need to divide it by 1 billion or we can just use `fromNano` method from the TON library. -And that's all for the `verifyTransactionExistance` function! +Since values are in nanotons by default, we divide by 1 billion or use the `fromNano` method from the TON library. +And that's it for the `verifyTransactionExistance` function! -Now we can create function to generate link for a quick transition to the wallet application for payment +Finally, we create a function to generate a payment link by embedding the transaction parameters in a URL. ```js export function generatePaymentLink(toWallet, amount, comment, app) { if (app === "tonhub") { @@ -219,7 +217,7 @@ export function generatePaymentLink(toWallet, amount, comment, app) { )}&text=${comment}`; } ``` -All we need is just to substitute the transaction parameters in the URL. Without forgetting to transfer the value of the transaction to nano. +All we need is just to substitute the transaction parameters in the URL. Make sure to convert the transaction value to nano. ## Telegram bot @@ -239,12 +237,14 @@ import { import handleStart from "./bot/handlers/start.js"; ``` -Let's set up dotenv module to comfy work with environment variables that we set at .env file +Set up the dotenv module to work with environment variables: + ```js dotenv.config(); ``` -After that we create a function that will run our project. In order for our bot not to stop if any errors appear, we add this code +Now, define a function to run the bot. To prevent it from stopping due to errors, include: + ```js async function runApp() { console.log("Starting app..."); @@ -255,7 +255,7 @@ async function runApp() { }); ``` -Now initialize the bot and the necessary plugins +Next, initialize the bot and the necessary plugins. ```js // Initialize the bot const bot = new Bot(process.env.BOT_TOKEN); @@ -267,9 +267,9 @@ Now initialize the bot and the necessary plugins bot.use(createConversation(startPaymentProcess)); ``` -Here we use `BOT_TOKEN` from our config that we made at the beginning of the tutorial. +Here we use `BOT_TOKEN` from our configuration we created at the beginning of the tutorial. -We initialized the bot but it's still empty. We must add some functions for interaction with the user. +We have initialized the bot, but it is still empty. We need to add some features to interact with the user. ```js // Register all handelrs bot.command("start", handleStart); @@ -280,7 +280,7 @@ We initialized the bot but it's still empty. We must add some functions for inte ``` Reacting to the command/start, the handleStart function will be executed. If the user clicks on the button with callback_data equal to "buy", we will start our "conversation", which we registered just above. And when we click on the button with callback_data equal to "check_transaction", we will execute the checkTransaction function. -And all that remains for us is to launch our bot and output a log about a successful launch +Finally, launch the bot and output a log a success message. ```js // Start bot await bot.init(); @@ -292,7 +292,7 @@ And all that remains for us is to launch our bot and output a log about a succes #### /start Command -Let's begin with the `/start` command handler. This function will be called when the user launches the bot for the first time, restarts it +Let's begin with the `/start` command handler. This function is triggered when a user starts or restarts the bot. ```js import { InlineKeyboard } from "grammy"; @@ -310,14 +310,13 @@ Welcome to the best Dumplings Shop in the world and concurrently an ); } ``` -Here we first import the InlineKeyboard from the grammy module. After that, we create an inline keyboard in the handler with an offer to buy dumplings and a link to this article (a bit of recursion here😁). -.row() stands for the transfer of the next button to a new line. -After that, we send a welcome message with the text (important, I use html markup in my message to decorate it) along with the created keyboard -The welcome message can be anything you want. +First, import the InlineKeyboard from the grammy module. Then, create an inline keyboard offering to buy dumplings and linking to this tutorial. +The .row() method places the next button on a new line. +We send a welcome message (formatted with HTML) along with the keyboard. You can customize this message as needed. #### Payment process -As always, we will start our file with the necessary imports +We begin by importing necessary modules: ```js import { InlineKeyboard } from "grammy"; @@ -327,13 +326,14 @@ import { verifyTransactionExistance, } from "../../services/ton.js"; ``` -After that, we will create a startPaymentProcess handler, which we have already registered in the app.js for execution when a certain button is pressed +After that, we will create a startPaymentProcess handler, which we have already registered in the app.js. This function is executed when a specific button is pressed. + +To remove the spinning watch icon in Telegram, we acknowledge the callback before proceeding. -In the telegram when you click on the inline button a spinning watch appears in order to remove them, we respond to the callback ```js await ctx.answerCallbackQuery(); ``` -After that, we need to send the user a picture of dumplings, ask him to send the number of dumplings that he wants to buy. And we are waiting for him to enter this number +Next, we need to send the user a picture of dumplings, ask them to send the number of dumplings that they want to buy. Wait for the user to enter this number. ```js await ctx.replyWithPhoto( "https://telegra.ph/file/bad2fd69547432e16356f.jpg", @@ -346,7 +346,7 @@ After that, we need to send the user a picture of dumplings, ask him to send the // Wait until the user enters the number const count = await conversation.form.number(); ``` -Now we calculate the total amount of the order and generate a random string, which we will use to comment on the transaction and add the dumplings postfix +Next, we calculate the total amount of the order and generate a random string that we will use for the transaction comment and add the postfix `"dumplings"`. ```js // Get the total cost: multiply the number of portions by the price of the 1 portion const amount = count * 3; @@ -354,13 +354,13 @@ Now we calculate the total amount of the order and generate a random string, whi const comment = Math.random().toString(36).substring(2, 8) + "dumplings"; ``` -And we save the resulting data to the session so that we can get this data in the next handler. +Save the resulting data to the session so that we can get this data in the next handler. ```js conversation.session.amount = amount; conversation.session.comment = comment; ``` -We generate links to go to a quick payment and create an inline keyboard +We generate links for quick payment and create a built-in keyboard. ```js const tonhubPaymentLink = generatePaymentLink( process.env.OWNER_WALLET, @@ -382,7 +382,8 @@ const tonhubPaymentLink = generatePaymentLink( .row() .text(`I sent ${amount} TON`, "check_transaction"); ``` -And we send our message with the keyboard, where we ask the user to send a transaction to our wallet address with a randomly generated comment +Send the message using the keyboard, in which ask the user to send a transaction to our wallet address with a randomly generated comment. + ```js await ctx.reply( ` @@ -390,13 +391,13 @@ Fine, all you have to do is transfer ${amount} TON to the wallet ${process WARNING: I am currently working on ${process.env.NETWORK} -P.S. You can conveniently make a transfer by clicking on the appropriate button below and confirm the transaction in the offer`, +P.S. You can conveniently make a transfer by clicking on the appropriate button below and confirming the transaction in the offer`, { reply_markup: menu, parse_mode: "HTML" } ); } ``` -Now all we have to do is create a handler to check for the presence of a transaction +Now all we have to do is create a handler to check for the presence of a transaction. ```js export async function checkTransaction(ctx) { await ctx.answerCallbackQuery({ @@ -424,21 +425,20 @@ export async function checkTransaction(ctx) { } } ``` -All we are doing here is just checking for a transaction, and provided that it exists, we tell the user about it and reset the data in the session - +Next, simply check for a transaction, and if it exists, notify the user and flush the data in the session. -### Bot start +### Start of the bot -To start use this command: +To start the bot, use this command: ```bash npm2yarn npm run app ``` -If your bot doesn't work correctly, compare your code with code [from this repository](https://github.com/coalus/DumplingShopBot). If it didn't help, feel free to write me in telegram. You can find my telegram account below +If your bot isn't working correctly, compare your code with the code [from this repository](https://github.com/coalus/DumplingShopBot). If issues persist, feel free to contact me on Telegram. You can find my Telegram account below. ## References - - Made for TON as part of [ton-footsteps/58](https://github.com/ton-society/ton-footsteps/issues/58) - - By Coalus ([Telegram @coalus](https://t.me/coalus), [Coalus on GitHub](https://github.com/coalus)) - - [Bot Sources](https://github.com/coalus/DumplingShopBot) + - Made for TON as a part of [ton-footsteps/58](https://github.com/ton-society/ton-footsteps/issues/58). + - By Coalus ([Telegram @coalus](https://t.me/coalus), [Coalus on GitHub](https://github.com/coalus)). + - [Bot sources](https://github.com/coalus/DumplingShopBot). diff --git a/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot.md b/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot.md index effb1c880fa..c84e0076656 100644 --- a/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot.md +++ b/docs/v3/guidelines/dapps/tutorials/telegram-bot-examples/accept-payments-in-a-telegram-bot.md @@ -10,27 +10,26 @@ In this article, we'll guide you through the process of accepting payments in a In this article, you'll learn how to: -- create a Telegram bot using Python + Aiogram -- work with the public TON API (TON Center) -- work with SQlite database - -And finally: how to accept payments in a Telegram bot with the knowledge from previous steps. +- Create a Telegram bot using Python and Aiogram, +- Work with the public TON Center API, +- Work with an SQlite database, +- How to accept payments in a Telegram bot by applying the knowledge from previous steps. ## 📚 Before we begin -Make sure you have installed the latest version of Python and have installed the following packages: +Make sure you have installed the latest version of Python and the following packages: -- aiogram -- requests -- sqlite3 +- aiogram, +- requests. +- sqlite3. ## 🚀 Let's get started! -We'll follow the order below: +We'll follow this order: -1. Work with SQlite database -2. Work with the public TON API (TON Center) -3. Create a Telegram bot using Python + Aiogram +1. Work with an SQlite database. +2. Work with the public TON API (TON Center). +3. Create a Telegram bot using Python and Aiogram. 4. Profit! Let's create the following four files in our project directory: @@ -45,7 +44,7 @@ telegram-bot ## Config -In `config.json` we'll store our bot token and our public TON API key. +In `config.json`, we store our bot token and public TON API key. ```json { @@ -58,7 +57,7 @@ In `config.json` we'll store our bot token and our public TON API key. } ``` -In `config.json` we decide which network we'll use: `testnet` or `mainnet`. +In `config.json`, define whether you'll use use `Testnet` or `Mainnet`. ## Database @@ -66,10 +65,9 @@ In `config.json` we decide which network we'll use: `testnet` or `mainnet`. This example uses a local Sqlite database. -Create `db.py`. +Create a file called `db.py`. -To start working with the database, we need to import the sqlite3 module -and some modules for working with time. +To work with the database, import sqlite3 module and some modules for handling time. ```python import sqlite3 @@ -77,11 +75,11 @@ import datetime import pytz ``` -- `sqlite3`—module for working with sqlite database -- `datetime`—module for working with time -- `pytz`—module for working with timezones +- `sqlite3`—module for working with sqlite database, +- `datetime`—module for working with time. +- `pytz`—module for working with timezones. -Next, we need to create a connection to the database and a cursor to work with it: +Next, establish a connection to the database and a cursor: ```python locCon = sqlite3.connect('local.db', check_same_thread=False) @@ -90,7 +88,7 @@ cur = locCon.cursor() If the database does not exist, it will be created automatically. -Now we can create tables. We have two of them. +We need two tables: #### Transactions: @@ -104,10 +102,10 @@ CREATE TABLE transactions ( ); ``` -- `source`—payer's wallet address -- `hash`—transaction hash -- `value`—transaction value -- `comment`—transaction comment +- `source`—payer's wallet address, +- `hash`—transaction hash, +- `value`—transaction value, +- `comment`—transaction comment. #### Users: @@ -121,17 +119,17 @@ CREATE TABLE users ( ); ``` -- `id`—Telegram user ID -- `username`—Telegram username -- `first_name`—Telegram user's first name -- `wallet`—user wallet address +- `id`—Telegram user ID, +- `username`—Telegram username, +- `first_name`—Telegram user's first name, +- `wallet`—user wallet address. -In the `users` table we store users :) Their Telegram ID, @username, -first name, and wallet. The wallet is added to the database on the first +The `users` table stores Telegram users along with their Telegram ID, @username, +first name, and wallet. The wallet is added to the database upon the first successful payment. The `transactions` table stores verified transactions. -To verify a transaction, we need the hash, source, value and comment. +To verify a transaction, we need a unique transaction hash, source, value, and comment. To create these tables, we need to run the following function: @@ -157,14 +155,14 @@ locCon.commit() This code will create the tables if they are not already created. -### Work with database +### Work with database -Let's analyze the situation: -User made a transaction. How to verify it? How to make sure that the same transaction is not confirmed twice? +Let's analyze the process: +A user makes a transaction. How do we verify it? How do we ensure that the same transaction isn't confirmed twice? -There is a body_hash in transactions, with the help of which we can easily understand whether there is a transaction in the database or not. +Each transaction includes a `body_hash`, which allows us to easily check whether the transaction is already in the database. -We add transactions to the database in which we are sure. The `check_transaction` function checks whether the found transaction is in the database or not. +We only add transactions that have been verified. The `check_transaction` function determines whether a given transaction is already in the database. `add_v_transaction` adds transaction to the transactions table. @@ -184,7 +182,7 @@ def check_transaction(hash): return False ``` -`check_user` checks if the user is in the database and adds him if not. +`check_user` verifies if the user exists in the database and adds them if not. ```python def check_user(user_id, username, first_name): @@ -199,7 +197,7 @@ def check_user(user_id, username, first_name): return True ``` -The user can store a wallet in the table. It is added with the first successful purchase. The `v_wallet` function checks if the user has an associated wallet. If there is, then returns it. If not, then adds. +The user can store a wallet in the table. It is added with the first successful purchase. The `v_wallet` function checks if the user has an associated wallet. If not, it adds the wallet upon the user's first successful purchase. ```python def v_wallet(user_id, wallet): @@ -214,7 +212,7 @@ def v_wallet(user_id, wallet): return result[0] ``` -`get_user_wallet` simply returns the user's wallet. +`get_user_wallet` simply retrieves the user's wallet. ```python def get_user_wallet(user_id): @@ -223,8 +221,8 @@ def get_user_wallet(user_id): return result[0] ``` -`get_user_payments` returns the user's payments list. -This function checks if the user has a wallet. If he has, then it returns the payment list. +`get_user_payments` returns the user's payment history. +This function checks if the user has a wallet. If they do, it provides the list of their payments. ```python def get_user_payments(user_id): @@ -252,26 +250,27 @@ def get_user_payments(user_id): ## API -_We have the ability to interact with the blockchain using third-party APIs provided by some network members. With these services, developers can skip the step of running their own node and customizing their API._ +_We can interact with the blockchain using third-party APIs provided by network members. These services allow developers to bypass the need their own node and customize their API._ -### Required Requests +### Required requests -In fact, what do we need to confirm that the user has transferred the required amount to us? +What do we need to confirm that a user has transferred the required amount? -We just need to look at the latest incoming transfers to our wallet and find among them a transaction from the right address with the right amount (and possibly a unique comment). -For all of this, TON Center has a `getTransactions` method. +We simply need to check the latest incoming transfers to our wallet and find a transaction from the right address with the right amount (and possibly a unique comment). +For this, TON Center provides the `getTransactions` method. ### getTransactions -By default, if we apply it, we will get the last 10 transactions. However, we can also indicate that we need more, but this will slightly increase the time of a response. And, most likely, you do not need so much. +By default, this method retrieves the last 10 transactions. However, we can request more, though this slightly increases the response time. In most cases, requestin additional transactions is unnecessary. -If you want more, then each transaction has `lt` and `hash`. You can look at, for example, 30 transactions and if the right one was not found among them, then take `lt` and `hash` from the last one and add them to the request. +If more transactions are required, each transaction includes `lt` and `hash`. We can fetch, for example, the last 30 transactions. If the required transaction is not found, we can take `lt` and `hash` of the last transaction in the list and include them in a new request. -So you get the next 30 transactions and so on. +This allows us to retrieve the next 30 transactions, and so on. -For example, there is a wallet in the test network `EQAVKMzqtrvNB2SkcBONOijadqFZ1gMdjmzh1Y3HB1p_zai5`, it has some transactions: +For example, consider the wallet in the test network `EQAVKMzqtrvNB2SkcBONOijadqFZ1gMdjmzh1Y3HB1p_zai5`. -Using a [query](https://testnet.toncenter.com/api/v2/getTransactions?address=EQAVKMzqtrvNB2SkcBONOijadqFZ1gMdjmzh1Y3HB1p_zai5&limit=2&to_lt=0&archival=true) we will get the response that contains two transactions (some of the information that is not needed now has been hidden, you can see the full answer at the link above). +Using a [query](https://testnet.toncenter.com/api/v2/getTransactions?address=EQAVKMzqtrvNB2SkcBONOijadqFZ1gMdjmzh1Y3HB1p_zai5&limit=2&to_lt=0&archival=true) returns a response containing two transactions. +Note that some details have been omitted for clarity. ```json { @@ -313,7 +312,7 @@ Using a [query](https://testnet.toncenter.com/api/v2/getTransactions?address=EQA } ``` -We have received the last two transactions from this address. When adding `lt` and `hash` to the query, we will again receive two transactions. However, the second one will become the next one in a row. That is, we will get the second and third transactions for this address. +By adding `lt` and `hash` to the query, we can retrieve the next two two transactions in sequence. That is, instead of getting the first and second transactions, we will receive the second and third. ```json { @@ -351,13 +350,13 @@ We have received the last two transactions from this address. When adding `lt` a } ``` -The request will look like [this.](https://testnet.toncenter.com/api/v2/getTransactions?address=EQAVKMzqtrvNB2SkcBONOijadqFZ1gMdjmzh1Y3HB1p_zai5&limit=2<=1943166000003&hash=hxIQqn7lYD%2Fc%2FfNS7W%2FiVsg2kx0p%2FkNIGF6Ld0QEIxk%3D&to_lt=0&archival=true) +The request will look like as follows [this.](https://testnet.toncenter.com/api/v2/getTransactions?address=EQAVKMzqtrvNB2SkcBONOijadqFZ1gMdjmzh1Y3HB1p_zai5&limit=2<=1943166000003&hash=hxIQqn7lYD%2Fc%2FfNS7W%2FiVsg2kx0p%2FkNIGF6Ld0QEIxk%3D&to_lt=0&archival=true) We will also need a method `detectAddress`. -Here is an example of a Tonkeeper wallet address on testnet: `kQCzQJJBAQ-FrEFcvxO5sNxhV9CaOdK9CCfq2yCBnwZ4aCTb`. If we look for the transaction in the explorer, instead of the above address, there is: `EQCzQJJBAQ-FrEFcvxO5sNxhV9CaOdK9CCfq2yCBnwZ4aJ9R`. +Here is an example of a Tonkeeper wallet address on Testnet: `kQCzQJJBAQ-FrEFcvxO5sNxhV9CaOdK9CCfq2yCBnwZ4aCTb`. If we look for the transaction in the explorer, the address appears as: `EQCzQJJBAQ-FrEFcvxO5sNxhV9CaOdK9CCfq2yCBnwZ4aJ9R`. -This method returns us the “right” address. +This method provides us with the correctly formatted address. ```json { @@ -377,15 +376,13 @@ This method returns us the “right” address. } ``` -We need `b64url`. - -This method allows us to validate the user's address. +Additionally, we need `b64url`, which allows us to validate the user's address. -For the most part, that's all we need. +Basically, that's all we need. ### API requests and what to do with them -Let's go back to the IDE. Create the file `api.py`. +Now, let's move to the IDE andreate the `api.py` file. Import the necessary libraries. @@ -397,11 +394,11 @@ import json import db ``` -- `requests`—to make requests to the API -- `json`—to work with json -- `db`—to work with our sqlite database +- `requests`—to make requests to the API, +- `json`—to work with JSON, +- `db`—to work with our sqlite database. -Let's create two variables for storing the start of the requests. +Let's create two variables to store the base URLs for our requests. ```python # This is the beginning of our requests @@ -409,7 +406,7 @@ MAINNET_API_BASE = "https://toncenter.com/api/v2/" TESTNET_API_BASE = "https://testnet.toncenter.com/api/v2/" ``` -Get all API tokens and wallets from the config.json file. +We get all API tokens and wallets from the config.json file. ```python # Find out which network we are working on @@ -462,12 +459,11 @@ def get_address_transactions(): return response['result'] ``` -This function returns the last 30 transactions to our `WALLET`. - -Here you can see `archival=true`. It is needed so that we only take transactions from a node with a complete history of the blockchain. +This function returns the last 30 transactions for our `WALLET`. -At the output, we get a list of transactions—[{0},{1},...,{29}]. List of dictionaries in short. +The `archival=true` parameter ensures that transactions are retrieved from a node with a complete blockchain history. +At the output, we get a list of transactions, such as `[{0},{1},...,{29}]` which are represented as a list of dictionaries. And finally the last function: ```python @@ -499,15 +495,15 @@ def find_transaction(user_wallet, value, comment): return False ``` -At the input are the “correct” wallet address, amount and comment. If the intended incoming transaction is found, the output is True; otherwise, it is False. +At the input, we get the correct wallet address, amount and comment. If the expected incoming transaction is found, the output is True; otherwise, it is False. ## Telegram bot -First, let's create the basis for a bot. +First, let's establish the bot's foundation. ### Imports -In this part, we will import the necessary libraries. +In this part, we will import the required libraries. From `aiogram` we need `Bot`, `Dispatcher`, `types` and `executor`. @@ -541,7 +537,7 @@ import api ### Config setup -It is recommended that you store data such as `BOT_TOKEN` and your wallets for receiving payments in a separate file called `config.json` for convenience. +It is recommended to store data such as `BOT_TOKEN` and wallet addresses for receiving payments in a separate file called `config.json` for convenience. ```json { @@ -556,24 +552,22 @@ It is recommended that you store data such as `BOT_TOKEN` and your wallets for r #### Bot token -`BOT_TOKEN` is your Telegram bot token from [@BotFather](https://t.me/BotFather) +`BOT_TOKEN` is the Telegram bot token obtained from [@BotFather](https://t.me/BotFather) #### Working mode -In the `WORK_MODE` key, we will define the bot's mode of operation—in the test or main network; `testnet` or `mainnet` respectively. +The `WORK_MODE` key defines whether the bot operates in the test or main network; `testnet` or `mainnet` respectively. #### API tokens -API tokens for `*_API_TOKEN` can be obtained in the [TON Center](https://toncenter.com/) bots: +API tokens for `*_API_TOKEN` can be obtained from the [TON Center](https://toncenter.com/) bots: -- for mainnet — [@tonapibot](https://t.me/tonapibot) -- for testnet — [@tontestnetapibot](https://t.me/tontestnetapibot) +- Mainnet — [@tonapibot](https://t.me/tonapibot) +- Testnet — [@tontestnetapibot](https://t.me/tontestnetapibot) -#### Connect config to our bot +#### Connecting the config to our bot -Next, we finish setting up the bot. - -Get the token for the bot to work from `config.json` : +Next, we complete the bot setup by retrieving the bot token from `config.json` : ```python with open('config.json', 'r') as f: @@ -602,7 +596,7 @@ dp = Dispatcher(bot, storage=MemoryStorage()) ### States -We need States to split the bot workflow into stages. We can specialize each stage for a specific task. +States allow us to devide the bot workflow into stages, each designated for a specific task. ```python class DataInput (StatesGroup): @@ -612,7 +606,7 @@ class DataInput (StatesGroup): PayState = State() ``` -For details and examples see the [Aiogram documentation](https://docs.aiogram.dev/en/latest/). +For details and examples, refer to the [Aiogram documentation](https://docs.aiogram.dev/en/latest/). ### Message handlers @@ -620,7 +614,7 @@ This is the part where we will write the bot interaction logic. We'll be using two types of handlers: -- `message_handler` is used to handle messages from user. +- `message_handler` is used to handle messages from users, - `callback_query_handler` is used to handle callbacks from inline keyboards. If we want to handle a message from the user, we will use `message_handler` by placing `@dp.message_handler` decorator above the function. In this case, the function will be called when the user sends a message to the bot. @@ -654,13 +648,13 @@ async def cmd_start(message: types.Message): await DataInput.firstState.set() ``` -In the decorator of this handler we see `state='*'`. This means that this handler will be called regardless of the state of bot. If we want the handler to be called only when the bot is in a specific state, we will write `state=DataInput.firstState`. In this case, the handler will be called only when the bot is in the `firstState` state. +In the decorator of a handler, you may see `state='*'`, meaning the handler will be triggered regardless of the bot's state. If we want the handler to activate only in a specific state, we specify it, such as `state=DataInput.firstState`, ensuring the handler runs only when the bot is in `firstState`. After the user sends `/start` command, the bot will check if the user is in database using `db.check_user` function. If not, it will add him. This function will also return the bool value and we can use it to address the user differently. After that, the bot will set the state to `firstState`. #### /cancel -Next is the /cancel command handler. It is needed to return to the `firstState` state. +The /cancel command returns the bot to `firstState`. ```python @dp.message_handler(commands=['cancel'], state="*") @@ -672,7 +666,7 @@ async def cmd_cancel(message: types.Message): #### /buy -And, of course, `/buy` command handler. In this example we will sell different types of air. We will use the reply keyboard to choose the type of air. +And, of course, there is a `/buy` command handler. In this example, we sell different types of air and use the reply keyboard to choose the type. ```python # /buy command handler @@ -721,27 +715,27 @@ Use... await state.update_data(air_type="Just pure 🌫") ``` -...to store the air type in FSMContext. After that, we set the state to `WalletState` and ask the user to send his wallet address. +...to store the air type in FSMContext. After that, we set the state to `WalletState` and ask the user to send their wallet address. -This handler will work only when `WalletState` is set and will be waiting for a message from user with the wallet address. +This handler activates only in WalletState, expecting a valid wallet address. -The next handler seems to be very complicated but it's not. First, we check if the message is a valid wallet address using `len(message.text) == 48` because wallet address is 48 characters long. After that, we use `api.detect_address` function to check if the address is valid. As you remember from the API part, this function also returns "Correct" address which will be stored in the database. +Consider the next handler. It may seem complex, but it isn’t. First, we verify whether the message contains a wallet address of the correct length using `len(message.text) == 48`. Then, we call the `api.detect_address` function to validate the address. This function also returns the standardized *correct* address, which is stored in the database. After that, we get the air type from FSMContext using `await state.get_data()` and store it in `user_data` variable. Now we have all the data required for the payment process. We just need to generate a payment link and send it to the user. Let's use the inline keyboard. -Three buttons will be created for payment in this example: +The bot provides three payment buttons: -- for official TON Wallet -- for Tonhub -- for Tonkeeper +- TON wallet, +- Tonhub, +- Tonkeeper. -The advantage of special buttons for wallets is that if the user does not yet have a wallet, then the site will prompt him to install one. +These buttons are advantageous of special buttons because they guide users to install a wallet if they don't have one You are free to use whatever you want. -And we need a button that the user will press after transaction so we can check if the payment was successful. +And we need a button that the user will press after tmaking a transaction, allowing the bot to verify the payment. ```python @dp.message_handler(state=DataInput.WalletState) @@ -779,7 +773,7 @@ async def user_wallet(message: types.Message, state: FSMContext): #### /me -One last message handler that we need is for `/me` command. It shows the user's payments. +One last message handler is `/me`. It shows the user's payments. ```python # /me command handler @@ -798,7 +792,9 @@ async def cmd_me(message: types.Message): ### Callback handlers -We can set callback data in buttons which will be sent to the bot when the user presses the button. In the button that the user will press after the transaction, we set callback data to "check." As a result, we need to handle this callback. +Callback data is embedded in buttons, allowing the bot to recognize user actions. + +For example, the “Payment Confirmed” button sends the callback "check", which the bot must process. Callback handlers are very similar to message handlers but they have `types.CallbackQuery` as an argument instead of `message`. Function decorator is also different. @@ -820,9 +816,9 @@ async def check_transaction(call: types.CallbackQuery, state: FSMContext): await DataInput.firstState.set() ``` -In this handler we get user data from FSMContext and use `api.find_transaction` function to check if the transaction was successful. If it was, we store the wallet address in the database and send a notification to the user. After that, the user can find his transactions using `/me` command. +In this handler we get user data from FSMContext and use `api.find_transaction` to check if the transaction was successful. If so, the wallet address is stored in the database, and the bot notifies the user. After that, the user can check their transaction anytime using `/me`. -### Last part of main.py +### Finalizing main.py At the end, don't forget: @@ -842,20 +838,20 @@ All code of `main.py` can be found [here](https://github.com/LevZed/ton-payments ## Bot in action -We finally did it! You should now have a working bot. You can test it! +Congratulations! The bot is ready. You can test it! Steps to run the bot: 1. Fill in the `config.json` file. 2. Run `main.py`. -All files must be in the same folder. To start the bot, you need to run `main.py` file. You can do it in your IDE or in the terminal like this: +All files must be in the same folder. To start the bot, you need to run the `main.py` file. You can do it in your IDE or in the terminal like this: ``` python main.py ``` -If you have any errors, you can check them in the terminal. Maybe you missed something in the code. +If errors occur, check them in the terminal. Maybe you have missed something in the code. Example of a working bot [@AirDealerBot](https://t.me/AirDealerBot)