Telegram Bot
Let's dive into the exciting world of building a Telegram bot that sends messages based on Data Stream from Aptos Blockchain!
- Step 0: Empty Boilerplate from Go SDK
- Step 1: Raw Repo with Boilerplate
- Step 2: Added Stream
- Step 3: Added Filtering
- Step 4: Added Telegram Bot
Step-by-step tutorial
Step 0: Empty Boilerplate from Go SDK -> Step 1: Raw Repo with Boilerplate
First things first, set up your own dApp in the Developer Portal and subscribe to the Apos topic. If you prefer, you can use the following Access Token:
SAAJRV3Y3BHN4X223WESAO6EMTYNLHOANORCO5VSTEZETZUXZGSNBK2BKM
To get started, clone the repository by running the following command in your shell:
git clone [email protected]:SyntropyNet/aptos-hackathon-2023.git
Navigate to the project directory:
cd aptos-hackathon-2023/0-GoingOn-empty-repo
Once you're in the right place, let's start with the basic code in Step 0: Empty Boilerplate from Go SDK
Connect to the NATS server by setting the NATS server address (34.107.87.29) and adding your Access Token:
- Our NATS server address:
34.107.87.29
- add your or our Access token:
SAAEPLBNRA56YZTG4XN674JQXJ6L5KKVNUB7XUW5YOFJXKV2PYQ2FJJ4ZU
- Our NATS server address:
When you run make serve, you should see the awesome message
Connected to NATS server
in your terminal!
Step 1: Raw Repo with Boilerplate -> Step 2: Added Stream
In this step, we'll subscribe to the Aptos topic (stream) and add a handler function to handle the stream. When you receive data, a cool message sayingGot msg on: syntropy.aptos.mainnet.tx
will be printed in the terminal.Subscribe to Aptos topic (stream).
aptosTopic = "syntropy.aptos.mainnet.tx"
Add a handler function to handle the stream.
service.AddHandler(aptosTopic, func(data []byte) error {
return PrintData(ctx, service, data)
})Add the ability to print a message in the terminal.
func PrintData(ctx context.Context, service *pubsub.NatsService, data []byte) error {
message := fmt.Sprintf("Got msg on: %s", aptosTopic)
log.Println(message)
return nil
}When you type
make serve
in your terminal, you should be able to see the following message every time there's data flowing:
Got msg on: syntropy.aptos.mainnet.tx
Step 2: Added Stream -> Step 3: Added Filtering
Let's enhance our code by filtering the data. We'll use the aptos.json and aptostypes.go files to work with Aptos Transaction Data. By implementing basic filtering and event-based filtering, we'll show only user transactions. The printed message will now include the sender address, receiver address, withdraw amount, and deposit amount. Time to make sense of the data and add some order!Now we have the data flowing, let's have a look at the files
aptos.json
andaptostypes.go
- first one contains a raw Aptos Transaction Data, second one - "translates" it to the Go stuct, so we can easy reuse it inPrintData
function.Let's use
AptosTransaction
type in the PritnData functionvar aptosTx AptosTransaction
if err := json.Unmarshal(data, &aptosTx); err != nil {
log.Printf("ERROR: %s", err.Error())
return nil
}Ok, so now we can print even more in the message:
address := aptosTx.Txn.Sender
depositAddr := ""
depositAmount := ""
withdrawAmount := ""Let's do the basic filtering and show only
user_transactions
if strings.Compare(aptosTx.Txn.Type, "user_transaction") != 0 {
return nil
}Let's filter using
events
attached to the transaction:deposit := false
withdraw := false
events := aptosTx.Txn.Events
for _, evt := range events {
t := evt.Type
depositAddr = evt.GUID.AccountAddress
if strings.Contains(t, "::coin::DepositEvent") {
if deposit {
log.Println("Multiple deposit events found!", depositAmount, depositAddr)
}
depositAmount = evt.Data.Amount
deposit = true
}
if strings.Contains(t, "::coin::WithdrawEvent") {
if withdraw {
log.Println("Multiple withdraw events found!", withdrawAmount)
}
withdrawAmount = evt.Data.Amount
withdraw = true
}
}Let's print the expected message:
message := fmt.Sprintf("Got msg on: %s, sender address: %s, receiver address: %s, withdraw amount: %s, deposit amount: %s",
aptosTopic, address, depositAddr, withdrawAmount, depositAmount)
log.Println(message)The final message in the terminal after typing
make serve
will look like this:Got msg on: syntropy.aptos.mainnet.tx, sender address: 0x1d8727df513fa2a8785d0834e40b34223daff1affc079574082baadb74b66ee4, receiver address: 0x54ad3d30af77b60d939ae356e6606de9a4da67583f02b962d2d3f2e481484e90, withdraw amount: 520400, deposit amount: 520400
Step 3: Added Filtering -> Step 4: Added Telegram Bot
We're almost there! The Telegram bot is ready for action. No need to worry about setting it up, it's all done for you! If you want to use your own bot, talk to @botfather on Telegram and he'll guide you. For following along, join the group here: https://t.me/+cB1n8O6xerw5ODBk
Input the Telegram bot and chat details:
botToken = "6203625523:AAHGYx1judXEh6sq8sOjYSVydFGxMeXgdog"
chatID = -842363663Create a bot instance in the main function
// Add this after the const
var bot *tgbotapi.BotAPI
// Paste this in main function after connecting to NATS
// Create a new bot instance
var err error
bot, err = tgbotapi.NewBotAPI(botToken)
if err != nil {
log.Panic(err)
}Handle sending a message.
func sendTelegramMessage(message string) {
msg := tgbotapi.NewMessage(chatID, message)
// Send the message
_, err := bot.Send(msg)
if err != nil {
log.Println(err)
}
}Send a message in the PrintData function.
sendTelegramMessage(message)