DEV Community

Cover image for ¿Cómo hacer un bot de criptomonedas en Telegram con Rust y Teloxide
Steadylearner
Steadylearner

Posted on • Updated on • Originally published at steadylearner.com

¿Cómo hacer un bot de criptomonedas en Telegram con Rust y Teloxide

En este post, aprenderemos a hacer un bot sencillo de criptomonedas para Telegram, similar al de la imagen del post.

Puedes contactarme por Telegram si necesitas contratar a un desarrollador Blockchain Full Stack.

También puedes unirte a mi grupo de telegram, en el cual puedes encontrar otros desarrolladores blockchain, así como reclutadores, jefes de proyecto, así como hacer preguntas y hacer conexiones.

Para este post se usará principalmente Rust como lenguaje de programación.

¿Por qué Rust?

Rust es un lenguaje increíblemente rápido y eficiente en cuanto a memoria: sin tiempo de ejecución ni recolector de basura (garbage collector), puede alimentar servicios de rendimiento crítico, funcionar en dispositivos integrados e integrarse fácilmente con otros lenguajes.

A pesar de que el código usado en este post es muy simple, espero que lo encuentres de ayuda para iniciarte con este lenguaje de programación. Puedes esncontrar el código de este post aquí

Usaremos Teloxide y binance-rs. Por favor dedicale tiempo a la lectura de la documentación de ambas herramientas antes de empezar.

Tienen varios frameworks de Rust para Telegram, pero decidí usar Teloxide porque puedes obtener ayuda de sus creadores facilmente a través de su canal de Telegram.

Si aún no tienes Rust instalado, por favor sigue las instrucciones del sitio web oficial.

Opcionalmente puedes instalar cargo edit y cargo watch para que puedas desarrollar mejor.

$cargo install cargo-edit
$cargo install cargo-watch
Enter fullscreen mode Exit fullscreen mode

Consulté esto antes de escribir este post. Si ya estas familiarizado con JavaSript puede que te ayude a leer esto antes.

Para probar lo que harémos en este tutorial, necesitas tener una cuenta de Telegram.

También puedes crear una cuenta de Binance en caso de que después quieras usar su API.

Tabla de Contenido

  1. Configurar el bot de Telegram con BotFather.
  2. Preparar el entorno de desarrollo para usar Teloxide y binance-rs.
  3. Construye tu bot de Telegram para encontrar el valor de la criptomoneda con Binance.
  4. Conclusión.

1. Configurar el bot de Telegram con Botfather

Para hacer el bot de Telegram, necesitamos crear un token de la API y configurarlo.

Por favor visita el sitio web de BotFather

Luego usa el comando /help. Te mostrará los comandos que puedes utilizar.

botfather commands by /help

Tiene muchos, pero solo necesitarás algunos de ellos para poder empezar.

CREATE, LIST, DELETE
/newbot - create a new bot
/mybots - list your bots
/deletebot - delete a bot

UPDATE META DATA
/setdescription - change bot description
/setabouttext - change bot about info
/setuserpic - change bot profile photo
Enter fullscreen mode Exit fullscreen mode

Puedes arrancar tu bot con el comando /newbot y seguir la instrucción. usa binance_bot para el nombre de tu bot, o si lo deseas colocale otro.

Telegram bot API token from botfather

Guardalo bien, ya que lo usaremos luego en un archivo .env

Luego usa /setuserpic para agregar una imagen a tu bot.

botfather /setuserpic command

Yo usé la imagen de Binance. Pero puedes usar la que gustes.

Felicitaciones, si llegaste hasta aquí, quiere decir que ya estas listo para empezar a programar el bot de Telegram.

2. Preparar el entorno de desarrollo para usar Teloxide y binance-rs.

Anteriormente, configuramos el bot de Telegram y obtuvimos el token de la API. Ahora lo controlaremos remotamente con nuestro código de Rust.

En esta parte instalaremos las crates de Teloxide y binance-rs, y configuraremos el entorno de desarrollo.

Usa este comando para inicializar el proyecto de Rust.

$cargo new binance_bot
Enter fullscreen mode Exit fullscreen mode

Esto creará algunos archivos en la carpeta de binance_bot. Edita tu archivo Cargo.toml como verás a continuación.

[package]
name = "binance_bot"
version = "0.1.0"
edition = "2018"

[dependencies]
# 1.
dotenv = "0.15.0"
dotenv_codegen = "0.15.0"

