
如何使用 Geyser Enhanced Websockets 监控 Solana 交易
简介
很长一段时间里,我一直想知道这些监控应用和机器人是如何工作的。经过一番艰难的搜索,我发现了 Helius 的 Geyser Enhanced Websockets。虽然它们并非免费(你需要 Business 或 Professional 计划),但却是非常强大的工具。
通过 Helius 使用 Geyser Enhanced Websockets 很简单——粘贴你要监控的地址,然后运行代码即可。你可以监控任何对象:NFT、钱包、程序、平台,真的什么都可以。你可以制作钱包追踪器、代币追踪器、买卖监控器和交易量监控器等工具。
这类 API 和工具有时可能要花费数千美元,但本文将通过几个示例,展示如何用很少的成本实现这些功能。只需 499 美元(Business 计划),自制工具的 ROI 就近乎无限;无论是与他人共享还是自己使用,它都能让你获得优势,并提供无数种处理 Solana 实时数据的方式。
如果你刚开始使用 Helius Geyser Websockets,请阅读这篇博客文章和文档。你可以跟着操作,因为第一个示例相当容易理解。
Raydium 新资金池监控器
const WebSocket = require('ws');
// Create a WebSocket connection
const ws = new WebSocket('wss://atlas-mainnet.helius-rpc.com?api-key=YOUR_API_KEY');
// Function to send a request to the WebSocket server
function sendRequest(ws) {
const request = {
jsonrpc: "2.0",
id: 420,
method: "transactionSubscribe",
params: [
{ failed: false,
accountInclude: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"]
},
{
commitment: "confirmed",
encoding: "jsonParsed",
transactionDetails: "full",
maxSupportedTransactionVersion: 0
}
]
};
ws.send(JSON.stringify(request));
}这段代码的第一部分非常直观。我们设置 API 密钥,并使用要监控的账户发送请求,这里的账户是 675kPX9…,也就是 Raydium 链上程序。通过此请求,我们将获得所有与 Raydium 交互、已确认且未失败的交易。通常,发送此请求每秒会返回数千笔交易,因此我们来重点介绍一种过滤噪声的简单方法。
过滤噪声
下面的代码片段是主要的事件处理和过滤逻辑。on message 函数根据日志解析交易返回的数据。在本例中,我们要查看所有包含“initialize2: InitializeInstruction2”日志的交易——该日志会告诉我们用户何时在 Raydium 上创建了新的流动性池。你也可以根据监控目标使用任何其他日志。我建议针对要监控的操作创建一笔测试交易。例如,你可以向资金池添加流动性,查看该交易的日志内容,然后过滤这些日志,以获得所有添加了流动性的交易。
ws.on('open', function open() {
console.log('WebSocket is open');
sendRequest(ws); // Send a request once the WebSocket is open
});
ws.on('message', async function incoming(data) {
const messageStr = data.toString('utf8');
try {
const messageObj = JSON.parse(messageStr);
const result = messageObj.params.result;
const logs = result.transaction.meta.logMessages;
const signature = result.signature; // Extract the signature
const accountKeys = result.transaction.transaction.message.accountKeys.map(ak => ak.pubkey); // Extract only pubkeys
if (logs && logs.some(log => log.includes("initialize2: InitializeInstruction2"))) {
// Log the signature, and the public keys of the AMM ID
console.log('Transaction signature:', signature);
console.log('AMM ID:', accountKeys[2]); // Corrected to the third account for AMM ID
}
} catch (e) {
}
});
ws.on('error', function error(err) {
console.error('WebSocket error:', err);
});
ws.on('close', function close() {
console.log('WebSocket is closed');
});确认交易包含该日志后,我们会提取两项内容:一是签名,用于比较并验证程序的准确性;二是账户密钥,也就是 AMM ID(即该资金池的 AMM 地址),因为许多机器人和狙击机器人会使用 AMM ID 发起交易。
如果需要,你还可以提取更多数据。例如,你可以获取创建者(通常是 accountKeys 中的第 17 个公钥)、用于创建资金池的代币(可从交易前后的代币余额或内部指令中获取)、代币数量,甚至是创建者收到的 LP 代币。创建者收到的 LP 代币数量可用于制作流动性销毁监控器,因为当资金池创建者销毁其 LP 代币时——这些代币本质上是其资金池份额的凭证——他们便放弃了移除流动性的能力(但要注意,如果铸造权限仍在他们手中,他们仍可铸造更多代币并将其卖入资金池)。
JSON 结构
要获取更多数据,你可以查看交易的 JSON 结构,相关信息可参阅 Solana 官方文档。或者,你也可以保存 JSON 响应,并使用这个格式化工具查看其结构。这一点非常重要,因为一旦了解交易的基本结构,你就可以提取使用区块浏览器时能看到的任何数据。
下面是通用 JSON,其中包含两个重要且深度嵌套的对象:Transaction 和 Meta。在 Transaction 中,有一个 message 对象,其中保存了最近的区块哈希、accountKeys 和 instructions。在 Meta 中,有交易前后的 Balances(lamport 余额)、innerInstructions、logMessages,以及交易前后的 token balances。
Pump.Fun 监控器示例
考虑到 Solana 上当前的 meme 币趋势,我制作了一个非常简单的 pump.fun 监控器。只需将我们监控的地址替换为“6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P”(即 pump.fun 链上程序),然后使用这个 on message 函数:
ws.on('message', function incoming(data) {
const messageStr = data.toString('utf8');
try {
const messageObj = JSON.parse(messageStr);
const result = messageObj.params.result;
const logs = result.transaction.meta.logMessages;
const signature = result.signature; // Extract the signature
const accountKeys = result.transaction.transaction.message.accountKeys.map(ak => ak.pubkey);
if (logs && logs.some(log => log.includes('Program log: Instruction: InitializeMint2'))) {
console.log('New pump.fun token!');
console.log('tx:', signature);
console.log('Creator:', accountKeys[0]);
console.log('Token:', accountKeys[1]);
// Log the first and second account keys if they exist
}
} catch (e) {
}
});与处理 Raydium 的方式类似,我们查看所有与 pump.fun 程序交互的交易,并根据所需日志进行过滤(规律已经很明显了:日志、日志、日志)。获得带有所需日志的交易后,我们会提取签名、创建者以及代币本身!
你可以看到,accountKeys 和签名在 JSON 中的嵌套位置与 Raydium 示例相同,因此可以轻松获取创建者、代币和签名。大多数交易的 JSON 结构基本相同,但某些值的位置或顺序可能有所不同——你将在下一个示例中看到这一点。
总之,这是一个相当简单的 pump.fun 新代币监控器。利用这些信息,你可以购买代币,也可以仅出于监控目的了解它的存在。你还可以将其与不同的 Helius DAS API 结合,打造更强大的工具,例如获取元数据或创建者的相关信息。
Jupiter DCA 监控器
这个示例相对小众,但它展示了如何通过日志查看一切。通过以下请求,我们将查看 Jupiter 的 DCA(定投)程序,更具体地说,是查看通过 Jupiter 完成的每一笔 DCA 买入。这个示例可用于套利交易计算,也可用于分析潜在的市场影响。利用 DCA 买入数据分析潜在市场影响的做法目前远未得到充分应用。
如你所见,到目前为止还没有任何复杂操作。我们在顶部添加了 base58 导入,并将地址改为 Jupiter DCA 程序。接下来的部分可能看起来相当复杂——某种程度上确实如此——但我认为提供一个稍复杂的示例很重要。
const WebSocket = require("ws");
const bs58 = require("bs58");
// Create a WebSocket connection
const ws = new WebSocket(
"wss://atlas-mainnet.helius-rpc.com?api-key=YOUR_API_KEY"
);
// Function to send a request to the WebSocket server
function sendRequest(ws) {
const request = {
jsonrpc: "2.0",
id: 420,
method: "transactionSubscribe",
params: [
{
failed: false,
accountInclude: ["DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M"],
},
{
commitment: "confirmed",
encoding: "jsonParsed",
transactionDetails: "full",
maxSupportedTransactionVersion: 0,
},
],
};
ws.send(JSON.stringify(request));
}这里所做的操作包括:
- 使用 DCA 日志,仅过滤出此类交易。
- 从交易中提取
User、Input Mint和Output Mint。 - 获取
Instruction Data Raw,并将字节转换为输入参数,例如用户输入的数量、卖出频率以及每次卖出的数量。
ws.on("message", async function incoming(data) {
const messageStr = data.toString("utf8");
try {
const messageObj = JSON.parse(messageStr);
const instructions = messageObj.params.result.transaction.transaction.message.instructions;
const result = messageObj.params.result;
const logs = result.transaction.meta.logMessages;
// Extract only pubkeys
if (
logs &&
logs.some((log) => log.includes("Program log: Instruction: OpenDcaV2"))
) {
instructions.forEach((instruction) => {
if (instruction.programId.includes("DCA265")) {
if (instruction.accounts.length === 13) {
console.log("User:", instruction.accounts[2]);
console.log("Input Mint:", instruction.accounts[3]);
console.log("Output Mint:", instruction.accounts[4]);
const data = instruction.data;
const bytedata = bs58.decode(data);
const hexString = bytedata.toString("hex");
const inAmountbytes = hexString.substring(16 * 2, 24 * 2);
const cycleFrequencyBytes = hexString.substring(32 * 2, (32 + 8) * 2);
const inAmountPerCycleBytes = hexString.substring(24 * 2, 32 * 2);
// Reverse the byte order for little-endian interpretation
const reversedCycleFrequencyBytes = cycleFrequencyBytes
.match(/.{1,2}/g)
.reverse()
.join("");
const reversedInAmountBytes = inAmountbytes
.match(/.{1,2}/g)
.reverse()
.join("");
const reversedInAmountPerCycleBytes = inAmountPerCycleBytes
.match(/.{1,2}/g)
.reverse()
.join("");
const cycleFrequency = BigInt("0x" + reversedCycleFrequencyBytes);
const inAmount = BigInt("0x" + reversedInAmountBytes);
const inAmountPerCycle = BigInt("0x" + reversedInAmountPerCycleBytes);
console.log("Cycle Frequency every", cycleFrequency.toString() + " seconds");
console.log("Amount input:", inAmount.toString());
console.log("Amount per cycle:", inAmountPerCycle.toString());
}
}
});
}
} catch (e) {}
});*解密原始指令数据
你看到的原始指令数据通常与输入参数相对应。通过这种方式获取数据并不困难,而且我们不需要进行任何反序列化——这通常会让很多人望而却步。
例如,我们来看看这笔交易中的数据:
8e772b6da2340bb12e783a66000000006d9415754e00000037ca8a3a270000003c00000000000000010000000000000000010000000000000000010000000000000000
现在,打开 hexed.it 并粘贴这些数据:
现在,我们来查找这些输入参数:
在右侧的搜索框中输入 336971797613。点击“查找下一个”,即可看到 inAmount 值在字节中的位置。
如你所见,它表明从 6D 开始,到 37 之前最后一个 00 为止的字节保存着 inAmount 的值。我们监控的这种格式的每笔 DCA 交易中,inAmount 都位于相同的字节位置。接下来的 8 个字节对保存着 inAmountPerCycle 的值。这是一种很巧妙的方法,可用于查找交易 JSON 中通常不明确的值,因为 JSON 主要包含地址和余额,而不是输入参数。
你做到了!
如果你坚持读到了这里,现在应该已经打下了使用 Helius Geyser WebSockets 的扎实基础。最难的部分是迈出第一步。现在,你可以监控钱包、程序、资金池,以及任何你想监控的对象。无需使用价格高得离谱的 API 或类似工具。如果遇到任何问题或有任何疑问,你随时可以在 Helius Discord 中提问!
资源
相关文章
订阅 Helius
及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新


