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

2025-06-07

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

你好👋,

在上一期中,我介绍了构建 Solana Sniper 机器人的基本步骤、编程技术等。作为编码过程的一部分,我们还开发了一个脚本,用于将 SOL 从钱包 A 转移到钱包 B。

在本期中,我将深入探讨 Solana SPL 代币,探索其在 Solana 生态系统中的功能和重要性。作为实际实现的一部分,我将引导您完成编码过程,特别关注如何将 SPL 代币从钱包 A 转移到钱包 B。

1. Solana SPL 代币

1.1 为什么在开发 Solana Sniper Bot 时应该了解 SPL 代币

在深入研究 Solana SPL 代币之前,了解 SPL 代币和 Solana 狙击机器人之间的关系至关重要。

  • 核心功能:SPL 代币是 Solana 区块链上的代币标准,类似于以太坊上的 ERC-20 代币。由于狙击机器人经常以新发行的代币或流动性池为目标,因此了解 SPL 代币对于以编程方式与这些资产进行交互至关重要。

  • 代币交易:狙击机器人需要高速执行 SPL 代币的买卖订单或转账。学习如何处理 SPL 代币,可以让你对机器人进行编程,使其高效地执行这些交易,这对于抓住市场机遇至关重要。

  • 市场机遇:许多狙击机器人专注于交易新发行的SPL代币,这些代币的价格波动通常较大。通过了解SPL代币,您可以快速识别并与之互动,从而提升您的机器人的竞争优势。

  • 与 DeFi 协议集成:Solana 上的许多去中心化金融 (DeFi) 协议都使用 SPL 代币。了解 SPL 代币可以让您的机器人与这些协议(例如去中心化交易所 (DEX) 或借贷平台)进行交互,从而扩展其功能和潜在的盈利能力。

  • 自定义代币策略:一些狙击机器人专门针对特定类型的代币(例如,模因币、治理代币或 NFT)。了解 SPL 代币后,您可以根据这些独特的代币类型定制机器人的策略。

1.2 什么是 SPL 代币?

Solana SPL 代币(Solana 程序库代币)是在 Solana 区块链上创建和管理代币的标准。它类似于以太坊上的 ERC-20 标准,但针对 Solana 的高速、低成本基础设施进行了优化。

  • 定义:SPL代币是使用Solana程序库(SPL)创建和管理的数字资产,它为代币的创建、转移和管理提供了一套规则和标准。

  • 可替代性:SPL 代币通常是可替代的,这意味着每个代币都可以与同一类型的另一个代币互换(例如,1 USDC 始终等于 1 USDC)。

  • 可扩展性:SPL 代币标准还可用于非同质化代币 (NFT) 和半同质化代币,使其适用于各种用例。

1.3 SPL代币的组成部分

  • 代币铸币厂:“铸币厂”是链上账户,用于定义代币的属性,例如其供应量、小数位数和权限。每个 SPL 代币都有一个唯一的铸币厂地址。

  • 代币账户:每个代币账户为用户持有一定数量的代币。每个用户可以拥有多个代币账户,用于持有不同的 SPL 代币。

  • 小数:SPL 代币最多可以有 9 位小数,从而允许精确的小数部分(例如 0.000000001)。

  • 授权机构:授权机构是指对代币铸造或代币账户拥有控制权的实体(例如,钱包或程序)。这包括:

    • 铸币局:控制新代币的创建。
    • 冻结权限:可以冻结代币账户(可选)。
    • 所有者:拥有代币账户并可以转移代币的钱包。

1.4 其他

  • SPL代币如何运作

    • 创建:开发者通过在 Solana 区块链上初始化一个“mint”账户来创建 SPL 代币。这将定义代币的属性,例如总供应量和小数位数。
    • 分发:通过将代币转移到用户的代币账户来分发给用户。
    • 转账:用户可以通过签署更新其代币账户余额的交易来发送和接收 SPL 代币。
    • 销毁:可以通过将代币发送到销毁地址来“销毁”(毁坏)代币,从而减少总供应量。
  • SPL 代币与原生 SOL

    • 原生 SOL:SOL 是 Solana 区块链的原生加密货币,用于支付交易费用和质押。
    • SPL 代币:SPL 代币建立在 Solana 区块链之上,代表自定义资产。在转移或与其交互时,需要 SOL 支付交易费。
  • SPL 令牌的工具和库

    • SPL 代币程序:定义创建和管理 SPL 代币规则的链上程序。
    • Solana Web3.js:一个用于与 Solana 区块链交互的 JavaScript 库,包括 SPL 代币。
    • 钱包:Phantom、Solflare 和 Sollet 等钱包支持 SPL 代币。
    • 浏览器:Solscan 和 Solana Explorer 等工具允许用户查看 SPL 代币交易和余额。


