如何打造你的 Solana 狙击机器人 (4)💰🚀

2025-06-07

如何打造你的 Solana 狙击机器人 (4)💰🚀

你好👋,

感谢您来到这里!🎉

在之前的文章中,我概述了构建 Solana Sniper 机器人、SPL 代币、Solana DEX 平台等的基本步骤。作为开发过程的一部分,我们还创建了三个脚本:一个用于将 SOL 从钱包 A 转移到钱包 B,一个用于在相同钱包之间转移 SPL 代币,以及一个用于兑换代币 A 和代币 B 的脚本(或买卖脚本)。

我相信,通过前几期的讲解,我们已经涵盖了开发 Solana 狙击机器人所需的基础概念。有了这些基础,现在是时候深入研究这种机器人的实际实现方法了。

在本期中,我想重点探讨一个特定方面:选择 Telegram 机器人作为 Solana 狙击机器人主要界面背后的原因。Telegram 机器人拥有一系列优势,使其特别适合此用途,我将详细阐述这些优势。从易用性和可访问性,到强大的 API 和实时通信功能,Telegram 机器人脱颖而出,成为管理和与 Solana 狙击机器人交互的理想选择,原因有以下几点。让我们进一步探讨这些原因。

1. Telegram 机器人

Telegram 机器人Telegram 消息平台上一种特殊类型的账户,由软件而非人类用户驱动。这些机器人旨在自动执行任务、提供服务或通过聊天界面与用户互动。它们使用 Telegram 的Bot API构建,该 API 允许开发者创建自定义机器人,用于发送和接收消息、管理群组、处理付款以及执行各种其他功能。

1.1 Telegram Bot 基本概念

  • Telegram 机器人的主要特点

    • 自动化:Telegram 机器人擅长自动执行重复性任务,为用户节省时间和精力。例如,它们可以自动向用户发送重要更新通知,例如加密货币市场的价格变动或群组中的新消息。它们还可以通过处理诸如欢迎新成员、执行规则或移除垃圾邮件等任务来管理群聊。此外,机器人还可以从外部来源(例如 API 或数据库)获取数据,并以结构化格式呈现给用户。这种自动化功能使机器人在个人和商业用例中都非常高效。
    • 互动性:Telegram 机器人的设计注重互动性,允许用户通过简单的命令或查询与其互动。例如,用户可以发送命令,例如/start发起与机器人的对话,或/help获取可用命令和指令的列表。机器人还可以支持内联查询,用户可以在任何聊天中直接输入查询,机器人将立即响应,而无需打开单独的对话。这种互动性使机器人感觉像反应灵敏的智能助手,从而提升了用户体验。
    • 可定制性:Telegram 机器人最强大的功能之一就是其可定制性。开发者可以根据特定需求对机器人进行编程,使其执行各种任务。例如,可以设计一个机器人,根据预先定义的策略执行买卖订单来交易加密货币。此外,它还可以跟踪资产的实时价格、提供分析数据,甚至通过游戏或测验为用户提供娱乐。Telegram Bot API 的灵活性使开发者能够创建满足特定需求的机器人,使其成为用途广泛的工具。
    • 实时通信:Telegram 机器人能够实时发送和接收消息,这对于需要即时更新的应用程序至关重要。例如,在交易机器人中,实时通信可确保用户立即收到有关市场动态、交易执行或价格警报的通知。此功能对于客户支持机器人也非常有用,因为快速响应对于维持用户满意度至关重要。Telegram 机器人的实时特性使其成为时间敏感型任务的理想选择。
    • 集成:Telegram 机器人可以与外部 API、数据库和服务无缝集成,从而提供高级功能。例如,机器人可以连接到加密货币交易所的 API,以获取实时市场数据、执行交易或监控投资组合表现。它还可以与数据库交互,存储和检索用户特定信息,例如偏好设置或交易历史记录。这种集成功能使机器人能够将其功能扩展到 Telegram 平台之外,从而成为复杂应用程序的强大工具。
    • 可访问性:Telegram 机器人高度可访问,因为它们可以在各种设备和平台上使用。无论您使用的是智能手机、平板电脑、台式电脑,还是 iOS、Android、Windows 或 macOS,只要支持 Telegram,即可在任何平台使用 Telegram 机器人。这种跨平台兼容性确保用户可以随时随地与机器人互动,使其成为个人和专业用途的便捷多功能工具。
  • 为什么 Telegram 机器人在加密货币和交易领域如此受欢迎

    • 用户友好界面:Telegram 的聊天界面直观易用,即使对技术不精通的用户也能轻松上手。在熟悉的聊天环境中发送命令或接收通知的便捷性降低了使用交易机器人等高级工具的门槛。这种用户友好性使 Telegram 机器人可供从普通用户到专业交易员的广泛受众使用。
    • 实时警报:在快节奏的加密货币交易世界中,时机至关重要。Telegram 机器人可以发送有关市场动态、价格变动或交易执行的即时通知,确保用户不会错过任何机会。这些实时警报对于做出明智的决策并在动荡的市场中保持领先至关重要。
    • 远程控制:Telegram 机器人允许用户在世界任何地方管理交易或监控投资组合。只要您有互联网连接,无论您是在旅途中还是在家中,都可以通过 Telegram 与机器人互动。这种远程控制功能为需要始终与市场保持联系的交易者提供了无与伦比的便利。
    • 安全性:Telegram 以其高度重视隐私和安全而闻名,提供端到端加密等功能,用于秘密聊天和安全数据存储。对于处理钱包地址和交易详情等敏感信息的加密货币交易机器人来说,这些安全功能至关重要。用户可以放心,在使用 Telegram 机器人时,他们的数据和活动都受到保护。
  • 示例用例

    • 加密货币交易机器人:这些机器人旨在自动化加密货币交易所的交易活动。它们可以监控市场价格,根据预先定义的策略执行交易,并提供投资组合表现的实时更新。例如,Solana 狙击机器人可以使用 Telegram 通知用户新代币的发布,或在满足特定条件时立即执行交易。
    • 通知机器人:通知机器人用于发送特定事件的警报,例如当加密货币达到特定价格阈值或发布重要新闻时。这些机器人对于无需手动持续监控市场即可随时掌握最新动态非常有用。
    • 群组管理机器人:在 Telegram 群组或频道中,机器人可以自动执行审核任务,例如删除垃圾邮件、禁止违规者或欢迎新成员。它们还可以提供管理功能,例如置顶消息、管理投票或生成活动报告。
    • 支付机器人:支付机器人促进 Telegram 生态系统内的交易,让用户无缝收发款项。例如,机器人可以让用户直接通过 Telegram 支付服务费用、分摊账单,甚至向内容创作者捐款。

