Telegram Bot

Step-by-step Tutorial: From Raw Repo to Telegram Bot based on Aptos stream!

Let's dive into the exciting world of building a Telegram bot that sends messages based on Data Stream from Aptos Blockchain!

  1. Step 0: Empty Boilerplate from Go SDK :triangular-flag-on-post:
  2. Step 1: Raw Repo with Boilerplate โœจ
  3. Step 2: Added Stream๐ŸŒŠ
  4. Step 3: Added Filtering๐Ÿงช๐Ÿ”
  5. Step 4: Added Telegram Bot ๐Ÿค–๐Ÿ’ฌ

Step-by-step tutorial

  1. Step 0: Empty Boilerplate from Go SDK :arrow-right: Step 1: Raw Repo with Boilerplateโœจ

    1. 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:

    2. To get started, clone the repository by running the following command in your shell:

      git clone [email protected]:SyntropyNet/aptos-hackathon-2023.git
    3. Navigate to the project directory:

      cd aptos-hackathon-2023/0-GoingOn-empty-repo
    4. Once you're in the right place, let's start with the basic code inStep 0: Empty Boilerplate from Go SDK

    5. Connect to the NATS server by setting the NATS server address ( and adding your Access Token:

      1. Our NATS server address:
      2. add your or our Access token: SAAEPLBNRA56YZTG4XN674JQXJ6L5KKVNUB7XUW5YOFJXKV2PYQ2FJJ4ZU
    6. When you run make serve, you should see the awesome message Connected to NATS server in your terminal! ๐Ÿš€๐Ÿ”Œ`

  2. Step 1: Raw Repo with Boilerplateโœจ :arrow-right: 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 saying Got msg on: syntropy.aptos.mainnet.tx will be printed in the terminal. Exciting, right? ๐Ÿ˜„

    1. Subscribe to Aptos topic (stream).
      aptosTopic = "syntropy.aptos.mainnet.tx"
    2. Add a handler function to handle the stream.
    	service.AddHandler(aptosTopic, func(data []byte) error {
    		return PrintData(ctx, service, data)
    1. 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)
      	return nil
    2. 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

  3. Step 2: Added Stream๐ŸŒŠ :arrow-right: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! ๐Ÿ“‰๐Ÿ’ธ

    1. Now we have the data flowing, let's have a look at the files aptos.json and aptostypes.go - first one contains a raw Aptos Transaction Data, second one - "translates" it to the Go stuct, so we can easy reuse it in PrintData function.

    2. Let's use AptosTransaction type in the PritnData function

      	var aptosTx AptosTransaction
      	if err := json.Unmarshal(data, &aptosTx); err != nil {
      		log.Printf("ERROR: %s", err.Error())
      		return nil
    3. Ok, so now we can print even more in the message:

      	address := aptosTx.Txn.Sender
      	depositAddr := ""
      	depositAmount := ""
      	withdrawAmount := ""
    4. Let's do the basic filtering and show only user_transactions

      	if strings.Compare(aptosTx.Txn.Type, "user_transaction") != 0 {
      		return nil
    5. 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
    6. 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)
    7. The final message in the terminal after typingmake serve will look like this:

      Got msg on: syntropy.aptos.mainnet.tx, sender address: 0x1d8727df513fa2a8785d0834e40b34223daff1affc079574082baadb74b66ee4, receiver address: 0x54ad3d30af77b60d939ae356e6606de9a4da67583f02b962d2d3f2e481484e90, withdraw amount: 520400, deposit amount: 520400
  4. Step 3: Added Filtering๐Ÿงช๐Ÿ” :arrow-right: Step 4: Added Telegram Bot ๐Ÿค–๐Ÿ’ฌ

    1. 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: ๐Ÿ˜„๐Ÿ‘ฅ

    2. Input the Telegram bot and chat details:

      	botToken    = "6203625523:AAHGYx1judXEh6sq8sOjYSVydFGxMeXgdog"
      	chatID      = -842363663
    3. Create 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 {
    4. Handle sending a message.

      func sendTelegramMessage(message string) {
      	msg := tgbotapi.NewMessage(chatID, message)
      	// Send the message
      	_, err := bot.Send(msg)
      	if err != nil {
    5. Send a message in the PrintData function.