2.代币 2022

Token 2022 是 Solana 区块链上 SPL Token 标准的升级或扩展。SPL Token 是 Solana 上创建和管理代币的标准,类似于以太坊上的 ERC-20 代币,但 Token 2022 计划引入了更多功能和改进,以增强代币创建者和用户的功能性、安全性和灵活性。

2.1 Token 2022 的主要特点

  • 增强功能
    Token 2022 通过添加新功能扩展了原始 SPL Token 标准的功能,例如:

    • 机密转账:实现对金额和余额进行加密的隐私保护交易。
    • 转移挂钩:允许开发人员在转移代币时实现自定义逻辑,例如强制收取费用或进行限制。
    • 不可转让代币:支持创建不可转让的代币,用于表示所有权或凭证。
    • 计息代币:使代币能够随着时间的推移而累积利息,这对于金融应用很有用。
  • 提高安全性:Token 2022 引入了额外的安全措施来防止漏洞并确保更安全的令牌操作。

  • 向后兼容性:升级旨在与现有的 SPL 令牌标准向后兼容,确保现有令牌和应用程序继续运行而不会中断。

  • 开发人员灵活性:Token 2022 为开发人员提供了更多工具和选项来创建基于代币的创新应用程序,例如去中心化金融 (DeFi) 平台、游戏资产等。

  • 监管合规性:机密转移和不可转让代币等功能可以帮助项目遵守监管要求,例如隐私法或代币转移限制。

2.2 Token 2022 为何重要

  • 创新:Token 2022 使开发人员能够创建更复杂的代币,这些代币具有原始 SPL 代币标准无法实现的功能。

  • DeFi 增长:生息代币和保密转账等高级功能可以推动 Solana 上去中心化金融 (DeFi) 的创新。

  • 隐私:机密转移解决了隐私问题,使 Solana 对用户和机构更具吸引力。

  • 可定制性:开发人员可以根据特定用例定制代币,例如动态 NFT 或具有基于角色的权限的代币。

2.3 Token 2022 的实际应用示例

  • 有利息的代币:权益质押协议可以发行根据权益质押奖励自动累积利息的代币。

  • 机密转移:以隐私为中心的应用程序可以使用 Token 2022 来隐藏交易金额,同时仍保持审计员的透明度。

  • 动态 NFT:NFT 项目可以使用 Token 2022 创建具有随时间演变的元数据的代币(例如,游戏中升级的角色)。

2.4 SPL 代币与 2022 年代币

  • SPL 代币
    SPL(Solana 程序库)代币是 Solana 上的原始代币标准,旨在创建可替代和不可替代代币(NFT)。
    限制

    • 高级功能的扩展性有限。
    • 不提供对计息代币、机密转移或基于角色的权限等功能的原生支持。
  • 代币 2022

    • Token 2022 是基于原有 SPL 代币计划构建的升级版、更先进的代币标准。它引入了新的特性和功能,以支持更复杂的用例。
  • SPL 代币和 2022 代币之间的主要区别

特征 SPL代币 代币 2022
标准 原始代币标准 升级和先进的标准
功能 基本代币创建和转移 高级功能,如生息代币、保密转账等。
可扩展性 有限的 高度可扩展,具有自定义逻辑
向后兼容性 不适用 与 SPL 代币兼容
用例 可替代代币(NFT) 复杂的 DeFi、隐私代币、动态 NFT


3.如何将 SPL 代币从钱包 A 转移到钱包 B

在上一期中,我们已经开发了一个用于转移 SOL 的脚本。
这次,让我们使用您自己的代码来发送 SPL 代币。

步骤1:设置环境

  • 为了方便起见,我们使用 VS Code 开发自己的代码。假设你已经安装了 Node.js(18.0 或更高版本)。
  • 另外,我们需要钱包 A 和钱包 B。准确地说,要将钱从钱包 A 发送到钱包 B,您需要钱包 A 的私钥和钱包 B 的公钥。
  • 使用初始化您的项目npm init
  • 使用此命令安装依赖项:
