如何打造你的 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
- 检查
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"
}
}
tsc --init
使用命令安装 Typescript 环境。tsconfig.json
像这样编辑文件:
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
- .env 文件
SENDER_WALLET_PRIVATE_KEY="PRIVATE KEY OF WALLET A"
RECEIVER_WALLET_PUBLIC_KEY="PUBLIC KEY OF WALLET B"
第 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");
步骤 3:运行代码
- 在终端中运行以下命令:
npm run start
- 如果交易成功,您将收到来自 solscan 的交易链接。
3.下一期将会有什么内容?
我将解释 Solana DEX 以及如何购买/出售 SPL 代币。
✅您可以在我的 Github 上查看完整代码:
如果你喜欢我的文章,请在 Github 上关注我。
关注我
❓如果您对这篇文章有任何疑问或意见,请随时联系我。🎯
📧我的联系方式
Gmail : saivietthanh0314@gmail.com
电报