Accept bitcoin payments or telegram bot autosales” cvv shops

Introduction

This article was written by me (KONUNG) especially for Exploit.in contest, here I will describe how to create Telegram bot for autosales with payment in bitcoins. I will be using NodeJS, MySQL, Blockchain. I decided to take NodeJS because, it is mostly created for servers. People who know other languages can learn JS basics and switch to it without problems in a couple of hours. I never had a chance to write telegram bots before, but I spent a couple of days with it and it was very easy. There’s tons of material on the internet on how to install NodeJS and MySQL, so I won’t waste any time demonstrating the full installation.

Concept

The concept of the bot is as follows, the client launches the bot, then he has two commands to choose from: /showproducts show products, /checkorder check order status. When you view all the products, the customer will get the ID, name, description, price (in USD), number of items in stock and below the message inline button Buy. All he will need to do is to click on the buy button, get the order ID and details for replenishment, pay and check the order status by its ID.

Кишки

After the customer clicks Buy, we will receive a product ID and price in dollars, then we just recalculate the current exchange rate, find an address free for payment, add the data to the database, and N-number of minutes will check whether the payment passed, if payment passed, add to the table with orders of a product, after a certain time (90 minutes in our case), if the order is not paid it will be removed from the database, that would not clutter the database. Also, we will have an admin panel with its own commands for adding/removing products, etc.

Bot creation and configuration

The first thing we will do is to get a token for the bot to work with. Find botfather in Telegram, run it and write /newbot after which it will ask for a name for the bot and then the username by which it will be found by other users, the username must end in bot, when everything is done you will receive a token for access to the bot, do not send anyone this token, it is fraught with a risk of compromising your shop. A small list of secondary settings you can do:

/setname Changes bot name /setdescription Sets bot description (In chat) /setabouttext Sets bot description (In profile) /setuserpic Sets bot avatar /setcommands Sets commands for bot with their description

Next, set the main commands for the bot that will be visible to the user, first send the bot /setcommands, choose there our bot and send him the following commands in a message:

showproducts Show all products checkorder Check order status

That’s basically all the bot’s settings.

Database

Now the most interesting – the database, it’s easier than it may seem at first sight, I named my_store, we will have three tables: my_order, my_products, my_productsinfo. I don’t know SQL so well, maybe I could optimize tables somewhere. Command to create tables:

CREATE TABLE my_products( here will be the products themselves product_id INT NOT NULL, product_data VARCHAR(255) NOT NULL );

CREATE TABLE my_productsinfo( here will be information about the products themselves product_id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, price INT NOT NULL, PRIMARY KEY(product_id) );

CREATE TABLE my_orders( the orders themselves will be stored here order_id CHAR(32) CHARACTER SET latin1 NOT NULL address VARCHAR(255) NOT NULL, status VARCHAR(255) NOT NULL, price FLOAT(8,8) NOT NULL, product_id INT NOT NULL, product_data VARCHAR(255), order_data TIMESTAMP DEFAULT CURRENT_TIMESTAMP, );

Бот

It’s time to write the code of our bot, so let’s begin by creating a config file (config.js), which will store the settings for our store.

module.exports = { authToken: 1701858052:AAGWYQ5Kp-4EiOi_9GJKBXqMYj3UrIzXHhk, MySQL: { client: mysql, connection: { host: 127.0.0.1, user: root, password: , database: my_store } }, adminChatId: 437619229, xPub: xpub6FBEgyfiZ79TbeZdgo39Ahr4pRQaoqJMAs7mQNV8MLPaHB19PX7PMhPP12Hjp32jduEA2rQ93DNYgtzm92ZAUizKdUAGWnYdxWCmJwNCtpK }

There are not many settings here, first authToken is bot’s token which we received at the stage of bot creation in botfather, we just insert your token and that’s it. Next is setting up a connection to the database, here we specify the host address, username, password and name of the database if it is different. To find out your chat ID, you need to send /echo to the bot, then you will see it in the code.