npm install typescript ts-node @project-serum/anchor @solana/web3.js @solana/spl-token dotenv bs58
Enter fullscreen mode Exit fullscreen mode
  • 检查package.json文件并编辑脚本如下:
{
  "main": "index.ts",
  "scripts": {
    "build": "tsc",
    "start": "ts-node index.ts",
    "clean": "tsc --build --clean",
    "dev": "tsc && node ./dist/index.js"
  },
  "dependencies": {
    "@project-serum/anchor": "^0.26.0",
    "@solana/spl-token": "^0.4.12",
    "@solana/web3.js": "^1.98.0",
    "bs58": "^6.0.0",
    "dotenv": "^16.4.7",
    "typescript": "^5.7.3"
  },
  "devDependencies": {
    "@types/node": "^22.13.4",
    "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 文件
SENDER_WALLET_PRIVATE_KEY="PRIVATE KEY OF WALLET A"
RECEIVER_WALLET_PUBLIC_KEY="PUBLIC KEY OF WALLET B"
Enter fullscreen mode Exit fullscreen mode

第 2 步:主代码(index.ts)

此代码将 SPL 代币和 Token 2022 代币从钱包 A 转移到钱包 B。

import dotenv from "dotenv";
import bs58 from "bs58";
import {
  LAMPORTS_PER_SOL,
  Keypair,
  Connection,
  PublicKey,
  clusterApiUrl,
  ComputeBudgetProgram,
  TransactionMessage,
  VersionedTransaction,
  TransactionInstruction
} from "@solana/web3.js";
import {
  getOrCreateAssociatedTokenAccount,
  getMint,
  createTransferInstruction,
  TOKEN_PROGRAM_ID,
  TOKEN_2022_PROGRAM_ID, 
  ASSOCIATED_TOKEN_PROGRAM_ID,
  createTransferCheckedInstruction,
} from "@solana/spl-token";
import { BN } from "@project-serum/anchor";

dotenv.config();

// Keys from .env
const fromWalletPrivateKeyString = process.env
  .SENDER_WALLET_PRIVATE_KEY as string;
const receiverPublicKeyString = process.env
  .RECEIVER_WALLET_PUBLIC_KEY as string;

const fromWallet = Keypair.fromSecretKey(bs58.decode(fromWalletPrivateKeyString));
const toWalletPublicKey = new PublicKey(receiverPublicKeyString);

// transferSplToken function
async function transferSplToken(mint:PublicKey, transferAmount: number, network: string = "mainnet") {
  let connection: Connection;
  if (network === "mainnet") {
    connection = new Connection("https://api.mainnet-beta.solana.com");
  } else {
    connection = new Connection(clusterApiUrl("devnet"), "confirmed");
  }
  // Check fromWallet balance
  const fromWalletBalance = await connection.getBalance(fromWallet.publicKey);
  console.log("From Wallet Balance:", fromWalletBalance / LAMPORTS_PER_SOL, "SOL");

  if (fromWalletBalance < 0.01 * LAMPORTS_PER_SOL) {
    throw new Error("From wallet does not have enough SOL to pay for transaction fees.");
  }

  const accountInfo = await connection.getAccountInfo(mint);
  const tokenProgramID = accountInfo?.owner;
  console.log("Token ProgramID", tokenProgramID);

  // Get token mint info (including decimals)
  const mintInfo = await getMint(
    connection,
    mint,
    "confirmed",
    tokenProgramID // TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID
  );
  console.log("Token Decimals:", mintInfo);

  console.log("ASSOCIATED_TOKEN_PROGRAM_ID: ", ASSOCIATED_TOKEN_PROGRAM_ID);

  // Get the token account of the fromWall address, if it doesn't exist, create it
  const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    fromWallet,
    mint,
    fromWallet.publicKey,
    false,
    undefined,
    undefined,
    tokenProgramID, // TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID
    ASSOCIATED_TOKEN_PROGRAM_ID
  );

  //get the token account of the toWallet address, if it does not exist, create it
  const toTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    fromWallet, // payer
    mint,
    toWalletPublicKey,
    false,
    undefined,
    undefined,
    tokenProgramID, // TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID
    ASSOCIATED_TOKEN_PROGRAM_ID
  );

  console.log ("fromTokenAccount::", fromTokenAccount.toString());

  // Check the balance of the fromTokenAccount
  const fromTokenAccountBalance = await connection.getTokenAccountBalance(fromTokenAccount.address);
  console.log("From Token Account Balance:", fromTokenAccountBalance.value.uiAmount, "tokens");

  // Ensure the fromTokenAccount has enough tokens for the transfer
  if (fromTokenAccountBalance.value.uiAmount === null || fromTokenAccountBalance.value.uiAmount < transferAmount) {
    throw new Error("Insufficient funds in the fromTokenAccount.");
  }

  // // Token Transfer Instruction
  let transferInstruction: TransactionInstruction;

  if(String(tokenProgramID) == String(TOKEN_PROGRAM_ID)){
    transferInstruction = createTransferInstruction(
      fromTokenAccount.address,
      toTokenAccount.address,
      fromWallet.publicKey,
      transferAmount * Math.pow(10, mintInfo.decimals)
    );
  } else { 
    //tokenProgramID == TOKEN_2022_PROGRAM_ID
    transferInstruction = createTransferCheckedInstruction(
      fromTokenAccount.address,
      mint,
      toTokenAccount.address,
      fromWallet.publicKey,
      new BN(transferAmount * Math.pow(10, mintInfo.decimals)),
      mintInfo.decimals,
      [],
      TOKEN_2022_PROGRAM_ID
    );
  }

  // Priority fee instruction
  const PRIORITY_FEE_MICRO_LAMPORTS = 200000; // 0.2 lamports per compute unit (adjust as needed)
  // Instruction to set the compute unit price for priority fee
  const PRIORITY_FEE_INSTRUCTIONS = ComputeBudgetProgram.setComputeUnitPrice({microLamports: PRIORITY_FEE_MICRO_LAMPORTS});

  // Fetch a fresh blockhash
  const latestBlockhash = await connection.getLatestBlockhash();

  // Compiles and signs the transaction message with the sender's Keypair.
  const messageV0 = new TransactionMessage({
    payerKey: fromWallet.publicKey,
    recentBlockhash: latestBlockhash.blockhash,
    instructions: [PRIORITY_FEE_INSTRUCTIONS, transferInstruction],
  }).compileToV0Message();

  const versionedTransaction = new VersionedTransaction(messageV0);

  // Sign transaction, broadcast, and confirm
  versionedTransaction.sign([fromWallet]);

  // Attempts to send the transaction to the network, handling success or failure.
  try {
    const transactionSignature = await connection.sendTransaction(versionedTransaction, {
      maxRetries: 20,
    });

    const confirmation = await connection.confirmTransaction(
      {
        signature: transactionSignature,
        blockhash: latestBlockhash.blockhash,
        lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
      },
      "confirmed"
    );
    if (confirmation.value.err) {
      throw new Error("🚨Transaction not confirmed.");
    }

    if(network === "mainnet"){
      console.log(
        "Transaction Signature: ",
        `https://solscan.io/tx/${transactionSignature}`
      );
    } else {
      console.log(
        "Transaction Signature: ",
        `https://solscan.io/tx/${transactionSignature}?cluster=devnet`
      );
    }

  } catch (error) {
    console.error("Transaction failed", error);
  }
}