1.2 如何开发Telegram Bot

开发 Telegram 机器人非常简单,尤其得益于 Telegram 拥有完善的Bot API,以及适用于不同编程语言的各种库和工具。以下是帮助您创建自己的 Telegram 机器人的分步指南:

步骤 1:设置 Telegram 机器人

  • 创建新机器人

    • 打开 Telegram 并搜索BotFather(Telegram 用于创建和管理机器人的官方机器人)。
    • 开始与 BotFather 聊天并使用/newbot命令。
    • 按照说明进行操作:

      • 为您的机器人选择一个名称(例如“MyCryptoBot”)。
      • 为您的机器人设置用户名(必须以 bot 结尾,例如“MyCryptoBot_bot”)。
    • 创建完成后,BotFather 将为您提供一个Bot Token(唯一的 API 密钥)。请妥善保存此令牌,因为它是与 Telegram API 交互所必需的。

  • 配置您的机器人
    使用 BotFather 进一步定制您的机器人:

    • 使用 设置个人资料图片/setuserpic
    • 使用 添加描述/setdescription
    • 使用设置命令(例如/start、 ) /help/setcommands

第二步:选择编程语言
Telegram 机器人几乎可以用任何编程语言开发。热门选择包括:

  • Python(使用类似python-telegram-bot或的库aiogram

  • JavaScript/Node.js(使用类似node-telegram-bot-api或的库telegraf

  • Java(使用类似的库TelegramBots

  • PHP、C#或其他,取决于您的偏好。

对于初学者来说,Python由于其简单性和强大的库可用性而强烈推荐。

步骤3:设置开发环境

  • 安装必要的工具

对于Pythonpython-telegram-bot使用 pip 安装库:

pip install python-telegram-bot
Enter fullscreen mode Exit fullscreen mode

对于Node.js:安装node-telegram-bot-api库:

npm install node-telegram-bot-api
Enter fullscreen mode Exit fullscreen mode
  • 设置代码编辑器(例如,VS Code,PyCharm)并创建一个新的项目文件夹。

步骤 4:编写您的机器人代码这是一个用Python
编写的简单 Telegram 机器人的示例

from telegram import Update
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext

# Replace 'YOUR_BOT_TOKEN' with the token you received from BotFather
BOT_TOKEN = 'YOUR_BOT_TOKEN'

# Define a start command handler
def start(update: Update, context: CallbackContext):
    update.message.reply_text('Hello! I am your Telegram bot. How can I assist you?')

# Define a help command handler
def help(update: Update, context: CallbackContext):
    update.message.reply_text('Here are the commands you can use:\n/start - Start the bot\n/help - Get help')

# Define a function to echo user messages
def echo(update: Update, context: CallbackContext):
    update.message.reply_text(update.message.text)

def main():
    # Initialize the Updater with your bot token
    updater = Updater(BOT_TOKEN, use_context=True)

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

    # Register command handlers
    dp.add_handler(CommandHandler("start", start))
    dp.add_handler(CommandHandler("help", help))

    # Register a message handler to echo messages
    dp.add_handler(MessageHandler(Filters.text & ~Filters.command, echo))

    # Start the bot
    updater.start_polling()
    updater.idle()

if __name__ == '__main__':
    main()
Enter fullscreen mode Exit fullscreen mode

步骤 5:运行你的机器人

  • 将代码保存在文件中(例如my_bot.py)。

  • 运行脚本:

python my_bot.py
Enter fullscreen mode Exit fullscreen mode
  • 打开 Telegram,搜索你的机器人用户名,然后开始聊天。测试/start/help命令,并尝试发送一条消息,看看机器人是否回复。

步骤 6:添加高级功能
一旦您的基本机器人运行,您就可以使用高级功能增强它:

  • 集成 API

    • 将您的机器人连接到外部 API(例如,加密货币价格 API、天气 API)以获取和显示数据。
    • 示例:使用 CoinGecko API 获取实时加密货币价格。
  • 添加命令:创建自定义命令(例如,/price BTC获取比特币的价格)。

  • 处理内联查询:允许用户使用内联模式在任何聊天中与您的机器人进行交互。

  • 部署到服务器:使用Heroku、AWSGoogle Cloud等云平台全天候托管您的机器人。

  • 添加安全性:实施身份验证以限制对您的机器人的访问(例如,只允许特定用户使用它)。

步骤 7:部署您的机器人
为了使您的机器人持续运行:

  • 在云平台上托管

    • 将您的机器人部署到 Heroku、AWS 或 DigitalOcean 等云服务。
    • 对于 Python,您可以使用Gunicorn将您的机器人作为 Web 服务器运行。
  • 使用 Webhook

    • 不要进行轮询,而是设置一个 webhook 来实时接收来自 Telegram 的更新。
    • Python 示例:
updater.start_webhook(listen="0.0.0.0", port=PORT, url_path=BOT_TOKEN)
updater.bot.set_webhook(f"https://yourdomain.com/{BOT_TOKEN}")
Enter fullscreen mode Exit fullscreen mode

步骤 8:测试和迭代

  • 彻底测试您的机器人以确保它按预期运行。

  • 收集用户反馈并根据需要添加新功能或修复错误。

学习资源

通过遵循这些步骤,您可以创建一个功能齐全的电报机器人,以满足您的需求,无论是用于交易、通知还是任何其他目的!



2.构建一个 Telegram 机器人作为 Solana 狙击机器人的 UI

这是狙击机器人的常见购买代币 UI。
Telegram Bot 购买代币 UI

我们已经介绍了如何在 Solana 中购买 SPL 代币。
所以这次,让我们使用 Solana 构建一个购买代币的 UI,Node.js尽管我之前已经解释了如何使用PythonSolana 开发 Telegram 机器人。

步骤1:设置环境

  • 为了方便起见,我们使用 VS Code 开发自己的代码。假设你已经安装了 Node.js(18.0 或更高版本)。
  • 使用初始化您的项目npm init
  • 使用此命令安装依赖项:
npm install typescript ts-node @solana/web3.js axios dotenv bs58 fs mongoose node-telegram-bot-api
Enter fullscreen mode Exit fullscreen mode
  • 检查package.json文件并编辑脚本如下:
{
  "name": "solana-sniper-bot",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "ts-node index.ts",
    "build": "tsc",
    "clean": "tsc --build --clean",
    "dev": "tsc && node ./dist/index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@solana/web3.js": "^1.98.0",
    "axios": "^1.8.1",
    "bs58": "^6.0.0",
    "dotenv": "^16.4.7",
    "fs": "^0.0.1-security",
    "mongoose": "^8.10.1",
    "node-telegram-bot-api": "^0.66.0",
    "typescript": "^5.7.3"
  },
  "devDependencies": {
    "@types/node": "^22.13.5",
    "@types/node-telegram-bot-api": "^0.64.7",
    "ts-node": "^10.9.2"
  }
}

Enter fullscreen mode Exit fullscreen mode
  • tsc --init使用命令安装 Typescript 环境。
  • tsconfig.json像这样编辑文件:
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}
Enter fullscreen mode Exit fullscreen mode
  • .env 文件
TELEGRAM_BOT_TOKEN=""
BIRDEYE_API_KEY=""
SOLANA_RPC_URL=""
BOT_WALLET_PUBLIC_KEY=""
Enter fullscreen mode Exit fullscreen mode

步骤2:主要代码

这些是构建 Telegram Bot UI 的主要文件。
构建 Telegram Bot UI 的主要文件

  • index.ts文件
import TelegramBot from "node-telegram-bot-api";
import { connectDatabase } from "./config/db";
import { addUser, getUserById } from "./service/userService";
import { IK_START, getIKSnipe } from "./components/inlineKeyboard";
import { messageHandler } from "./bot/message.handler";
import { callbackQueryHandler } from "./bot/callbackquery.handler";
import fs from "fs";

import dotenv from "dotenv";

dotenv.config();

const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;

const BotMenu = [
  {
    command: "start",
    description: "💥 Start",
  },
  {
    command: "setting",
    description: "⚙️ setting",
  },
  {
    command: "position",
    description: "💰 Position",
  },
  {
    command: "referral",
    description: "📊 Referral Stats",
  },
  { command: "help", description: "❓ Help" },
];

const bot = new TelegramBot(TELEGRAM_BOT_TOKEN!, {
  polling: true,
  webHook: false,
  onlyFirstMatch: true,
  filepath: false,
});

const userSnipeConfig = new Map();

const startBot = () => {
  // Connect Database
  connectDatabase();

  bot.setMyCommands(BotMenu);

  bot.onText(/^\/start$/, async (msg: TelegramBot.Message) => {
    console.log("🚀 input start cmd:");

    const chatId = msg.chat.id;
    let user;
    const existingUser = await getUserById(chatId);
    if (existingUser) {
      console.log("User already exist: ", chatId);
      user = existingUser;
    }
    else {
      console.log("New User: ", chatId);

      const userChat = msg.chat;
      user = await addUser({
        chat_id: userChat.id,
        username: userChat.username,
        first_name: userChat.first_name,
        last_name: userChat.last_name
      });
    }

    // Snipe Config Init
    let snipe_config:any = {
      token: null,
      slippage: 50,
      snipe_fee: 0.005,
      snipe_tip: 0.005,
      tp: null,
      sl: null,
      snipe_amount: null,
    };

    userSnipeConfig.set(chatId, snipe_config);

    const image = fs.createReadStream("./public/sniper.jpg");
    const caption = `Welcome to <b>Lucky Sniper</b> Bot!✨\n⬇You can deposit SOL to your wallet and start sniping!🔍\n\n💰Your Wallet:\n<code>${user.public_key}</code>`;
    await bot.sendPhoto(msg.chat.id, image, {
      parse_mode: "HTML",
      caption: caption,
      reply_markup: {
        inline_keyboard: IK_START,
      },
    });
  });

  bot.onText(/^\/snipe/, async (msg: TelegramBot.Message) => {

  });

  bot.on("message", (msg: TelegramBot.Message) => {
    console.log("message handler");
    messageHandler(bot, msg, userSnipeConfig);
  });

  bot.on("callback_query", async (cb_query: TelegramBot.CallbackQuery) => {
    console.log("callback_query handler");
    callbackQueryHandler(bot, cb_query, userSnipeConfig);
  });
};

startBot();

Enter fullscreen mode Exit fullscreen mode
  • config/constant.ts文件
export const BOT_FEE_PERCENT = 1; // 1%

export enum BotCaption {
  strInputTokenAddress = `💰 Enter Token Address`,
  strInvalidSolanaTokenAddress = `⚠️ Invalid Solana Token Address! Again enter correct Token Address!`,
  strInputSwapSolAmount = `💰 Enter Swap SOL Amount`,
  strInvalidSolAmount = `⚠️ Invalid Swap SOL Amount ⚠️`,
  HelpCaption = `🚀 TG Solana Trading Bot 🚀`,
  strWelcome = `<b>Welcome to Solana Trading bot</b> 🎉\n`,
  SET_PRIORITY_FEE = `💸 Priority Fee SOL Amount \n\n<i>💲 Enter SOL Value in format "0.0X"</i>`,
  SET_JITOTIP = `💸 Jito Tip SOL Amount \n\n<i>💲 Enter SOL Value in format "0.0X"</i>`,
  SET_SNIPE_AMOUNT = `💰 Snipe Amount \n\n<i>💲 Enter Snipe Amount in format "0.0X"</i>`,
  SET_SLIPPAGE = `⚖ Slippage \n\n<i>💲 Enter Slippage in format "xx%"</i>`,
  SET_TakeProfit = `⚖ Take Profit \n\n<i>💲 Enter Take Profit in format "xx%"</i>`,
  SET_StopLoss = `⚖ Stop Loss \n\n<i>💲 Enter Stop Loss in format "xx%"</i>`,
  strInvalidInput = `⚠️ Invalid Input ⚠️`,
  SET_PK = `🔑 Private KEY \n\n<i>💲 Enter Wallet Private KEY</i>`,
  SET_DES = `⚙ User Setting.\nYou can set any settings on here. You can set any settings on here.`,
  SWAP_FAILED = `⚠️ Swap Failed ⚠️`,
  SNIPE_CONFIG_FAILED = `⚠️ Snipe Configuration Failed ⚠️`,
  AUTO_SWAP_ON = "🔔 Auto Swap ON",
  AUTO_SWAP_OFF = "🔕 Auto Swap OFF",
  strAlreadyRefer = `👍 You have already referred a friend.`,
  strReferSuccess = `👍 You have successfully referred a friend.`,
  strInvalidReferUser = `⚠️ Invalid User ⚠️`,
}
Enter fullscreen mode Exit fullscreen mode
  • components/inlineKeyboard.ts文件
import { getShortenedCA } from "../utils/utils";

// Start Inline Keyboard
export const IK_START = [
  [
    {
      text: "📥 Buy",
      callback_data: "BUY",
    },
    {
      text: "📤 Sell",
      callback_data: "SELL",
    },
  ],
  [
    {
      text: "⚙ Settings",
      callback_data: "SETTINGS",
    },
  ],
  [
    {
      text: "🔎 Snipe",
      callback_data: "SNIPE_SETTINGS",
    },
  ],
];

// Snipe Inline Keyboard
export function getIKSnipe({
  token = null,
  slippage = 50,
  snipe_fee = 0.005,
  snipe_tip = 0.005,
  tp = null,
  sl = null,
  snipe_amount = null,
}: {
  token: string | null;
  slippage: number;
  snipe_fee: number;
  snipe_tip: number;
  tp: number | null;
  sl: number | null;
  snipe_amount: number | null;
}): any {
  const IK_SNIPE = [
    [
      {
        text: "🔙 Back",
        callback_data: "BACK",
      },
      {
        text: "🔃 Refresh",
        callback_data: "REFRESH",
      },
    ],
    [
      {
        text: `${token ? "🟢" : "🔴"} Token: ${
          token ? getShortenedCA(token) : "---"
        }`,
        callback_data: `TOKEN-${token}`,
      },
    ],
    [
      {
        text: `Snipe Fee: ${snipe_fee} SOL`,
        callback_data: `SNIPE_FEE-${snipe_fee}`,
      },
      {
        text: `Snipe Tip: ${snipe_tip} SOL`,
        callback_data: `SNIPE_TIP-${snipe_tip}`,
      },
    ],
    [
      {
        text: `Slippage: ${slippage}%`,
        callback_data: `SLIPPAGE-${slippage}%`,
      },
    ],
    [
      {
        text: `${tp ? "🟢" : "🔴"} Take Profit(TP): ${tp ? tp : "---"} %`,
        callback_data: `TP-${tp ? tp : "null"}`,
      },
      {
        text: `${sl ? "🟢" : "🔴"} Stop Loss(SL): ${sl ? sl : "---"} %`,
        callback_data: `SL-${sl ? sl : "null"}`,
      },
    ],
    [
      {
        text: `${snipe_amount == 0.2 ? "" : ""}Snipe 0.2 SOL`,
        callback_data: `SNIPE-0.2`,
      },
      {
        text: `${snipe_amount == 0.5 ? "" : ""}Snipe 0.5 SOL`,
        callback_data: `SNIPE-0.5`,
      },
    ],
    [
      {
        text: `${snipe_amount == 1 ? "" : ""}Snipe 1 SOL`,
        callback_data: `SNIPE-1`,
      },
      {
        text: `${
          snipe_amount &&
          snipe_amount != 0.2 &&
          snipe_amount != 0.5 &&
          snipe_amount != 1
            ? ""
            : ""
        }Snipe ${snipe_amount ? snipe_amount : "X"} SOL`,
        callback_data: `SNIPE-${snipe_amount}`,
      },
    ],
    [
      {
        text: `🎯 Create a snipe`,
        callback_data: `CREATE_SNIPE`,
      },
    ],
    [
      {
        text: `📃 Created Snipes`,
        callback_data: `LIST_SNIPE`,
      },
    ],
  ];

  return IK_SNIPE;
}
Enter fullscreen mode Exit fullscreen mode
  • bot/botAction.ts文件
import TelegramBot from "node-telegram-bot-api";
import fs from "fs";

export async function sendIKSnipe(
  bot: TelegramBot,
  chatId: number,
  IK_SNIPE: any,
  caption?: string
) {
  const image = fs.createReadStream("./public/sniper.jpg");

  if (!caption) {
    caption = `⬇You can create a new snipe or check current active snipes!🔍`;
  }

  await bot.sendPhoto(chatId, image, {
    parse_mode: "HTML",
    caption: caption,
    reply_markup: {
      inline_keyboard: IK_SNIPE,
    },
  });
}
Enter fullscreen mode Exit fullscreen mode
  • bot/callbackquery.handler.ts文件
import TelegramBot from "node-telegram-bot-api";
import { getUserById, addUser } from "../service/userService";
import { getIKSnipe } from "../components/inlineKeyboard";
import fs from "fs";
import { BotCaption } from "../config/constants";
import { sendIKSnipe } from "./botAction";
import { addSwap } from "../service/swapService";
import { isValidSnipeConfig } from "../utils/utils";
import buyToken from "../swap/buy";

export async function callbackQueryHandler(
  bot: TelegramBot,
  cb_query: TelegramBot.CallbackQuery,
  userSnipeConfig: Map<number, any>
) {
  const cb_query_cmd = cb_query.data;
  const chatId = cb_query.message?.chat.id;
  const messageId = cb_query.message?.message_id || 0;
  if (!cb_query_cmd || !chatId) return;

  let user;
  const existingUser = await getUserById(chatId);
  if (existingUser) {
    console.log("User already exist: ", chatId);
    user = existingUser;
  } else {
    console.log("New User: ", chatId);
    user = await addUser({
      chat_id: chatId,
      username: cb_query.from.username,
      first_name: cb_query.from.first_name,
      last_name: cb_query.from.last_name,
    });
  }

  switch (cb_query_cmd.split("-")[0]) {
    case "SNIPE_SETTINGS": // Snipe Button
      const snipe_config = userSnipeConfig.get(chatId);
      console.log("Callback snipe_config: ", snipe_config);

      const IK_SNIPE = getIKSnipe(snipe_config);
      sendIKSnipe(bot, chatId, IK_SNIPE);
      break;
    case "BACK": //Back Button
      bot.deleteMessage(chatId, messageId);
      return;
    case "TOKEN": //Token Button
      await bot.sendMessage(chatId, BotCaption.strInputTokenAddress, {
        parse_mode: "HTML",
        reply_markup: {
          force_reply: true,
          selective: true,
        },
      });
      break;
    case "SNIPE_FEE": //Snipe fee Button
      await bot.sendMessage(chatId, BotCaption.SET_PRIORITY_FEE, {
        parse_mode: "HTML",
        reply_markup: {
          force_reply: true,
          selective: true,
        },
      });
      break;
    case "SNIPE_TIP": //Snipe tip Button
      await bot.sendMessage(chatId, BotCaption.SET_JITOTIP, {
        parse_mode: "HTML",
        reply_markup: {
          force_reply: true,
          selective: true,
        },
      });
      break;
    case "SLIPPAGE": //Slippage Button
      await bot.sendMessage(chatId, BotCaption.SET_SLIPPAGE, {
        parse_mode: "HTML",
        reply_markup: {
          force_reply: true,
          selective: true,
        },
      });
      break;
    case "TP": //TP Button
      await bot.sendMessage(chatId, BotCaption.SET_TakeProfit, {
        parse_mode: "HTML",
        reply_markup: {
          force_reply: true,
          selective: true,
        },
      });
      break;
    case "SL": //SL Button
      await bot.sendMessage(chatId, BotCaption.SET_StopLoss, {
        parse_mode: "HTML",
        reply_markup: {
          force_reply: true,
          selective: true,
        },
      });
      break;
    case "SNIPE": //Snipe-[x] Button
      const amount = cb_query_cmd.split("-")[1];
      if (amount == "0.2" || amount == "0.5" || amount == "1") {
        const snipe_config = userSnipeConfig.get(chatId);
        const updated_config = {
          ...snipe_config,
          snipe_amount: parseFloat(amount),
        };
        console.log("Message snipe_config: ", updated_config);
        userSnipeConfig.set(chatId, updated_config);
        const IK_SNIPE = getIKSnipe(updated_config);
        sendIKSnipe(bot, chatId, IK_SNIPE);
      } else {
        await bot.sendMessage(chatId, BotCaption.SET_SNIPE_AMOUNT, {
          parse_mode: "HTML",
          reply_markup: {
            force_reply: true,
            selective: true,
          },
        });
      }
      break;
    case "REFRESH": //Refresh Button
      // Snipe Config Init
      const init_snipe_config: any = {
        token: null,
        slippage: 50,
        snipe_fee: 0.005,
        snipe_tip: 0.005,
        tp: null,
        sl: null,
        snipe_amount: null,
      };

      userSnipeConfig.set(chatId, init_snipe_config);
      const INIT_IK_SNIPE = getIKSnipe(init_snipe_config);
      sendIKSnipe(bot, chatId, INIT_IK_SNIPE);
      break;
    case "CREATE_SNIPE": //Create Snipe Button
      const completed_snipe_config = userSnipeConfig.get(chatId);
      const isValid = isValidSnipeConfig(completed_snipe_config);
      if (isValid) {
        // buyToken
        const result = await buyToken(
          chatId,
          user.private_key,
          completed_snipe_config.snipe_amount,
          completed_snipe_config.token,
          completed_snipe_config.snipe_fee,
          completed_snipe_config.slippage
        );
        if (result && result.status == "success") {
          await bot.sendMessage(
            chatId,
            `Success Buy Token!🎉\nTxID: <code>${result.tx_hash}</code>`,
            { parse_mode: "HTML" }
          );
        } else {
          await bot.sendMessage(chatId, "Failed Buy Token!");
        }
        await addSwap(completed_snipe_config, chatId);
      } else {
        await bot.sendMessage(chatId, BotCaption.SNIPE_CONFIG_FAILED, {
          parse_mode: "HTML",
        });
      }
      break;
    default:
      break;
  }
}

Enter fullscreen mode Exit fullscreen mode
  • bot/message.handler.ts文件
import TelegramBot from "node-telegram-bot-api";
import { getUserById } from "../service/userService";
import { isValidSolanaAddress } from "../utils/utils";
import { BotCaption } from "../config/constants";
import { getIKSnipe } from "../components/inlineKeyboard";
import { sendIKSnipe } from "./botAction";
import { getTokenOverview } from "../service/birdeyeService";

export async function messageHandler(
  bot: TelegramBot,
  msg: TelegramBot.Message,
  userSnipeConfig: Map<number, any>
) {
  try {
    if (!msg.text) return;

    const chatId = msg.chat.id;
    const existingUser = await getUserById(chatId);
    if (!existingUser) {
      return;
    }

    const { reply_to_message } = msg;
    if (reply_to_message && reply_to_message.text) {
      const { text } = reply_to_message;

      const regex = /^[0-9]+(\.[0-9]+)?$/;
      const isNumber = regex.test(msg.text) === true;
      const reply_message_id = reply_to_message.message_id;

      switch (text) {
        case BotCaption.strInputTokenAddress:
        case BotCaption.strInvalidSolanaTokenAddress:
          const isCA = await isValidSolanaAddress(msg.text);
          if (isCA) {
            const snipe_config = userSnipeConfig.get(chatId);
            console.log("Message snipe_config: ", snipe_config);
            const updated_config = { ...snipe_config, token: msg.text };
            userSnipeConfig.set(chatId, updated_config);
            // snipe_config.token = msg.text;
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(
              chatId,
              BotCaption.strInvalidSolanaTokenAddress,
              {
                parse_mode: "HTML",
                reply_markup: {
                  force_reply: true,
                  selective: true,
                },
              }
            );
            return;
          }
          break;
        case BotCaption.SET_PRIORITY_FEE.replace(/<[^>]*>/g, ""):
          console.log("priority fee");
          if (isNumber) {
            const snipe_config = userSnipeConfig.get(chatId);
            const updated_config = {
              ...snipe_config,
              snipe_fee: parseFloat(msg.text),
            };
            console.log("Message snipe_config: ", updated_config);
            userSnipeConfig.set(chatId, updated_config);
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(chatId, BotCaption.strInvalidInput);
          }
          break;
        case BotCaption.SET_JITOTIP.replace(/<[^>]*>/g, ""):
          console.log("jito tip");
          if (isNumber) {
            const snipe_config = userSnipeConfig.get(chatId);
            const updated_config = {
              ...snipe_config,
              snipe_tip: parseFloat(msg.text),
            };
            console.log("Message snipe_config: ", updated_config);
            userSnipeConfig.set(chatId, updated_config);
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(chatId, BotCaption.strInvalidInput);
          }
          break;
        case BotCaption.SET_SLIPPAGE.replace(/<[^>]*>/g, ""):
          console.log("slippage");
          if (isNumber) {
            const snipe_config = userSnipeConfig.get(chatId);
            const updated_config = {
              ...snipe_config,
              slippage: parseFloat(msg.text),
            };
            console.log("Message snipe_config: ", updated_config);
            userSnipeConfig.set(chatId, updated_config);
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(chatId, BotCaption.strInvalidInput);
          }
          break;
        case BotCaption.SET_TakeProfit.replace(/<[^>]*>/g, ""):
          console.log("take profit");
          if (isNumber) {
            const snipe_config = userSnipeConfig.get(chatId);
            const updated_config = {
              ...snipe_config,
              tp: parseFloat(msg.text),
            };
            console.log("Message snipe_config: ", updated_config);
            userSnipeConfig.set(chatId, updated_config);
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(chatId, BotCaption.strInvalidInput);
          }
          break;
        case BotCaption.SET_StopLoss.replace(/<[^>]*>/g, ""):
          console.log("priority fee");
          if (isNumber) {
            const snipe_config = userSnipeConfig.get(chatId);
            const updated_config = {
              ...snipe_config,
              sl: parseFloat(msg.text),
            };
            console.log("Message snipe_config: ", updated_config);
            userSnipeConfig.set(chatId, updated_config);
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(chatId, BotCaption.strInvalidInput);
          }
          break;
        case BotCaption.SET_SNIPE_AMOUNT.replace(/<[^>]*>/g, ""):
          console.log("snipe amount");
          if (isNumber) {
            const snipe_config = userSnipeConfig.get(chatId);
            const updated_config = {
              ...snipe_config,
              snipe_amount: parseFloat(msg.text),
            };
            console.log("Message snipe_config: ", updated_config);
            userSnipeConfig.set(chatId, updated_config);
            const IK_SNIPE = getIKSnipe(updated_config);
            sendIKSnipe(bot, chatId, IK_SNIPE);
          } else {
            await bot.deleteMessage(chatId, msg.message_id);
            await bot.deleteMessage(chatId, reply_message_id);

            await bot.sendMessage(chatId, BotCaption.strInvalidInput);
          }
          break;
      }
    } else {
      const isCA = await isValidSolanaAddress(msg.text);
      if (isCA) {
        const tokenInfo = await getTokenOverview(msg.text);

        const caption = `Name (Symbol): ${tokenInfo.name} (${tokenInfo.symbol})\nPrice: ${tokenInfo.price}\nMarketCap: ${tokenInfo.marketCap}`;

        const snipe_config = userSnipeConfig.get(chatId);
        console.log("Message snipe_config: ", snipe_config);
        const updated_config = { ...snipe_config, token: msg.text };
        userSnipeConfig.set(chatId, updated_config);
        const IK_SNIPE = getIKSnipe(updated_config);
        sendIKSnipe(bot, chatId, IK_SNIPE, caption);
      } else {
        return;
      }
    }
  } catch (error) {}
}
Enter fullscreen mode Exit fullscreen mode

提示:您可以在我的 Github 存储库中找到所有文件


步骤 3:运行代码

  • 在终端中运行以下命令:
npm run start
Enter fullscreen mode Exit fullscreen mode


3.下一期将会有什么内容?

在下一期中,我将讲解有关在 Raydium 和 PumpFun 上聆听新池的创建。



✅您可以在我的 Github 上查看完整代码:

我的 Github 代码

如果你喜欢我的文章,请在 Github 上关注我。
关注我


❓如果您对这篇文章有任何疑问或意见,请随时联系我。🎯


📧我的联系方式

Gmail : saivietthanh0314@gmail.com
电报

文章来源:https://dev.to/vietthanhsai/how-to-build-your-solana-sniper-bot-4-55c3
PREV
优化 Web 应用程序性能的 9 个简单步骤
NEXT
如何打造你的 Solana 狙击机器人 (3)💰🚀