Algorand - Telegram implementation Using python. Part 1

Algorand - Telegram implementation Using python. Part 1

By Ddev | Ddev@ALgorand | 4 Nov 2020


056679e7df19795f80e68ceda77be9ea0aa71ba0344d558882ea3dc62b1e0a9b.png

From writing codes to application design to deployment can be tough especially if you're young in the industry. I am in this category and I love to explore daily to see how I can make myself relevant to the world by doing something new and in a different way, perhaps most things we do aren't really new under the sky but how we do it and the end result matters. Let's hit the nail on the head.

Telegram is a messaging application with fascinating end to end encryption which has made it famous to date. Virtually every applications we use is simply a human - machine (programs) interaction. You input or hit a command button and a return message is sent back to you. This is how Telegram bot operates. You call commands, while it performs some background processes and return to you the result. If you are on a search for application with enormous user base to increase visibility for your business, product, services or project, you consider exploring Telegram.

Algorand is a technology company that built and developed the world’s first open, permissionless, pure proof-of-stake blockchain protocol that, without forking, provides the necessary security, scalability, and decentralization needed for today’s economy. With an award-winning team, we enable traditional finance and decentralized financial businesses to embrace the world of frictionless finance.


NOTE: This solution is available in video format at the end of this article.


This solution comes with the video version which  I will release shortly after this article is published. Things you will be exposed to are :

  • Working with Algorand python SDK
  • Implement your codes using Telegram.
  • Deploy to a cloud service, so that your application can be viewed all around the world.

Requirements

  • Install Python Algorand SDK
  • Install Python Application
  • An Editor.
  • Telegram Module : run ==> pip install python-telegram-bot from the CLI (Window Os)
  • Telegram Application

I assume you have installed all of the above listed requirements. With this application, users will be able to perform the following functions that run on the Algorand Testnet:

  • Create an account. 
  • Query the balance of the generated account's address. 
  • Get Mnemonic Phrase from private key. 
  • Check account status. 

Firstly, we will need a Telegram identity which you can get from the Bot father.

  • Open the Telegram app, search for Bot father and Start a conversation with it. 
  • Send the /newbot command to create a new bot for yourself. 
  • Follow the instructions to supply the Bot name and username. This should get you a new bot if the steps are successfully processed. A string of characters will be provided to you which is your bot's token. Keep it safe as anyone with it can control your bot.
  • We will use the token later.

8f02e84938b1d4da1d473bf4373e489e2b9d85473808811e6d5889d6a8f6f6b7.png


Open your editor, I'd recommend Pycharm if you don't already use one. Import the necessary modules. You may need to first familiarize yourself with what the package and/or the modules do so as to use it effectively. Head to the github. 

# Create a python file called connection.py and paste the following code. 
# To get the url and the token, sign up on purestake.com
from algosdk.v2client import algod

url = "SPECIFY THE V2 URL HERE"
algod_token = "ALGOD TOKEN HERE"


def connect():
    # Using the third party API
    algod_url = url
    algod_auth = algod_token  # os.environ.get('ALGODTOKEN')
    headers = {"X-API-Key": algod_token}
    try:
        return algod.AlgodClient(algod_auth, algod_url, headers)
    except Exception as e:
        print(e)


algod_client = connect()
params = algod_client.suggested_params()

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Import the necessary modules.

import logging
from algosdk import account, mnemonic
from connection import algod_client
from telegram import (ReplyKeyboardMarkup, InlineKeyboardButton,  InlineKeyboardMarkup)
import os

from telegram.ext import (
    Updater,
    CommandHandler,
    CallbackQueryHandler,
    Filters,
    ConversationHandler,
    PicklePersistence,
)

# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)

logger = logging.getLogger(__name__)

# Use the token you got from bot father here
TOKEN = <YOUR_BOT_TOKEN_HERE>

# Displays these as commands when the start command is invoked
# Also, a way of grabbing input from the user
reply_keyboard = [
    ['/Create_account', '/Get_Mnemonics_from_pky'],
    [
        '/Query_account_balance', 
        '/Account_status', '/enquire'
    ],
    ['/About', '/help', '/Done'],
]

# Maps the above parameters to the keyboard, so when user clicks 
# on any, it is captured as command
# Set the one-time keyboard to true.
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)

# Utility that instantiates conversation with the bot
# Must pass in "update" and "context as parameters to every declared/defined functions
# update.message.from_user gets all updates from a user including name and username in Json object, so we are stripping off the user's username.