# 2. 
teloxide = { version = "0.4", features = ["frunk", "macros", "auto-send"] } 

log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version =  "1.3", features = ["rt-multi-thread", "macros"] }

binance = { git = "https://github.com/wisespace-io/binance-rs.git" }
Enter fullscreen mode Exit fullscreen mode

No será muy diferente del archivo REAMD.md que nos proporciona Teloxide. Pero hay algunas diferencias que debes tener en cuenta.

  1. Usaremos dotenv en lugar de configurar manualmente TELOXIDE_TOKEN diferente a como viene escrito en la documentación.
# Unix-like
$ export TELOXIDE_TOKEN=<Your token here>

# Windows
$ set TELOXIDE_TOKEN=<Your token here>
Enter fullscreen mode Exit fullscreen mode
  1. Si no incluyes macros en teloxide, algunos de estos ejemplos no funcionarán, y arrojará un error similar al de este mensaje 'can't find derive macro'.

Crea un archivo .env con $touch .env y agrega el token de la sección anterior.

TELOXIDE_TOKEN=<YOUR TOKEN FROM THE PREVIOUS PART>
Enter fullscreen mode Exit fullscreen mode

Se debió haber creado el siguiente archivo src/main.rs.

Ahora copia y pega este bloque de código del ejemplo oficial para poder usar archivos .env .

use dotenv::dotenv;
use std::env;

use teloxide::prelude::*;

#[tokio::main]
async fn main() {
    run().await;
}

async fn run() {
  dotenv().ok(); // Read .env and set env variables with this

  teloxide::enable_logging!();
  log::info!("Starting dices_bot...");

  let bot = Bot::from_env().auto_send();

  teloxide::repl(bot, |message| async move {
    println!("dice");
    message.answer_dice().await?;
    respond(())
  })
  .await;
  // INFO  binance_bot > Starting dices_bot...
}
Enter fullscreen mode Exit fullscreen mode

Ahora usaremos el comando $cargo run --release y esperaremos un poco antes de que el compilador de Rust termine su trabajo.

Mientras este haciendo eso, visita el bot de Telegram y escribe cualquier cosa. Debería mostrar algo como esto.

Teloxide dice example

Espero que hayas podido llegar hasta aquí. Verificaste que puedes usar el crate de Teloxide. En la siguiente sección lo usaremos en conjunto con binance-rs. Puedes editar tu archivo main.rs con el siguiente código para ver que el crate de binance-rs funcione en el entorno de desarrollo.

use binance::api::*;
use binance::market::*;

fn main() {
    let market: Market = Binance::new(None, None);

    // Latest price for ALL symbols
    // match market.get_all_prices() {
    //     Ok(answer) => println!("{:#?}", answer),
    //     Err(e) => println!("Error: {:#?}", e),
    // }

    match market.get_price("BTCUSDT") {
        Ok(answer) => println!("{:#?}", answer),
        Err(e) => println!("Error: {:#?}", e),
    }
}
Enter fullscreen mode Exit fullscreen mode

Pruebalo con el siguiente comando $cargo run --release. Debería mostrar el precio actual de USDT de Bitcon por consola.

Yo use una Macbook air con el chip M1 para compilarlo, pero fallo al compilarlo con la arquitectura arm64.

Puedes buscar una solución para usar arquitectura i386 en caso de que hayas tenido inconvenientes. Puedes ver de que arquitectura es tu computador usando el comando $arch

3. Construye tu bot de Telegram para encontrar el valor de la criptomoneda con Binance.

En esta parte modificaremos los comandos del ejemplo de Teloxide.

Por favor lee y prueba el código antes. luego puedes modificar tu archivo main.rs de la siguiente manera

use dotenv::dotenv;
use std::{env, error::Error};

use teloxide::{payloads::SendMessageSetters, prelude::*};
use teloxide::utils::command::BotCommand;
use teloxide::{utils::markdown::link};
use teloxide::types::ParseMode::MarkdownV2;

use binance::api::*;
use binance::market::*;

fn to_uppercase(string: &str) -> String {
    string.chars().map(|c| c.to_ascii_uppercase()).collect()
}

// Command examples

// /help
// /register
// /price BTC
// /price BTC USDT
// /price btc sudt
// /price BNB BTC
// /price bnb btc
#[derive(BotCommand)]
#[command(rename = "lowercase", description = "These commands are supported:")]
// 1.
enum Command {
  #[command(description = "display this text.")]
  Help,
  #[command(description = "show a Binance sign up page.")]
  Register,
  #[command(description = "show a cryptcurrency price in USDT by default.")]
  Price(String),
}