xPub is a more interesting thing, xPub is an extended public key. It is part of the bitcoin standard BIP32. If you have xPub key, the only thing you can do is to generate addresses but without private keys to them, in our case this is very convenient, because if somebody suddenly breaks into your server and sees code that is running, he can not steal your beta, maximum he can do is to suck your balls and lick when he sees how much you sold and how much money you spent. Where to get it? At https://www.blockchain.com/, register there a new account specifically for our shop and go to Settings->Wallets and Addresses->My Bitcoin Wallet->Manage->Advanced Options->Show xPub, voila, here is your xPub. I chose Blockchain because it’s convenient and easy, and you 100% heard about this wallet. Further comments will be in the code.

const conf = require(./Config) // const MD5 = require(md5) const {Telegraf, Markup} = require(telegraf) const bot = new Telegraf(conf.authToken) const knex = require(knex)(conf.MySQL) const Axios = require(axios) const bjs = require(bitcoinjs-lib); const XPubGenerator = require(xpub-generator).XPubGenerator;

const TenMinutes = 10 * 60 * 1000 //Interval with which we will check the cats for payment var Status = Sleep //Current action in the admin panel var checkorder = [] //Array where the id of chats for checking orders will be stored, further you will understand var Product = { Name: , Description: , Price: 0 }

