跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

什么是transactionSubscribe?

transactionSubscribe WebSocket方法(为标准Solana WebSocket API的Helius扩展)支持实时交易事件。 要使用它,请提供TransactionSubscribeFilter,且可选地包含TransactionSubscribeOptions进行进一步定制。
transactionSubscribe位于与标准Solana订阅方法相同的统一wss://mainnet.helius-rpc.comwss://devnet.helius-rpc.com 端点上。

TransactionSubscribeFilter

  • vote:布尔标志,用于包含/排除与投票相关的交易
  • failed:布尔标志,用于包含/排除失败的交易
  • signature:根据特定交易的签名过滤更新
  • accountInclude:您想接收交易更新的账户列表。交易更新中至少包含一个账户(例如,账户1或2)。
  • accountExclude:您想从交易更新中排除的账户列表
  • accountRequired:交易必须包含所有指定的账户才能被纳入更新(例如,账户1和2)
您可以在accountInclude, accountExcludeaccountRequired数组中包含最多50,000个地址。

TransactionSubscribeOptions(可选)

  • commitment:获取数据的承诺级别(processed, confirmedfinalized
  • encoding:返回数据的编码格式(base58, base64jsonParsed
  • transactionDetails:返回数据的详细级别(full, signatures, accountsnone
  • showRewards:布尔标志,指示是否应在更新中包含奖励数据
  • maxSupportedTransactionVersion:指定您想接收更新的最高版本交易。要获取遗留和v0交易,请将值设置为0
maxSupportedTransactionVersion 是必需的,用于返回给定交易的账户和完整级别详细信息(即,transactionDetails: "accounts" | "full")。

交易订阅示例

在此示例中,我们订阅包含 Raydium 账户 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 的交易。 当发生包含 675k...1Mp8 账户的交易,并出现在交易的 accountKeys 中时,我们将收到一个 WSS 通知。 根据订阅选项,交易通知将在 processed 承诺级别,jsonParsed 编码,full 交易详情下发送,并会显示奖励。
const WebSocket = require('ws');

// Create a WebSocket connection
const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=<API_KEY>');

// Function to send a request to the WebSocket server
function sendRequest(ws) {
    const request = {
        jsonrpc: "2.0",
        id: 420,
        method: "transactionSubscribe",
        params: [
            {
                accountInclude: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"]
            },
            {
                commitment: "processed",
                encoding: "jsonParsed",
                transactionDetails: "full",
                showRewards: true,
                maxSupportedTransactionVersion: 0
            }
        ]
    };
    ws.send(JSON.stringify(request));
}

// Function to send a ping to the WebSocket server
function startPing(ws) {
    setInterval(() => {
        if (ws.readyState === WebSocket.OPEN) {
            ws.ping();
            console.log('Ping sent');
        }
    }, 30000); // Ping every 30 seconds
}

// Define WebSocket event handlers

ws.on('open', function open() {
    console.log('WebSocket is open');
    sendRequest(ws);  // Send a request once the WebSocket is open
    startPing(ws);    // Start sending pings
});

ws.on('message', function incoming(data) {
    const messageStr = data.toString('utf8');
    try {
        const messageObj = JSON.parse(messageStr);
        console.log('Received:', messageObj);
    } catch (e) {
        console.error('Failed to parse JSON:', e);
    }
});

ws.on('error', function error(err) {
    console.error('WebSocket error:', err);
});

ws.on('close', function close() {
    console.log('WebSocket is closed');
});

示例通知

{
    "jsonrpc": "2.0",
    "method": "transactionNotification",
    "params": {
        "subscription": 4743323479349712,
        "result": {
            "transaction": {
                "transaction": [
                    "Ae6zfSExLsJ/E1+q0jI+3ueAtSoW+6HnuDohmuFwagUo2BU4OpkSdUKYNI1dJfMOonWvjaumf4Vv1ghn9f3Avg0BAAEDGycH0OcYRpfnPNuu0DBQxTYPWpmwHdXPjb8y2P200JgK3hGiC2JyC9qjTd2lrug7O4cvSRUVWgwohbbefNgKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0HcpwKokfYDDAJTaF/TWRFWm0Gz5/me17PRnnywHurMBAgIAAQwCAAAAoIYBAAAAAAA=",
                    "base64"
                ],
                "meta": {
                    "err": null,
                    "status": {
                        "Ok": null
                    },
                    "fee": 5000,
                    "preBalances": [
                        28279852264,
                        158122684,
                        1
                    ],
                    "postBalances": [
                        28279747264,
                        158222684,
                        1
                    ],
                    "innerInstructions": [],
                    "logMessages": [
                        "Program 11111111111111111111111111111111 invoke [1]",
                        "Program 11111111111111111111111111111111 success"
                    ],
                    "preTokenBalances": [],
                    "postTokenBalances": [],
                    "rewards": null,
                    "loadedAddresses": {
                        "writable": [],
                        "readonly": []
                    },
                    "computeUnitsConsumed": 0
                }
            },
            "signature": "5moMXe6VW7L7aQZskcAkKGQ1y19qqUT1teQKBNAAmipzdxdqVLAdG47WrsByFYNJSAGa9TByv15oygnqYvP6Hn2p",
            "slot": 224341380,
            "transactionIndex": 42
        }
    }
}

监控新的 Jupiter DCA

Jupiter DCA,即定期定额投资,是在 Solana 上安排定期交易的一种方式。由于这些定期买卖订单是在链上记录的,交易者可以使用 transactionSubscribe 方法和 getAsset 监听新订单。
const WebSocket = require('ws');   
const bs58      = require('bs58').default;

/* ───────────────────── 1.  CONFIG ──────────────────────────── */
const API_KEY   = process.env.HELIUS_API_KEY || (() => { throw new Error('Set HELIUS_API_KEY'); })();
const HELIUS_WS  = `wss://mainnet.helius-rpc.com?api-key=${API_KEY}`;
const HELIUS_RPC = `https://mainnet.helius-rpc.com/?api-key=${API_KEY}`;
const DCA_PROGRAM_ID = 'DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M';

/* ───────────────────── 2.  BINARY DECODER ──────────────────── */
function decodeOpenDcaV2(base58Data) {
  const buf = Buffer.from(bs58.decode(base58Data));
  return {
    appIdx:    buf.readBigUInt64LE(8), // Application Index
    inAmount:  buf.readBigUInt64LE(16), // Input Amount
    perCycle:  buf.readBigUInt64LE(24), // Per Cycle
    interval:  buf.readBigUInt64LE(32) // Interval
  };
}

const TOKEN_META = new Map();   // mint → { symbol, decimals }
/**
 * Fetch symbol & decimals for a mint once then cache.
 * Uses Helius getAsset DAS method: https://www.helius.dev/docs/api-reference/das/getasset
 */
async function getMeta(mint) {
  if (TOKEN_META.has(mint)) return TOKEN_META.get(mint);

  const body = {
    jsonrpc: '2.0',
    id:      'meow',
    method:  'getAsset',
    params:  { id: mint, displayOptions: { showFungible: true } }
  };

  const { result } = await fetch(HELIUS_RPC, {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify(body)
  }).then(r => r.json());

  const tokenInfo = result.token_info || {};
  const metadata = { symbol: tokenInfo.symbol || '?', decimals: tokenInfo.decimals ?? 0 };
  TOKEN_META.set(mint, metadata);
  return metadata;
}

/* ───────────────────── 4.  PRETTY HELPERS ──────────────────── */
function formatTimestamp(unixSeconds) {
    return new Date(Number(unixSeconds) * 1_000)
             .toISOString()
             .replace('T', ' ')
             .replace('.000Z', ' UTC');
}
function formatInterval(seconds) {
    if (seconds % 86_400 === 0) return `every ${seconds / 86_400}d`;
    if (seconds %  3_600 === 0) return `every ${seconds /  3_600}h`;
    if (seconds %     60 === 0) return `every ${seconds /     60}m`;
    return `every ${seconds}s`;
  }

  function formatAmount(raw, decimals, symbol) {
    const ui = Number(raw) / 10 ** decimals;
    return `${ui} ${symbol}`;
  }
/* ───────────────────── 5.  WEBSOCKET SETUP ─────────────────── */
const ws = new WebSocket(HELIUS_WS);

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id:      1,
    method:  'transactionSubscribe',
    params: [
      { failed: false, accountInclude: [DCA_PROGRAM_ID] },
      {
        commitment: 'confirmed',
        encoding:   'jsonParsed',
        transactionDetails: 'full',
        maxSupportedTransactionVersion: 0
      }
    ]
  }));

  setInterval(() => ws.ping(), 10_000);
});