# 'context.user_data' temporarily stores all entries from user. It can be used as a way
# to collect input from users. It is always in Json format.
# Here we clear the user_data storage to ensure that we are not using existing data in 
# place of current one since we will mostly be working with current data. So each time a
# user restarts the bot, we have an empty dictionary.

# This function is called when the /start command is invoked
def start(update, context):
    user = update.message.from_user
    reply = "Hi {}! I am ALGOMessenger.".format(user['first_name'])
    reply += (
        "I can help you with a few things.\n"
        "Tell me what you need to do.\n"
        "They should be from the menu.\n"
        "\nSend: \n"
        "/Create_account to Create an account.\n"
        "/Get_Mnemonic_from_pky to Get Mnemonic"
        "words from private key.\n"
        "/Transfer to Transfer asset.\n"
        "/Balance to Query account balance.\n"
        "/Account_status to Check your account status.\n"
        "Send /Done to cancel conversation."
        "Use /start to test this bot."
    )
    # update.message.reply_text() forwards updates to the user. 
    # If you need to send data types other than string, you 
    # find a way to type-cast it to string
    update.message.reply_text(reply, reply_markup=markup)
    context.user_data.clear() # Removes all updates from the
                              # user-data object.


# A polite way of ending a session.
def end_chat(update, context):
    update.message.reply_text(
        "Your current session is terminated.\n"
        "Click /start to restart."
    )
    return ConversationHandler.END


# Returns the status of an account when called
# When called, gets the user's existing address 
# and return the status of the account as 
# at when called, then end the session. 

def account_status(update, context):
    """
    :param update: Telegram's default param
    :param context: Telegram's default param
    :param address: 32 bytes Algorand's compatible address
    :return: Address's full information
    """
    pk = context.user_data['default_pk']
    status = algod_client.account_info(pk)
    for key, value in status.items():
        update.message.reply_text("{} : {}".format(key, value))
        time.sleep(0.7)
    return ConversationHandler.END

# Generates a private and public key and return them to the user.
# update.message.reply() sends message in text format to the user.
# On returning the keys to user, it informs them to get a testnet Algo for the purpose
# of testing this bot.

def create_account(update, context):
    """
    Returns the result of generating an account to user:
        - An Algorand address
        - A private key.
    """
    update.message.reply_text(
            "Hang on while I get you an account ..."
        )
    sk, pk = account.generate_account()
    update.message.reply_text("Your address:   {}\nPrivate Key:    {}\n".format(pk, sk))
    update.message.reply_text(
        "Keep your mnemonic phrase from prying eyes.\n"
        "\nI do not hold or manage your keys."
    )
    # Stores the keys in the user_data obj.
    # Normally, you don't want to do this.
    
    context.user_data['default_sk'] = sk
    context.user_data['default_pk'] = pk
    if context.user_data.get('default_pk') == pk and context.user_data['default_sk'] == sk:
        update.message.reply_text("Account creation success.")
    else:
        update.message.reply_text('Account creation error\n.')

    update.message.reply_text('To test if your address works fine, copy your address, and visit:\n ')
    keyboard = [[InlineKeyboardButton(
        "DISPENSER", 'https://bank.testnet.algorand.network/', callback_data='1')]]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('the dispenser to get some Algos', reply_markup=reply_markup)

    update.message.reply_text("Session ended. Click /start to begin.")
    return ConversationHandler.END


# Function to convert private key to mnemonic phrase
def get_mnemonics_from_sk(update, context):
    """
    Takes in private key and converts to mnemonics
    :param context:
    :param update:
    :return: 25 mnemonic words
    # """
    # Search and pull for the key in the user_data
    sk = context.user_data['default_sk']
    phrase = mnemonic.from_private_key(sk)
    update.message.reply_text(
        "Your Mnemonics:\n {}\n\nKeep your mnemonic phrase from prying eyes.\n"
        "\n\nI do not hold or manage your keys.".format(phrase), reply_markup=markup
    )
    update.message.reply_text('\nSession ended.')
    return ConversationHandler.END


# Check user's account and return the current total balance with pending rewards.
# When called. it takes user's existing account address, performs the query operation
# and return the result to user.

def query_balance(update, context):
    pk = context.user_data['default_pk']
    update.message.reply_text("Getting the balance on this address ==>   {}.".format(pk))
    if len(pk) == 58:
        account_bal = algod_client.account_info(pk)['amount']
        update.message.reply_text("Balance on your account: {}".format(account_bal))
    else:
        update.message.reply_text("Wrong address supplied.\nNo changes has been made.")
        context.user_data.clear()
    return ConversationHandler.END


