本文介绍了如何使用Pump.fun API和Yellowstone gRPC创建Solana交易机器人,以复制指定钱包的交易。内容包括配置项目、构建交易机器人、测试机器人等步骤。
本指南仅供教育目的,不应被视为财务建议。交易机器人可能存在风险,可能导致经济损失。请务必自行研究,并考虑在使用交易机器人或参与交易活动之前咨询财务顾问。确保在使用真实资金之前,你运行的所有代码都是安全且经过彻底测试的。
在本指南中,我们将学习如何创建一个 Solana 交易机器人,该机器人使用QuickNode 的 Metis 插件 和Yellowstone gRPC 来复制指定钱包在 Pump.fun DEX 上的交易。此指南面向具备 JavaScript、Solana 和基本 DeFi 概念知识的开发者。
更喜欢使用 Solana Web3.js 2.0 或 TypeScript?
如果你更喜欢使用 TypeScript 或新的 Solana Web3.js 2.0 库,请查看我们关于使用 Yellowstone 监控程序和如何使用 Solana Web3.js 2.0 构建 Pump.fun API 的指南。
solana-keygen -h
获取支持以创建新钱包的帮助)Solana 主要网 RPC 端点
要在 Solana 上进行构建,你需要一个 API 端点以连接到网络。你可以使用公共节点或自行部署和管理基础架构;但是,如果你希望享受 8 倍的更快响应时间,可以将繁重的工作交给我们。
了解为什么超过 50% 的 Solana 项目选择 QuickNode,并在这里 注册免费账户。我们将使用一个 SolanaMainnet 端点。
复制 HTTP 提供者链接:
Metis 是一个强大的工具,帮助开发者访问 Solana 上的流动性。通过集成 Jupiter 的 V6 交换 API、限制订单 API、Pump.fun 交易、交易 WebSocket 等,你可以访问构建强大交易工具所需的工具,以访问 Solana 上的多个 DeFi 协议。Metis 可作为 QuickNode 市场上的附加组件, 在这里 或者可以通过 JupiterAPI.com 访问公共端点。
在本指南中,我们将重点关注 /pump-fun/swap
端点(文档),该端点允许我们获取用于在 Pump.fun 上执行交换的序列化交易。此端点需要以下参数:
wallet
:执行交易的钱包的公钥type
:交易类型("BUY" 或 "SELL")mint
:被交易的代币的 mint 地址inAmount
:输入代币的数量(以原始单位表示)priorityFeeLevel
(可选):交易的优先费用级别("low"、"medium"、"high" 或 "auto")slippageBps
(可选):允许的最大滑点(以基点表示)来自该端点的响应包含一个 base64 编码的 Solana 交易,可以签名并发送到网络以执行交易。
Yellowstone 是一个市场附加组件,提供基于 gRPC 的 API,使开发者能够创建自定义订阅并在 Solana 网络上实时接收事件更新。这使其成为构建需要实时监控区块链活动的应用程序(例如交易机器人、分析平台和去中心化应用程序 dApps)的优秀工具。
要使用 Yellowstone,我们需要创建一个订阅请求,指定我们希望监控的账户、交易和其他事件。Yellowstone 将流式传输我们指定事件的实时更新。
有关 Yellowstone 的更多信息,请查看:
在开始构建交易机器人之前,让我们设置项目并安装必要的依赖项。
为你的项目创建一个新目录,并在终端中导航到该目录。
通过运行以下命令初始化一个新的 Node.js 项目:
npm init -y
npm install @solana/web3.js@1 bs58 dotenv @triton-one/yellowstone-grpc
@solana/web3.js
:与 Solana 区块链交互的 Solana Web3.js 库的旧版本bs58
:用于处理 Base58 编码/解码的库dotenv
:用于从 .env
文件加载环境变量的库@triton-one/yellowstone-grpc
:Yellowstone gRPC 客户端库在你的项目目录中创建一个名为 bot.js
的新文件。
在你的项目目录中创建一个 .env
文件,并添加以下环境变量:
SOLANA_RPC=<your_solana_rpc_endpoint> # https://example.quiknode.pro/replace-me-123/
SECRET_KEY=<your_wallet_secret_key> # [0, 0, ..., 0]
METIS_ENDPOINT=<your_metis_endpoint> # https://jupiter-swap-api.quiknode.pro/REPLACE_ME
YELLOWSTONE_ENDPOINT=<your_yellowstone_endpoint> # https://example.solana-mainnet.quiknode.pro:10000
YELLOWSTONE_TOKEN=<your_yellowstone_token> # abc...xyz
替换占位符为你的实际值:
SOLANA_RPC
:你的 QuickNode Solana 主要网 RPC 端点(你可以在 QuickNode 仪表板 中找到此内容)SECRET_KEY
:你的 Solana 钱包的秘密密钥(JSON 数组格式,例如 [0, 0, ..., 0]
)。确保此钱包充满 SOL 以便机器人能执行交易。METIS_ENDPOINT
:你的 QuickNode Metis 端点用于 Pump.fun API(例如 https://jupiter-swap-api.quiknode.pro/...
)。如果没有 Metis 附加组件,你可以使用公共端点:https://public.jupiterapi.com
(注意:公共端点可能会产生交易费用——请查看 jupiterapi.com 获取详细信息)。YELLOWSTONE_ENDPOINT
:你的 Yellowstone 端点(注意:这应是以 gRPC 端点,结尾需为 :10000
,有关更多信息,请查看 这里)YELLOWSTONE_TOKEN
:你的 Yellowstone API Token(在 这里 查找你的Token)现在我们已经设置好了项目,让我们开始构建交易机器人。🤖
从高层来看,我们将要做的事情如下:
打开 bot.js
文件并添加以下代码:
require("dotenv").config();
const fs = require("fs");
const fetch = require("node-fetch");
const bs58 = require("bs58").default;
const {
Connection,
Keypair,
VersionedTransaction,
LAMPORTS_PER_SOL,
PublicKey,
} = require("@solana/web3.js");
const Client = require("@triton-one/yellowstone-grpc").default;
const { CommitmentLevel } = require("@triton-one/yellowstone-grpc");
class CopyTradeBot {
config = {
WATCH_LIST: [\
"WALLET_TO_TRACK_1",\
"WALLET_TO_TRACK_2",\
"WALLET_TO_TRACK_3",\
//...\
],
PUMP_FUN: {
PROGRAM_ID: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
FEE_ACCOUNT: "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM",
BUY_DISCRIMINATOR: Buffer.from([102, 6, 61, 18, 1, 218, 235, 234]),
SELL_DISCRIMINATOR: Buffer.from([51, 230, 133, 164, 1, 127, 131, 173]),
TOKEN_DECIMALS: 6,
TARGET_ACCOUNTS: {
BUY: [\
{ name: "mint", index: 2 },\
{ name: "user", index: 6 },\
],
SELL: [\
{ name: "mint", index: 2 },\
{ name: "user", index: 6 },\
],
},
},
MIN_TX_AMOUNT: LAMPORTS_PER_SOL / 1000,
BUY_AMOUNT: LAMPORTS_PER_SOL / 1000,
LOG_FILE: "pump_fun_swaps.json",
COMMITMENT: CommitmentLevel.CONFIRMED,
TEST_MODE: true
};
constructor() {
this.validateEnv();
this.connection = new Connection(process.env.SOLANA_RPC);
this.wallet = Keypair.fromSecretKey(
Uint8Array.from(JSON.parse(process.env.SECRET_KEY))
);
console.log("🤖 机器人钱包:", this.wallet.publicKey.toBase58());
console.log("监控地址:");
this.config.WATCH_LIST.forEach((address) => console.log(" -", address));
}
// ... (其他方法将在这里添加)
}
这段代码设置了交易机器人的初始配置。配置每个部分的作用如下:
WATCH_LIST
:一个监控交易的Wallet地址数组。为了本示例,请从你的浏览器钱包中使用一个钱包地址(例如 Phantom、SolFlare、Backpack 等)。我们将在本指南的后面使用该钱包在 Pump.fun 上执行交易。PUMP_FUN
:一个包含 Pump.fun 程序配置详细信息的对象,包括程序 ID、费用账户、购买和出售指令的识别符、代币小数位数以及指令中目标账户(mint 用户)索引的配置。这些都是从 Pump.fun 的程序 IDL 和指令中得到的已知常量。在我们的 Solana 程序 IDL 指南 中获取更多信息。MIN_TX_AMOUNT
:机器人考虑交易所需的最低 SOL 数量(如果目标钱包消费的金额小于该金额,我们将直接忽略该交易)。BUY_AMOUNT
:机器人用于执行购买交易的 SOL 数量。为了演示,我们将只设置一个静态购买金额——如果我们看到一个想要复制的交易,我们将固定金额的 SOL 进行复制交易。完成指南后,你可以根据自己的用例自行尝试不同策略。LOG_FILE
:机器人将成功交易记录的文件路径。COMMITMENT
:Yellowstone 订阅的承诺级别。TEST_MODE
:启用/禁用测试模式的标志。当设置为 true
时,机器人将仿真交易,而不是在 Solana 网络上实际执行。这对于测试机器人的功能而不冒用真实资金是有用的。constructor
方法验证所需的环境变量,创建了一个 Solana 连接,并使用提供的秘密密钥初始化机器人的钱包。
让我们添加我们的其他方法!
我们在上面的构造函数中已经添加了一个 validateEnv()
方法,用于确保所需的环境变量已设置。该方法在 CopyTradeBot 类实例化时被触发。如果缺少任何必需的变量,机器人将抛出错误并退出。
在你的 CopyTradeBot 类中添加以下方法以验证所需的环境变量:
validateEnv = () => {
const requiredEnvs = [\
"SOLANA_RPC",\
"SECRET_KEY",\
"METIS_ENDPOINT",\
"YELLOWSTONE_ENDPOINT",\
"YELLOWSTONE_TOKEN",\
];
requiredEnvs.forEach((env) => {
if (!process.env[env]) {
throw new Error(`缺少必需的环境变量: ${env}`);
}
});
};
这将检查所有必需的环境变量在继续之前是否已设置。
让我们创建一个 fetchSwapTransaction()
方法,该方法将负责与 Pump.fun API(通过你的 Metis 端点)通信,以获取执行交换所需的序列化交易。你提供的信息包括钱包地址、交换类型(例如 "BUY")、代币 mint 和交换金额。
fetchSwapTransaction = async ({
wallet,
type,
mint,
inAmount,
priorityFeeLevel = "high",
slippageBps = "100",
}) => {
const body = JSON.stringify({
wallet,
type,
mint,
inAmount,
priorityFeeLevel,
slippageBps,
});
const res = await fetch(`${process.env.METIS_ENDPOINT}/pump-fun/swap`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
});
if (!res.ok) {
throw new Error(`交换指令获取错误: ${await res.text()}`);
}
return res.json();
};
该方法的两个主要组件如下:
body
:包含 Pump.fun API 生成交换交易所需的参数。fetch
:向 Pump.fun 的 /swap
端点发送 POST 请求,并提供参数。如果成功,你将获得一个 JSON 响应,其中包含一个 base64 编码的交易。有关此方法的更多信息,请查看我们 Pump.fun API 文档 在这里。
一旦 Pump.fun API 返回一个 base64 编码的交易,你需要使用机器人的 Keypair 在本地进行签名。让我们在 CopyTradeBot 类中添加一个负责此操作的 signTransaction()
方法:
signTransaction = async (swapTransaction) => {
const transaction = VersionedTransaction.deserialize(
Buffer.from(swapTransaction, "base64")
);
const latestBlockHash = await this.connection.getLatestBlockhash();
transaction.message.recentBlockhash = latestBlockHash.blockhash;
transaction.sign([this.wallet]);
const txBuffer = Buffer.from(transaction.serialize());
const txBase64 = txBuffer.toString("base64");
return txBase64;
};
因为交易已经序列化,所以我们需要将其反序列化为一个 VersionedTransaction
对象,用机器人的钱包进行签名,然后重新序列化为原始字节以供广播:
VersionedTransaction
对象。下一步是将签名后的交易广播到 Solana 网络。在你的机器人类中添加以下 sendAndConfirmTransaction()
方法:
sendAndConfirmTransaction = async (signedTxBase64) => {
try {
const txid = await this.connection.sendEncodedTransaction(signedTxBase64, {
skipPreflight: false,
encoding: 'base64'
});
const timeout = 30 * 1000;
const pollInterval = 3 * 1000;
const start = Date.now();
while (Date.now() - start < timeout) {
const response = await this.connection.getSignatureStatuses([txid]);
if (!response) {
await new Promise(resolve => setTimeout(resolve, pollInterval));
continue;
}
const statuses = response.value;
if (!statuses || statuses.length === 0) {
await new Promise(resolve => setTimeout(resolve, pollInterval));
continue;
}
const status = statuses[0];
if (status === null) {
await new Promise(resolve => setTimeout(resolve, pollInterval));
continue;
}
if (status.err) {
throw new Error(`交易失败: ${JSON.stringify(status.err)}`);
}
if (status.confirmationStatus && (status.confirmationStatus === 'confirmed' || status.confirmationStatus === 'finalized')) {
return txid;
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error(`交易确认超时,超时后 ${timeout}ms`);
} catch (error) {
throw {error, base64: Buffer.from(rawTransaction).toString("base64")};
}
};
该方法将签名后的交易发送到 Solana 网络,并等待其确认。使用以下步骤:
sendEncodedTransaction()
:将签名交易作为 base64 字符串发送到集群,并返回交易签名(txid)——请注意,由于我们在上一步中序列化了交易,因此可以使用 sendEncodedTransaction()
方法。创建该交易的 API 已经模拟了交易以计算计算单元,因此可以跳过预检查。getSignatureStatuses()
检查交易状态,直到确认或超时。有关最佳实践的更多信息,请查看我们的文档 在这里。为了记录和调试,logSwap()
方法将每个交换的 JSON 记录写入日志文件:
logSwap = (swapLog) => {
const logs = fs.existsSync(this.config.LOG_FILE)
? JSON.parse(fs.readFileSync(this.config.LOG_FILE, "utf-8"))
: [];
logs.push(swapLog);
fs.writeFileSync(this.config.LOG_FILE, JSON.stringify(logs, null, 2));
};
这里的工作原理如下:
pump_fun_swaps.json
存在,将其读取并解析为数组。swapLog
对象添加到数组中。每当我们检测到来自 WATCH_LIST
中“鲸鱼”的购买交易超过某个阈值(MIN_TX_AMOUNT
)时,我们需要执行某些逻辑。让我们在 CopyTradeBot 类中创建一个方法 handleWhaleBuy()
,在知道“鲸鱼”完成达成我们标准的购买交易后执行复制交易。将以下方法添加到你的 CopyTradeBot 类中:
handleWhaleBuy = async (whalePubkey, tokenMint, lamportsSpent, copiedTxid) => {
if (lamportsSpent < this.config.MIN_TX_AMOUNT) return;
try {
const inAmount = this.config.BUY_AMOUNT;
const response = await this.fetchSwapTransaction({
wallet: this.wallet.publicKey.toBase58(),
type: "BUY",
mint: tokenMint,
inAmount,
slippageBps: "300",
});
if (!response.tx) {
throw new Error(`意外的响应格式: ${JSON.stringify(response)}`);
}
const { tx } = response;
const signedTransaction = await this.signTransaction(tx);
let txid = '模拟-TxID';
if (!this.config.TEST_MODE) {
txid = await this.sendAndConfirmTransaction(signedTransaction);
}
console.log("🎯 - 复制 - TxID:", txid);
this.logSwap({
event: "COPY_BUY",
txid,
copiedTxid,
tokenMint,
lamportsSpent,
whalePubkey,
timestamp: new Date().toISOString(),
});
} catch (err) {
this.logSwap({
event: "COPY_BUY_ERROR",
error:
typeof err === "string"
? err
: err && typeof err.message === "string"
? err.message
: JSON.stringify(err, null, 2) || "未知错误",
copiedTxid,
timestamp: new Date().toISOString(),
});
}
};
让我们查看此方法的关键组件:
lamportsSpent
:目标钱包在原始交易中花费的总 SOL。这必须超过 MIN_TX_AMOUNT
,我们才会去复制该交易。你当然可以在这里实现自己的逻辑。inAmount
:我们机器人将花费多少 SOL 来复制交易。它设置为我们配置中的 BUY_AMOUNT
。fetchSwapTransaction()
:我们请求 Pump.fun 进行我们的购买交易的交易。signTransaction()
:使用我们的钱包对其进行签名。sendAndConfirmTransaction()
:将签名后的交易发送到 Solana 网络并等待确认。(如果启用 TEST_MODE
则跳过)logSwap()
:将复制交易尝试记录在日志文件中。现在我们已经在执行方法中处理完了交易,那么我们需要设置一个 Yellowstone 订阅,以便监控目标钱包在 Pump.fun 上的购买交易。Yellowstone 将允许我们监听符合特定条件的交易,然后我们可以解析交易指令数据,以确保我们做出适当的响应。
我们需要告诉 Yellowstone 我们关心监测哪些地址或程序。让我们在 CopyTradeBot 类中添加几个方法:
createSubscribeRequest = () => {
const { WATCH_LIST, PUMP_FUN, COMMITMENT } = this.config;
return {
accounts: {},
slots: {},
transactions: {
pumpFun: {
accountInclude: WATCH_LIST,
accountExclude: [],
accountRequired: [PUMP_FUN.FEE_ACCOUNT, PUMP_FUN.PROGRAM_ID],
},
},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
commitment: COMMITMENT,
accountsDataSlice: [],
ping: undefined,
};
};
sendSubscribeRequest = (stream, request) => {
return new Promise((resolve, reject) => {
stream.write(request, (err) => {
if (err) reject(err);
else resolve();
});
});
};
handleStreamEvents = (stream) => {
return new Promise((resolve, reject) => {
stream.on("data", this.handleData);
stream.on("error", (error) => {
console.error("流错误:", error);
reject(error);
stream.end();
});
stream.on("end", () => {
console.log("流结束");
resolve();
});
stream.on("close", () => {
console.log("流关闭");
resolve();
});
});
};
在这里我们定义了三个函数:
createSubscribeRequest()
:构建带有我们关心的账户/过滤器的订阅请求对象。accountsRequired
将确保我们只看到涉及 Pump.fun 的费用账户和程序 ID 的交易——费用账户帮助我们标识 Pump.fun 交易与程序上的其他类型的交易。accountInclude
过滤器确保我们只看到来自 WATCH_LIST
钱包的交易(你可以将它们视为“或者”连接,因此只要一笔交易包含这些账户中的任何一笔,就会被显示)。sendSubscribeRequest()
:将订阅发送到网络。handleStreamEvents()
:勾勒出我们将如何处理传入的数据、错误和流关闭。重要的是,在此,我们接收到新数据时调用 this.handleData
。换句话说,当 Yellowstone 返回符合我们过滤条件的交易时,我们将使用 handleData()
方法处理它。handleData()
方法是我们解析 Pump.fun 交易详细信息的地方。这对于我们的用例极为重要,因为这是我们将确定发生了哪种类型的交易(例如购买或出售)以及交易规模的地方。将以下方法添加到你的机器人类中,我们将对此进行详细讲解:
handleData = (data) => {
if (
!this.isSubscribeUpdateTransaction(data) ||
!data.filters.includes("pumpFun")
) {
return;
}
const transaction = data.transaction?.transaction;
const message = transaction?.transaction?.message;
const innerInstructions = transaction?.meta?.innerInstructions;
const flattenedInnerInstructions =
innerInstructions?.flatMap((ix) => ix.instructions || []) || [];
const allInstructions = [\
...message.instructions,\
...flattenedInnerInstructions,\
];
if (!transaction || !message || transaction?.meta?.err) return;
const formattedSignature = this.convertSignature(transaction.signature);
const matching = allInstructions.find(this.matchesInstructionDiscriminator);
if (!matching) {
console.log(`❓ - 未知 - TxID: ${formattedSignature.base58}`);
return;
}
const { amount, solAmount } = this.getInstructionData(matching.data);
if (solAmount < this.config.MIN_TX_AMOUNT) return;
const txType = this.getTransactionType(matching.data);
const icon = txType === "SELL" ? "📉" : txType === "BUY" ? "🎯" : "❓";
console.log(`${icon} - ${txType} - TxID: ${formattedSignature.base58}`);
const accountKeys = message.accountKeys;
const accountsToInclude = this.config.PUMP_FUN.TARGET_ACCOUNTS[txType];
const includedAccounts = accountsToInclude.reduce((acc, { name, index }) => {
const accountIndex = matching.accounts[index];
const publicKey = accountKeys[accountIndex];
acc[name] = new PublicKey(publicKey).toBase58();
return acc;
}, {});
if (includedAccounts.mint) {
console.log(" Mint:", includedAccounts.mint);
}
if (includedAccounts.user) {
console.log(" User:", includedAccounts.user);
}
console.log(
" 代币数量:",
amount / Math.pow(10, this.config.PUMP_FUN.TOKEN_DECIMALS)
);
console.log(" SOL 数量:", solAmount / LAMPORTS_PER_SOL);
if (txType === "BUY") {
(async () => {
try {
await this.handleWhaleBuy(
includedAccounts.user,
includedAccounts.mint,
solAmount,
formattedSignature.base58
);
} catch (error) {
console.error("处理(handleWhaleBuy)中的错误:", error);
}
})();
}
};
这里我们做的工作包括:
handleWhaleBuy()
函数,并传递相关交易数据。你将注意到我们在这里使用了一些尚未定义的辅助方法。让我们现在添加这些。将以下剩余的辅助方法添加到你的机器人类中。
isSubscribeUpdateTransaction = (data) => {
return (
"transaction" in data &&
typeof data.transaction === "object" &&
data.transaction !== null &&
"slot" in data.transaction &&
"transaction" in data.transaction
);
};
convertSignature = (signature) => {
return { base58: bs58.encode(Buffer.from(signature)) };
};
parseU64 = (data, offset) => {
const slice = data.slice(offset, offset + 8);
const dataView = new DataView(
slice.buffer,
slice.byteOffset,
slice.byteLength
);
return Number(dataView.getBigUint64(0, true));
};
getInstructionData = (instructionData) => {
const amount = this.parseU64(instructionData, 8);
const solAmount = this.parseU64(instructionData, 16);
return { amount, solAmount };
};
getTransactionType = (instructionData) => {
if (!instructionData) return "Unknown";
if (
this.config.PUMP_FUN.SELL_DISCRIMINATOR.equals(
instructionData.slice(0, 8)
)
) {
return "SELL";
} else if (
this.config.PUMP_FUN.BUY_DISCRIMINATOR.equals(
instructionData.slice(0, 8)
)
) {
return "BUY";
}
return "Unknown";
};
matchesInstructionDiscriminator = (ix) => {
if (!ix?.data) return false;
return (
this.config.PUMP_FUN.SELL_DISCRIMINATOR.equals(ix.data.slice(0, 8)) ||
this.config.PUMP_FUN.BUY_DISCRIMINATOR.equals(ix.data.slice(0, 8))
);
};
让我们解释其中每个的作用:
isSubscribeUpdateTransaction()
:检查传入的数据是否是来自 Yellowstone 的有效交易对象。convertSignature()
:将交易签名转换为 base58 编码字符串,以便更容易进行日志记录。parseU64()
:从指令数据中以给定偏移量解析 64 位无符号整数。这样我们就可以获取像代币数量和 SOL 数量的指令数据。getInstructionData()
:根据程序 IDL 中已知的偏移量从指令数据中提取金额和 SOL 数量。getTransactionType()
:根据指令数据的标志符确定交易是买入还是卖出,这些标志符包含在我们的配置中(来自程序 IDL 的已知值)。matchesInstructionDiscriminator()
:检查指令是否匹配买入或卖出的标志符。最后,让我们创建一个方法来初始化我们的 Yellowstone 实例,以及一个方法来启动我们的机器人。将以下方法添加到你的 CopyTradeBot 类中:
monitorWhales = async () => {
console.log("监控鲸鱼...");
const client = new Client(
process.env.YELLOWSTONE_ENDPOINT,
process.env.YELLOWSTONE_TOKEN,
{}
);
const stream = await client.subscribe();
const request = this.createSubscribeRequest();
try {
await this.sendSubscribeRequest(stream, request);
console.log(
"Geyser 连接已建立 - 正在监视鲸鱼 Pump.fun 活动。"
);
await this.handleStreamEvents(stream);
} catch (error) {
console.error("订阅过程中的错误:", error);
stream.end();
}
};
start = async () => {
console.log("🤖 Pump.fun 复制交易机器人正在启动...");
this.monitorWhales();
};
这些方法做的事情如下:
monitorWhales()
:使用你在 .env
中配置的端点和Token建立一个 Yellowstone 客户端。然后创建我们关心的 Pump.fun 交易的订阅,并监听传入数据。最终流式传输数据将传递给 handleStreamEvents
进行处理。start()
:通过调用 monitorWhales()
启动机器人。这是我们的机器人的入口点。让我们在 bot.js
文件中添加一行最后的代码,以便运行脚本时启动我们的机器人。在 CopyTradeBot
类外部添加以下主函数:
async function main() {
const bot = new CopyTradeBot();
await bot.start();
}
main().catch(console.error);
就是这样!如果你遇到任何问题,你可以在我们的 GitHub 示例库中查看此项目的完整代码, 在这里。让我们测试一下吧!
此时,你的 bot.js
文件包含监控目标钱包或钱包(WATCH_LIST
)并在 SOL 数量超过 MIN_TX_AMOUNT
时复制其 Pump.fun 购买的完整逻辑。为了演示/测试,请确保你的 WATCH_LIST
只是你控制的单个钱包地址。我们将在下一步中使用此地址复制自己的交易。
请小心真实资金
此示例在主要网上进行,如果将 TEST_MODE
设置为 false
,将执行真实交易。请小心真实资金,并考虑在 本地网络 上测试或使用少量 SOL。链上交易是不可逆的,如果未正确执行,可能会导致资金损失。
.env
文件中的钱包)拥有足够的 SOL 来支付所有兑换费用和交易费用。node bot.js
WATCH_LIST
的相同钱包,访问 Pump.fun 并执行一次购买交易。-你的控制台应打印类似 🎯 - BUY - TxID: ... 的消息
-如果交易被检测到,你应在文件 pump_fun_swaps.json 中看到 COPY_BUY 日志条目。
-如果你以 TEST_MODE
设置为 false
运行机器人,你可以在 Solana Explorer 上查看你的 txid
以获取交易详细信息。
干得好!
恭喜你!你已经构建了一个简单而强大的 Solana 复制交易机器人,使用 Pump.fun API 进行交换和 Yellowstone gRPC 进行实时交易流。这种设置演示了如何订阅链上事件并通过使用 Pump.fun API 获取和发送自己的交换交易来以编程方式做出响应。
随意定制此机器人以实现更高级的策略:- 变量购买金额:而不是固定的 BUY_AMOUNT,你可以跟踪鲸鱼的购买规模与你可用的总 SOL 之间的比例。
感谢你的关注,祝你构建愉快!如果你有任何问题或想探索更多 Solana 和 DeFi 教程,请查看我们的 指南 和 文档。祝你好运,安全交易!
让我们知道你在做什么或是否有任何问题!你可以在 Discord 或 Twitter 与我们联系。
让我们知道 如果你有任何反馈或对新主题的请求。我们很想听到你的声音。
- 原文链接: quicknode.com/guides/sol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!