/* ───────────────────── 6.  MAIN MESSAGE HANDLER ────────────── */
ws.on('message', async raw => {
  const payload = JSON.parse(raw);
  const result  = payload.params?.result;
  if (!result) return;

  // Look for the `OpenDcaV2` log message
  const logs = result.transaction.meta.logMessages || [];
  if (!logs.some(l => l.includes('OpenDcaV2'))) return;

  // loop through all instructions in the transaction to find the DCA instruction
  for (const ix of result.transaction.transaction.message.instructions) {
    if (ix.programId !== DCA_PROGRAM_ID) continue;

    try {
      // 1) decode binary payload
      const d = decodeOpenDcaV2(ix.data);

      // 2) fetch token symbols / decimals (cached)
      const [inMeta, outMeta] = await Promise.all([
        getMeta(ix.accounts[3]),   // input mint
        getMeta(ix.accounts[4])    // output mint
      ]);

      // 3) create a nice looking table
      console.table({
        user:        ix.accounts[2],
        pair:        `${inMeta.symbol}${outMeta.symbol}`,
        opened:      formatTimestamp(d.appIdx),
        'total in':  formatAmount(d.inAmount,  inMeta.decimals, inMeta.symbol),
        'per cycle': formatAmount(d.perCycle,  inMeta.decimals, inMeta.symbol),
        interval:    formatInterval(Number(d.interval))
      });
    } catch (e) {}
  }
});