# Inline bot utility, can be used for polling, links etc. 
def enquire(update, context):
    keyboard = [[InlineKeyboardButton("Website", 'https://algorand.com', callback_data='1'),
                 InlineKeyboardButton("Developer'site", 'https://developer.algorand.org', callback_data='2')],

                [InlineKeyboardButton("Community", 'https://community.algorand.com', callback_data='3')]]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Learn more about Algorand:', reply_markup=reply_markup)


def button(update, context):
    query = update.callback_query

    # CallbackQueries need to be answered, even if no notification to the user is needed
    # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
    query.answer()

    query.edit_message_text(text="Selected option: {}".format(query.data))


# help() provides guide when user needs help.
def help_command(update, context):
    update.message.reply_text("Use /start to test this bot.")


# On completion of a task, it clears the context and end the session.
def done(update, context):
    # call_transfer = transfer(update, context)
    # update.message.reply_text("{}".format(call_transfer))
    if 'choice' in context.user_data:
        del context.user_data['choice']
        context.user_data.clear()
        return ConversationHandler.END
    update.message.reply_text(
        "Swift! Your transaction is completed,", reply_markup=markup
    )
    return ConversationHandler.END

 

 

 

# Here is the application logic that determines how the code should run.
def main():
    # Create the Updater and pass it your bot's token.
    pp = PicklePersistence(filename=<specify a name for here>)#can be any valid name.
    updater = Updater(TOKEN, persistence=pp, use_context=True)

    # Get the dispatcher to register handlers
    dp = updater.dispatcher
    

    #For example, sending a /start command triggers the 'start' function
    # This is done using the Commandhandler module. 
    dp.add_handler(CommandHandler('start', start))
    dp.add_handler(CommandHandler('Create_account', create_account))
    dp.add_handler(CommandHandler('Get_Mnemonics_from_pky', get_mnemonics_from_sk))
    dp.add_handler(CommandHandler('Query_account_balance', query_balance))
    dp.add_handler(CommandHandler('Account_status', account_status))
    dp.add_handler(CommandHandler('Done', end_chat))
    dp.add_handler(CommandHandler('About', enquire))
    dp.add_handler(CallbackQueryHandler(button))
    dp.add_handler(CommandHandler('help', help_command))
    dp.add_handler(CommandHandler('enquire', enquire))

    # Start the Bot
    updater.start_polling()

    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()


if __name__ == '__main__':
    main()

Now that we are done with the coding, run it locally and you should see the bot respond to the right command.

 

 

After deployment, open the Telegram application, search for relorobot or Algobot20. Start a conversation with it.

ed5db7c24181473992d5c7aa1a9c3a3b815c4690c7e8b1e208e9fd6476225fde.png

 

b32c62b6f83de94957663b41cab96861af5b136a328738143b5e70e0ce4afe0b.png

 

963497243bed8dbc626f5178f70acfd1af4ca4143fa178f8cf4dbfebd7d458ec.png


1ad60faa2178fcd3347da6f81782f081714cf796362d1696495bf4653ca11e4f.png

 

569ab5202fc68a2e862a5bdfaaf0a75cc8d8f13da47de990bdc1855b677c43d8.png

 

3fda8b5e4a3621a4322bbde80322af8da3a21e9b11505653b5b20ccfee3694df.png


At this point, our bot works correctly. We are able to:

  • Create an account on Algorand Testnet.
  • Generate mnemonic keys from the private key. 
  • Query account balance.
  • Check the status of our account.


How does this help me as an Algorand developer?

The key take away from here is to be aware of the different and easier ways you can interact with the back-end. you can write and deploy a decentralized applications/smart contract on Algorand blockchain without having to go through a whole lot of processes of putting up the front-end. Do note that this is just a tip of what you can create using this paradigm. In the coming article, I will show you how you can write smart contract, deploy and interact with it via Telegram.

Full code is available on Github.


Video


Resources

Website

Developer Site

Download Python

 


Ddev
Ddev

I'm a crypto lover, a developer(python, Solidity, Javascript, CSS, HTML), ambassador, blockchain enthusiast and a writer. I am always learning.


Ddev@ALgorand
Ddev@ALgorand

A technology company that built and developed the world’s first open, permissionless, pure proof-of-stake blockchain protocol that, without forking, provides the necessary security, scalability, and decentralization needed for today’s economy. With an award-winning team, we enable traditional finance and decentralized financial businesses to embrace the world of frictionless finance.

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.