> ## 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.

# Theo dõi hoạt động mint token Pump.fun bằng Parsed Streams

> Đăng ký nhận các chỉ thị create của Pump.fun bằng Helius Parsed Streams và xây dựng một trình lắng nghe Solana có khả năng kết nối lại an toàn để ghi nhật ký mọi token mint mới cùng người tạo.

Hướng dẫn này xây dựng một trình lắng nghe chạy dài hạn cho **mọi token Pump.fun mới**. Trình lắng nghe lọc theo hai chỉ thị mà Pump.fun dùng để ra mắt token và duy trì kết nối khi hết thời gian chờ do không hoạt động cũng như trong quá trình triển khai.

<Steps>
  <Step title="Look Up the Program">
    Pump.fun ra mắt token thông qua hai chỉ thị tùy theo phiên bản: `create` và `create_v2`. Hãy xác nhận chính xác tên và vai trò tài khoản bằng [`describeProgram`](/docs/vi/parsed-streams/quickstart#khám-phá) trước khi lọc theo chúng. Tính năng này hiện chỉ có trên `wss://fs-beta.helius-rpc.com/?api-key=<API_KEY>`:

    ```json Request theme={"system"}
    { "jsonrpc": "2.0", "id": 1, "method": "describeProgram", "params": [{ "program": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" }] }
    ```

    Kiểm tra danh sách `instructions` trong phản hồi để tìm `create` và `create_v2`, đồng thời kiểm tra danh sách `roles` để tìm tài khoản bạn cần — thường là địa chỉ **mint** mới và vai trò tài khoản `creator` hoặc trường `creator` trong `args`. Hai phiên bản chỉ thị không nhất thiết có cùng cấu trúc, vì vậy mã bên dưới kiểm tra cả một đối số và một vài tên vai trò thay vì giả định chỉ có một cấu trúc.
  </Step>

  <Step title="Build the Filter">
    Lọc theo chương trình và cả hai tên chỉ thị. Hãy giữ `includeCpi` ở trạng thái bật — `create`/`create_v2` của Pump.fun thường nằm ở cấp cao nhất, nhưng đây là biện pháp dự phòng ít tốn kém — và loại trừ các giao dịch thất bại vì một lần triển khai thất bại sẽ không bao giờ tạo ra mint hoạt động:

    ```json theme={"system"}
    {
      "programs": ["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"],
      "instructionNames": ["create", "create_v2"],
      "includeFailed": false,
      "includeCpi": true
    }
    ```
  </Step>

  <Step title="Connect with a Reconnect-Safe Client">
    Trình theo dõi triển khai là một tiến trình chạy dài hạn, vì vậy hãy coi việc mất kết nối là tình huống thông thường thay vì ngoại lệ: giám sát quá trình bắt tay ban đầu, duy trì kết nối khi bộ lọc không có hoạt động và tự động kết nối lại khi kết nối đóng.

    ```javascript pumpfun-deploys.js theme={"system"}
    const API_KEY = process.env.HELIUS_API_KEY;

    if (!API_KEY) {
      console.error("Missing HELIUS_API_KEY.");
      process.exit(1);
    }

    const URL = `wss://beta.helius-rpc.com/?api-key=${API_KEY}`;
    const PUMP_PROGRAM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";

    const SUBSCRIBE_ID = 1;
    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 ts = () => new Date().toISOString();

    function connect() {
      console.log(`[${ts()}] connecting…`);
      const ws = new WebSocket(URL);

      // 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));
      });

      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);
        console.log(`[${ts()}] closed (code=${event.code}, reason="${event.reason}"). reconnecting in 3s…`);
        setTimeout(connect, 3000);
      });
    }

    connect();
    ```

    <Tip>
      Để đơn giản, ví dụ này sử dụng độ trễ kết nối lại cố định là 3 giây. Với trình lắng nghe dùng trong môi trường production, hãy dùng chiến lược thời gian chờ tăng theo cấp số nhân — xem [Xử lý kết nối lại](/docs/vi/parsed-streams/guides/handling-reconnects).
    </Tip>
  </Step>

  <Step title="Handle Notifications and Log Each Deploy">
    Định tuyến thông báo đến theo `id` (các yêu cầu của chính bạn) hoặc `method` (thông báo do máy chủ đẩy), sau đó lấy mint, người tạo và siêu dữ liệu từ chỉ thị đã giải mã:

    ```javascript theme={"system"}
    // 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.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));
    }
    ```

    Vì `includeFailed` là `false`, mọi thông báo được ghi nhật ký đều là token đã thực sự được triển khai. Hãy kiểm tra `ix.decoded` có tồn tại trước khi tin cậy `args` và `accounts` — một bản dựng không được nhận dạng của chương trình Pump.fun sẽ có `decoded: null` và nếu không kiểm tra, nó sẽ hiển thị dưới dạng `mint: null`.
  </Step>
</Steps>

## Các bước tiếp theo

<CardGroup cols={2}>
  <Card title="Track Jupiter Swaps" icon="arrow-right-arrow-left" href="/docs/vi/parsed-streams/guides/track-jupiter-swaps">
    Quy trình describeProgram → tạo bộ lọc → đăng ký được trình bày chi tiết hơn.
  </Card>

  <Card title="Handling Reconnects" icon="rotate" href="/docs/vi/parsed-streams/guides/handling-reconnects">
    Chiến lược thời gian chờ tăng theo cấp số nhân và backfill khoảng trống slot dành cho các trình lắng nghe chạy dài hạn.
  </Card>

  <Card title="Fetch Pump.fun Mints" icon="clock-rotate-left" href="/docs/vi/parsed-events/guides/fetch-pumpfun-mints">
    Phiên bản lịch sử: phân trang qua các lần triển khai trước đây của một người tạo bằng Parsed Events.
  </Card>
</CardGroup>