bot.start(ctx => { //The welcome message, when the bot starts ctx.reply(`Welcome ${ctx.message.from.first_name}, glad to welcome you to my store\n/showproducts View all products \n/checkorder Check order status`) })

bot.help( ctx => ctx.reply(/showproducts View all products \n/checkorder Check order status))

/* Shopper Commands*/

async function calcPrice(price){ //This function will convert $ to BTC at the current exchange rate try{ let response = await Axios.get(`https://web-api.coinmarketcap.com/v1/tools/price-conversion?amount=${price}convert_id=1id=2781`) return Number(response.data.data.quote[1].price.toFixed(8)) } catch(err){ return Error } }

async function getBalance(address){ //Функция проверки баланса try{ let response = await Axios.get(`https://chain.api.btc.com/v3/address/${address}`) return {received: Number((response.data.data.received * 0.00000001).toFixed(8)), unconfirmed: Number((response.data.data.unconfirmed_received * 0.00000001).toFixed(8))} } catch(err){ return {received: Error, unconfirmed: Error} } }

bot.on(callback_query, async ctx =>{//the event that is triggered when the buy button is clicked try{ let t = ctx.update.callback_query.data.split($) //then we split the date of the button we clicked let summa = await calcPrice(t[1]) //calculate price if (summa === Error) throw new Error(An error occurred while calculating price) let didi = -1 let addresses = [] for (let addr of await knex(my_orders).select(address)) addresses.push(addr.address) //draw orders

btc addresses from the database

do { didi t_address = new XPubGenerator(conf.xPub, bjs.networks.bitcoin).nthReceiving(didi) } while (addresses.includes(t_address)) //We generate xPub addresses until we get one not in the database

let Arra = { order_id: MD5(Date.now().toString ctx.update.callback_query.id), //Unique order ID by which the client will eventually find the order address: t_address, status: Pending payment, price: summa, product_id: t[0], product_data: Will be available after payment } await knex(my_orders).insert(Arra) //Create order ctx.reply(`Your order is being processed, if not paid within an hour and a half, the order will be liquidated. \nID of the order: ${Arra.order_id}{n Payment details: ${Arra.address}{nThe amount due: ${Arra.price}{nYou can check the status of your order by sending the command /checkorder`) } catch(err){ ctx.reply(There was an error try later) } })

bot.command(/showproducts, ctx =>{ //respond to command show products knex.select().from(my_productsinfo) .then( resp =>{ for (let product of resp){ knex(my_products).where({product_id: productproduct_id}).count({count: *}) .then( resp => ctx.reply(`ID: ${product.product_id}\nName: ${product.name}\nDescription: ${product.description}\nPrice: ${product.price}$\nCount: ${resp[0].count}`, Markup.inlineKeyboard([Markup.button.callback(Buy, `${product.product_id}$${product.price}`]) )) //The date in the button is product ID$Price .catch( err => ctx.reply(Error in getting product list)) } }) .catch(err => ctx.reply(Error in getting product list)) })

bot.command(/checkorder, ctx =>{ //Set user to checkorder mode checkorder.push(ctx.message.chat.id) ctx.reply(Enter order ID) })

bot.on(text, async (ctx, next) =>{ //This event is triggered on all text messages if (checkorder.includes(ctx.message.chat.id)){ //If chat in order check mode the following code is executed const STF = await knex(my_orders)where({order_id: ctx.message.text}) if (STF[0] == undefined){ ctx.reply(Order not found) } else { ctx.reply(orderID: ${STF[0].order_id}\nID product: ${STF[0].product_id}\nRequests: ${STF[0].address}\nPayment amount: ${STF[0].price}\nStatus: ${STF[0].status}\nProduct: ${STF[0].product_data}}} } checkorder.splice(checkorder.indexOf(ctx.message.chat.id), 1) //delete from the array, respectively checkorder status is removed } next() })

bot.command(/echo, ctx =>{ //This command is needed to know the id of the chat with us, after you specify the desired id in the config you can delete this command ctx.reply(ctx.message.chat.id) })

/* Admin Commands*/

bot.use((ctx, next) =>{ //An interesting thing, middleware, those who used Express framework know exactly what this thing is if (ctx.message.chat.id === conf.adminChatId) next() // If we are from admin chat then go ahead and perform next functions })

bot.command(/cancel, ctx =>{ Status = Sleep //Cancel current operations ctx.reply(All current operations have been cancelled) })

bot.command(/addproduct, ctx =>{ Status = AddProduct_N //go to add product ctx.reply(Specify product name) })

bot.command(/addproductdata, ctx =>{ Status = AddProductData //add products themselves ctx.reply(Send Data to add in ID$ProductData\example 3$email:password) })

bot.command(/showproductdata, ctx =>{ knex(my_products).select() //shows all products that are on sale .then( resp => ctx.reply(resp)) .catch( err => ctx.reply(error occurred)) })

bot.command(/delproductdata, ctx =>{ Status = DelProductData //To delete some specific product from my_products table ctx.reply(Send data about the product you want to delete in the following format ID$ProductData) })

bot.command(/delproduct, ctx =>{ Status = DelProduct //Delete products that the client sees ctx.reply(Send the ID of the product you want to delete) })

bot.on(text, ctx =>{ //Processes what we enter, what the admin enters switch(Status){ //What is in this swipe I described above case DelProduct: Status = Sleep knex(my_productsinfo).where({product_id: ctx.message.text}).del() .then( resp => ctx.reply(Product Successfully removed)) .catch( err => ctx.reply(An error occurred during removal)) break case AddProduct_N: Status = AddProduct_D Product.Name = ctx.message.text ctx.reply(Specify product description) break case AddProduct_D: Status = AddProduct_P Product.Description = ctx.message.text ctx.reply(Specify product price) break case AddProduct_P: Status = Sleep Product.Price = parseInt(ctx.message.text) knex(my_productsinfo).insert({name: Product.Name, description: Product.Description, price: Product.Price}) .then( =>ctx.reply(Product successfully added)) .catch( err => ctx.reply(Error occurred while adding product)) break case AddProductData: Status = Sleep let t = ctx.message.text.split($) knex(my_products).insert({product_id: t[0], product_data: t[1]}) .then( resp => ctx.reply(Product successfully added to database)) .catch( err => ctx.reply(An error occurred while adding to the database)) break case DelProductData: Status = Sleep let t = ctx.message.text.split($) knex(my_products).where({product_id: t[0], product_data: t[1]}).del() .then( resp => ctx.reply(Product successfully removed)) .catch( err => ctx.reply(An error occurred during removal)) break } })

cvv shops

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *