1
查找程序
Pump.fun根据版本通过两个指令启动令牌:
create 和 create_v2。在筛选之前,通过describeProgram确认确切的名称和账户角色:Request
{ "jsonrpc": "2.0", "id": 1, "method": "describeProgram", "params": [{ "program": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" }] }
2
构建筛选器
筛选程序和两个指令名称。保持
includeCpi 开启——Pump.fun的 create/create_v2 通常是顶级的,但这是一种廉价的保险——且排除失败的事务,因为失败的部署不会生成活的铸造:{
"programs": ["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"],
"instructionNames": ["create", "create_v2"],
"includeFailed": false,
"includeCpi": true
}
3
使用支持重连的客户端连接
部署跟踪器是一个长期运行的过程,因此将断开连接视为例行而非异常:监视初始握手,在安静的筛选器上保持连接,并在关闭时自动重连。
pumpfun-deploys.js
const API_KEY = process.env.HELIUS_API_KEY;
if (!API_KEY) {
console.error("Missing HELIUS_API_KEY.");
process.exit(1);
}
const URL = `wss://<ENDPOINT>/?api-key=${API_KEY}`;
const PUMP_PROGRAM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
const SUBSCRIBE_ID = 1;
const PING_ID = 99;
const SUBSCRIBE_REQUEST = {
jsonrpc: "2.0",
id: SUBSCRIBE_ID,
method: "parsedTransactionSubscribe",
params: [
{
programs: [PUMP_PROGRAM],
instructionNames: ["create", "create_v2"],
includeFailed: false,
includeCpi: true,
},
],
};
const CONNECT_TIMEOUT_MS = 10_000;
const PING_INTERVAL_MS = 30_000; // server closes idle connections after 10 min
const ts = () => new Date().toISOString();
function connect() {
console.log(`[${ts()}] connecting…`);
const ws = new WebSocket(URL);
let pingTimer = null;
// Watchdog: if the handshake never completes, force-close so we retry
// instead of hanging silently in CONNECTING.
const connectTimer = setTimeout(() => {
if (ws.readyState === WebSocket.CONNECTING) {
console.error(`[${ts()}] handshake stalled after ${CONNECT_TIMEOUT_MS}ms — closing`);
ws.close();
}
}, CONNECT_TIMEOUT_MS);
ws.addEventListener("open", () => {
clearTimeout(connectTimer);
console.log(`[${ts()}] connected, subscribing to pump create/create_v2`);
ws.send(JSON.stringify(SUBSCRIBE_REQUEST));
pingTimer = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ jsonrpc: "2.0", id: PING_ID, method: "ping" }));
}
}, PING_INTERVAL_MS);
});
ws.addEventListener("message", (event) => handleMessage(event.data));
ws.addEventListener("error", (err) => {
console.error(`[${ts()}] socket error:`, err.message || err);
});
ws.addEventListener("close", (event) => {
clearTimeout(connectTimer);
if (pingTimer) clearInterval(pingTimer);
console.log(`[${ts()}] closed (code=${event.code}, reason="${event.reason}"). reconnecting in 3s…`);
setTimeout(connect, 3000);
});
}
connect();
为了简单起见,此处使用固定的3秒重连延迟。对于生产监听器,应采用指数回退——详见处理重连。
4
处理通知并记录每个部署
按照因为
id(您自己的请求)或method(服务器推送通知)路由传入消息,然后从解码指令中提取铸造、创建者和元数据:// Pull an account pubkey out of a decoded instruction by its role name.
function accountByRole(decoded, role) {
return decoded?.accounts?.find((a) => a.name === role)?.pubkey ?? null;
}
let deployCount = 0;
function handleDeploy(tx, ix) {
deployCount += 1;
const args = ix.decoded?.args ?? {};
const mint = accountByRole(ix.decoded, "mint");
const creator =
args.creator ??
accountByRole(ix.decoded, "creator") ??
accountByRole(ix.decoded, "user");
console.log(`[${ts()}] pump deploy #${deployCount} (${ix.instructionName})`);
console.log(` mint: ${mint}`);
console.log(` creator: ${creator}`);
console.log(` name: ${args.name ?? "?"}`);
console.log(` symbol: ${args.symbol ?? "?"}`);
console.log(` uri: ${args.uri ?? "?"}`);
console.log(` slot=${tx.slot} sig=${tx.signature}`);
}
function handleMessage(raw) {
let msg;
try {
msg = JSON.parse(raw);
} catch {
console.log(`[${ts()}] non-JSON message:`, raw);
return;
}
if (msg.error) {
console.error(`[${ts()}] error (code=${msg.error.code}): ${msg.error.message}`);
return;
}
if (msg.id === SUBSCRIBE_ID && typeof msg.result === "number") {
console.log(`[${ts()}] subscribed (subscription id=${msg.result})`);
return;
}
if (msg.id === PING_ID) return; // keepalive pong, ignore quietly
if (msg.method === "parsedTransactionNotification") {
const { value } = msg.params.result;
// Default details is "full", so value.instructions is the whole
// transaction; matchedIndexes points at just the create/create_v2
// instructions this filter hit.
for (const i of value.matchedIndexes) handleDeploy(value.transaction, value.instructions[i]);
return;
}
console.log(`[${ts()}] message:`, JSON.stringify(msg, null, 2));
}
includeFailed是false,所以你记录的每个通知都是一个实际部署的令牌。在信任args和accounts之前,请检查ix.decoded是否存在 —— 一个未被识别的Pump.fun程序版本会随着decoded: null抵达,否则将显示为mint: null。下一步
跟踪 Jupiter 交换
更详细地描述程序 → 构建过滤器 → 订阅流程。
处理重连
指数退避和槽间隙回填用于长时间运行的监听器。
获取 Pump.fun 铸造
历史版本:通过解析事件浏览创造者的过去部署。