async fn responses_to_command(
    cx: UpdateWithCx<AutoSend<Bot>, Message>,
    command: Command,
) -> Result<(), Box<dyn Error + Send + Sync>> {
    let market: Market = Binance::new(None, None);

    match command {
        // 1.
        Command::Help => cx.answer(Command::descriptions()).send().await?, 
        // 2.
        Command::Register => {
            let register_link = link("https://accounts.binance.com/en/register?ref=SQ86TYC5", "Don't have a Binance account yet? You can register here\\.");

            cx.answer(register_link).parse_mode(MarkdownV2).send().await?
        },
        // 3.
        Command::Price(crpytocurrency) => {
            let mut iter = crpytocurrency.split_whitespace();

            if let Some(first_crypto_symbol) = iter.next() {

                let second_crypto_symbol = if let Some(second_crypto_symbol) = iter.next() {
                    println!("There was a second_crypto_symbol.");
                    second_crypto_symbol
                } else {
                    println!("There was no second_crypto_symbol. Use default.");
                    "USDT"
                };

                let target = to_uppercase(
                    &format!("{}{}", &first_crypto_symbol, &second_crypto_symbol)
                );

                match market.get_price(target) {
                    Ok(symbol_price) => {
                        println!("{:#?}", &symbol_price);
                        cx.answer(format!("The price you want is {:#?}. ", &symbol_price.price)).await?
                    },
                    Err(e) => {
                        eprint!("{:#?}", e);

                        cx.answer(format!("Something went wrong. Did you use the correct cryptocurrency pair?")).await?
                    },
                }
            } else {
                cx.answer("Cryptocurrency symbols were not specified. To start with, you can use /price ETH or /price ETH USDT.").await?
            }
        }
    };

    Ok(())
}

#[tokio::main]
async fn main() {
    run().await;
}

async fn run() {
    dotenv().ok();

    teloxide::enable_logging!();
    log::info!("Starting the_bot...");

    let bot = Bot::from_env().auto_send();
    let bot_name: String = "binance_bot".into();

    teloxide::commands_repl(bot, bot_name, responses_to_command).await;
}
Enter fullscreen mode Exit fullscreen mode

Utiliza $cargo run --release y visita tu bot.

Escribe /help, luego prueba algunos comandos como los de a continuación.

/help
/register

/price BTC
/price BTC USDT
/price btc usdt
/price BNB BTC
/price bnb btc
Enter fullscreen mode Exit fullscreen mode

Algunos mostraran resultados similares a estos.

Bitcoin Price before

Bitcoin Price

(Es interesante ver la caida de la criptomoneda mientras escribo este post, el de la primera imagen es de mientras escribía el código para este post, y el de la segunda imagen es de cuando escribía el post.)

Las cargas de aqui serán partes relevantes a los comandos y otras para la configuración.

  1. Muestra los textos de descripción que fueron definidos de enum command. solo necesitamos editar allí.

  2. No fue fácil encontrar como usar markdown con Teloxide en la documentación. Sería muy útil saber si Telegram quiere que uses \ para algunos caractéres cuando estes usando markdown.

  3. El usuario puede enviar varios inputs acompañados del comando /price, puedes ver como manejarlos fácilmente con la API de Rust.

Por ejemplo, el usuario puede enviar un input vacio, un input sin la segunda criptomoneda (por defecto se manejan con USDT), un input con más de 2 criptomonedas, etc.

Podrías darte cuenta de la belleza de Rust como lenguage si tuvieses que solucionar este caso con otro lenguaje de progrmación.

Si tienes alguna pregunta sobre Teloxide puedes consultar su documentación.

4. Conclusión

En este post aprendimos a como configurar Rust env para usar el framework Teloxide, espero que lo hayas hecho funcionar sin ningun problema, agregué varias imagenes para que puedas seguir el post y los ejemplos sin problemas.

Si estas familiarizado con Binance, puedes escribir mas comandos para interactuar con la API.

Si te gustó este post, por favor comparteló con otros, planeo escribir más sobre blockchain. actualmente estoy interesado en ETH y POLKADOT.

Si necesitas contratar a un desarrollador, puedes contactarme..

Escribiré un post para poder desplegar lo que hicimos en este ejemplo si mas personas encuentran este post de ayuda.

Gracias.

Top comments (0)