// Test
let mint: PublicKey;  // Mint Account Address (Token Address)
mint = new PublicKey("C8NEYcW7eoQsrQ7vqeiUTLFxwJQNHgj8LwSc3BUQx6YG"); // Devnet SPL Token
transferSplToken(mint, 1000000, "devnet");

mint = new PublicKey("13pkrcqF47rF2oF4kZnBVzH5omQ2f7nF429vzpjgL896"); // Devnet Token2022 Token
transferSplToken(mint, 1000000, "devnet");

mint = new PublicKey("7WphEnjwKtWWMbb7eEVYeLDNN2jodCo871tVt8jHpump"); // Mainnet SPL Token
transferSplToken(mint, 10, "mainnet");

mint = new PublicKey("HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC"); // Mainnet Token2022 Token
transferSplToken(mint, 0.05, "mainnet");
Enter fullscreen mode Exit fullscreen mode

步骤 3:运行代码

  • 在终端中运行以下命令:
npm run start
Enter fullscreen mode Exit fullscreen mode
  • 如果交易成功,您将收到来自 solscan 的交易链接。


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

我将解释 Solana DEX 以及如何购买/出售 SPL 代币。



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

我的 Github 代码

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


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


📧我的联系方式

Gmail : saivietthanh0314@gmail.com
电报

文章来源:https://dev.to/vietthanhsai/how-to-build-your-solana-sniper-bot-2-18b
PREV
如何打造你的 Solana 狙击机器人 (3)💰🚀
NEXT
降低信息系统复杂性的简单方法