ws.on('error', console.error);

ws.on('close', () => process.exit(1));

示例通知

监控新的 pump.fun 代币

const WebSocket = require('ws');

const KEY    = process.env.HELIUS_API_KEY ?? (() => { throw new Error('Set HELIUS_API_KEY'); })();
const WS_URL = `wss://mainnet.helius-rpc.com?api-key=${KEY}`;
const PUMP_FUN_PROG = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P';

/* ────────── 2.  OPEN WEBSOCKET & SUBSCRIBE ──────────────────── */
const ws = new WebSocket(WS_URL);

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc : '2.0',
    id      : 1,
    method  : 'transactionSubscribe',
    params  : [
      { failed:false, accountInclude:[PUMP_FUN_PROG] },
      { commitment:'confirmed', encoding:'jsonParsed',
        transactionDetails:'full', maxSupportedTransactionVersion:0 }
    ]
  }));
  // ping every 10 s so we don't get dropped
  setInterval(() => ws.ping(), 10_000);
});

/* ────────── 3.  MESSAGE HANDLER ─────────────────────────────── */
ws.on('message', raw => {
  const payload = JSON.parse(raw);
  const result  = payload.params?.result;
  if (!result) return;

  const logs = result.transaction.meta.logMessages || [];
  // filter for the pump.fun "InitializeMint2" log
  if (!logs.some(l => l.includes('Instruction: InitializeMint2'))) return;

  const sig   = result.signature;    // transaction signature
  const keys  = result.transaction.transaction.message.accountKeys
                             .map(k => k.pubkey);
  //   keys[0] → creator wallet
  //   keys[1] → the new token
  console.table({
    tx:      sig,
    creator: keys[0],
    token:   keys[1]
  });
});

ws.on('error', console.error);
ws.on('close', () => process.exit(1));  

示例通知

管理订阅

订阅 ID

transactionSubscribe 成功时,服务器会在 result 字段返回一个订阅 ID。这是所有来自该订阅的通知中在 params.subscription 中出现的相同号码:
{
  "jsonrpc": "2.0",
  "result": 4743323479349712,
  "id": 420
}
储存响应中的订阅 ID。取消订阅时需要它。

取消订阅

要停止接收通知,请使用订阅 ID 调用 transactionUnsubscribe。每次在同一连接上调用 transactionSubscribe 会创建一个具有自己 ID 的单独订阅,因此请确保在重新订阅之前取消订阅,以避免收到重复通知。
{
  "jsonrpc": "2.0",
  "id": 421,
  "method": "transactionUnsubscribe",
  "params": [4743323479349712]
}
在此示例中,我们订阅 Raydium 交易,从服务器的响应中获取订阅 ID,然后使用该 ID 取消订阅。在调用 transactionUnsubscribe 后,可能仍有一些未完成的消息会短暂到达。这是预期行为。
const WebSocket = require('ws');

const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=<API_KEY>');
let subscriptionId = null;

ws.on('open', () => {
    ws.send(JSON.stringify({
        jsonrpc: '2.0',
        id: 420,
        method: 'transactionSubscribe',
        params: [
            { accountInclude: ['675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'] },
            {
                commitment: 'processed',
                encoding: 'jsonParsed',
                transactionDetails: 'full',
                maxSupportedTransactionVersion: 0,
            },
        ],
    }));
    setInterval(() => ws.ping(), 30000);
});

ws.on('message', (data) => {
    const msg = JSON.parse(data.toString());

    // Capture the subscription ID from the subscribe response
    if (msg.id === 420 && msg.result !== undefined) {
        subscriptionId = msg.result;
        console.log('Subscribed, ID:', subscriptionId);
        return;
    }

    // Handle transaction notifications
    if (msg.method === 'transactionNotification') {
        console.log('Received:', msg.params.result.signature);
    }
});

function unsubscribe() {
    if (subscriptionId !== null) {
        ws.send(JSON.stringify({
            jsonrpc: '2.0',
            id: 421,
            method: 'transactionUnsubscribe',
            params: [subscriptionId],
        }));
        subscriptionId = null;
    }
}