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

# Pump.fun 토큰 생성 추적하기 - 파싱된 스트림 사용

> Pump.fun의 create 및 create_v2 명령어에 대해 파싱된 스트림을 구독하고, 새로운 토큰 생성, 생성자, 이름, 심볼, URI를 기록하는 연결 안전 리스너를 구축합니다.

이 안내서는 **새로운 모든 Pump.fun 토큰**에 대한 장기 실행 리스너를 구축합니다. 토큰을 시작하는 두 가지 명령어에 필터를 적용하고, 유휴 시간 초과 및 배포 이외의 상황에서도 연결 상태를 유지합니다.

<Steps>
  <Step title="프로그램 조회">
    Pump.fun은 버전에 따라 두 가지 명령어를 통해 토큰을 런칭합니다: `create` 및 `create_v2`. 필터링하기 전에 [`describeProgram`](/docs/ko/parsed-streams/quickstart#디스커버리)에서 정확한 이름과 계정 역할을 확인하세요:

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

    응답의 `instructions` 목록에서 `create` 및 `create_v2`를 확인하고, 필요한 계정 — 일반적으로 새로운 **생성** 주소, 그리고 `creator` 계정 역할 또는 `args`의 `creator` 필드를 확인하세요. 두 명령어 버전은 반드시 동일한 형식을 가지지 않으며, 아래 코드는 하나의 인수 및 두 가지 역할 이름을 확인하는 이유입니다.
  </Step>

  <Step title="필터 구축">
    프로그램과 두 명령어 이름에 필터를 적용하세요. `includeCpi`를 켜두세요 — Pump.fun의 `create`/`create_v2`는 보통 최상위 수준이지만, 이는 저렴한 보호 장치입니다 — 그리고 실패한 트랜잭션을 제외하십시오. 실패한 배포는 결코 실제 생성물을 만들지 않기 때문입니다:

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

  <Step title="재연결 안전 클라이언트로 연결">
    배포 트래커는 장기 실행 프로세스입니다. 따라서 연결 끊김을 특이한 상황이 아닌 일상적인 것으로 취급하세요: 초기 핸드셰이크를 감시하고, 조용한 필터에서 연결을 유지하며, 종료 시 자동으로 재연결합니다.

    ```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://<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();
    ```

    <Tip>
      심플리시티를 위해 고정된 3초 재연결 지연을 사용합니다. 프로덕션 리스너에서는 백오프를 점진적으로 늘리세요 — [Handling Reconnects](/docs/ko/parsed-streams/guides/handling-reconnects)를 참고하세요.
    </Tip>
  </Step>

  <Step title="알림 처리 및 각 배포 로그">
    들어오는 메시지를 `id` (사용자 요청) 또는 `method` (서버 푸시 알림) 경로로 분류하고, 디코딩된 명령어에서 생성, 생성자 및 메타데이터를 가져옵니다:

    ```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.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`이기 때문에, 기록하는 모든 알림은 실제로 배포된 토큰입니다. `ix.decoded`가 존재하는지 확인한 후에만 `args` 및 `accounts`를 신뢰하십시오 — 인식되지 않은 Pump.fun 프로그램 빌드는 `decoded: null`로 도착하며 `mint: null`로 표시됩니다.
  </Step>
</Steps>

## 다음 단계

<CardGroup cols={2}>
  <Card title="Jupiter 스왑 추적" icon="arrow-right-arrow-left" href="/docs/ko/parsed-streams/guides/track-jupiter-swaps">
    describeProgram → 필터 구축 → 구독 흐름에 대한 자세한 설명입니다.
  </Card>

  <Card title="재연결 처리" icon="rotate" href="/docs/ko/parsed-streams/guides/handling-reconnects">
    장기 실행 리스너를 위한 지수 백오프 및 슬롯 간격 백필.
  </Card>

  <Card title="Pump.fun 생성물 가져오기" icon="clock-rotate-left" href="/docs/ko/parsed-events/guides/fetch-pumpfun-mints">
    히스토리 버전: Parsed Events로 생성자의 과거 배포를 페이지로 넘깁니다.
  </Card>
</CardGroup>
