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

# Solana Pump AMM 데이터 스트리밍 with LaserStream

> Pump.fun 계정 및 트랜잭션 활동을 실시간으로 스트리밍하는 레이저스트림 스크립트로, 롤링 통계와 서명 디코딩 포함.

[LaserStream SDK](/docs/ko/laserstream/clients)를 사용하여 모든 Pump.fun 계정 업데이트 및 트랜잭션을 실시간으로 스트리밍하세요. 이 페이지에서는 시작부터 끝까지 실행할 수 있는 완전한 TypeScript 스크립트를 안내합니다: 각 트랜잭션이 도착할 때마다 출력하고, 매 분 롤링 통계(처리량, 고유 수수료 지불자, SOL로 총 수수료)를 보고하며, 자동으로 재연결합니다.

연속적인 Pump.fun 가시성이 필요한 모든 것에 유용한 시작점입니다 — 트레이딩 봇, 분석 대시보드, 알림 파이프라인 또는 상위에 더 전문적인 무언가를 구축할 수 있도록 데이터 형식을 탐색하는 것.

<Info>
  **전제 조건:** [Helius API 키](https://dashboard.helius.dev/) (Mainnet LaserStream을 위한 Business 또는 Professional 플랜) 및 Node.js 18+. [Account Subscriptions](/docs/ko/laserstream/guides/account-subscription) 및 [Transaction Monitoring](/docs/ko/laserstream/guides/transaction-monitoring)에 대한 이해가 도움이 되지만 필수는 아닙니다.
</Info>

***

## 설정

새로운 프로젝트를 만들고 SDK + `bs58` (트랜잭션 서명을 디코딩하는 데 사용)을 설치하고 API 키를 설정하세요:

```bash theme={"system"}
mkdir pump-monitor && cd pump-monitor
npm init -y
npm install helius-laserstream bs58
npm install --save-dev typescript ts-node @types/node
npx tsc --init
export HELIUS_API_KEY=your-key-here
```

이 스크립트가 실행될 위치에 가장 가까운 엔드포인트를 선택하세요 — [LaserStream 지역](/docs/ko/laserstream/grpc#메인넷-엔드포인트)을 참조하세요.

***

## 스크립트

이를 `index.ts`로 저장한 다음 `npx ts-node index.ts`를 실행하세요:

```typescript [expandable] theme={"system"}
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';
import bs58 from 'bs58';

const PUMP_PROGRAM_ID = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P';

// Rolling stats across the session.
const stats = {
  startedAt: Date.now(),
  transactions: 0,
  successes: 0,
  failures: 0,
  uniquePayers: new Set<string>(),
  totalFeesLamports: 0,
  accountUpdates: 0,
};

async function handleUpdate(data: any) {
  if (data.transaction) {
    const tx = data.transaction.transaction;
    if (!tx) return;

    stats.transactions++;
    const failed = !!tx.meta?.err;
    failed ? stats.failures++ : stats.successes++;

    // tx.meta.fee is a u64 string — coerce before adding.
    stats.totalFeesLamports += Number(tx.meta?.fee ?? 0);

    // Fee payer is the first account in the message.
    const firstKey = tx.transaction?.message?.accountKeys?.[0];
    if (firstKey) {
      const payer = typeof firstKey === 'string' ? firstKey : bs58.encode(firstKey);
      stats.uniquePayers.add(payer);
    }

    // tx.signature is a Buffer in the SDK.
    const sig = bs58.encode(tx.signature);
    const slot = data.transaction.slot;
    const flag = failed ? '❌' : '✅';
    console.log(`${flag}  ${sig.slice(0, 12)}…  slot ${slot}  fee ${tx.meta?.fee} lamports`);
  }

  if (data.account) {
    stats.accountUpdates++;
    const acct = data.account.account;
    const pubkey = typeof acct.pubkey === 'string' ? acct.pubkey : bs58.encode(acct.pubkey);
    console.log(`📋  account ${pubkey}  ${acct.data?.length ?? 0} bytes`);
  }
}

function printReport() {
  const minutes = (Date.now() - stats.startedAt) / 60_000;
  console.log('\n📊  Pump.fun activity report');
  console.log(`   Runtime:           ${minutes.toFixed(1)} min`);
  console.log(`   Transactions:      ${stats.transactions} (${stats.successes} ok, ${stats.failures} failed)`);
  console.log(`   Throughput:        ${(stats.transactions / Math.max(minutes, 0.0001)).toFixed(1)} tx/min`);
  console.log(`   Unique fee payers: ${stats.uniquePayers.size}`);
  console.log(`   Total fees:        ${(stats.totalFeesLamports / 1e9).toFixed(4)} SOL`);
  console.log(`   Account updates:   ${stats.accountUpdates}\n`);
}

async function main() {
  const config: LaserstreamConfig = {
    apiKey: process.env.HELIUS_API_KEY ?? 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // pick the region closest to you
  };

  const subscriptionRequest: SubscribeRequest = {
    accounts: {
      'pump-accounts': {
        account: [],
        owner: [PUMP_PROGRAM_ID],
        filters: [],
      },
    },
    transactions: {
      'pump-transactions': {
        accountInclude: [PUMP_PROGRAM_ID],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false,
      },
    },
    commitment: CommitmentLevel.CONFIRMED,
    slots: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    accountsDataSlice: [],
  };

  console.log('🚀  Streaming Pump.fun activity. Press Ctrl+C to stop.\n');

  const reportTimer = setInterval(printReport, 60_000);
  process.on('SIGINT', () => {
    clearInterval(reportTimer);
    printReport();
    process.exit(0);
  });

  await subscribe(config, subscriptionRequest, handleUpdate, async (error) => {
    console.error('Stream error:', error);
  });
}

main().catch(console.error);
```

***

## 스크립트가 하는 일

### 하나의 구독, 두 개의 필터 블록

단일 `subscribe(...)` 호출은 두 개의 이름 있는 필터 그룹을 포함합니다:

* **`accounts`** 필터는 데이터가 변경될 때마다 Pump.fun 프로그램(본딩 곡선, 민트 상태 등)이 소유한 모든 계정을 수신합니다.
* **`transactions`** 필터는 Pump.fun 프로그램과 상호 작용하는 모든 트랜잭션을 수신합니다. `vote: false, failed: false` 플래그는 투표와 실패한 트랜잭션을 핸들러에 도달하기 전에 삭제합니다.

둘 다 단일 gRPC 스트림을 통해 도착하므로 SDK는 하나의 연결만 관리하면 됩니다. 연결이 끊어지면 SDK는 자동으로 다시 연결하여 두 필터의 업데이트를 계속 수신합니다.

### 원시 필드 읽기

페이로드의 몇 가지 값은 사용하기 전에 약간의 변환이 필요합니다:

* \*\*`tx.signature`\*\*는 [`Buffer`](https://nodejs.org/api/buffer.html)입니다. 이를 `bs58.encode(...)`로 처리하여 탐색기나 `getTransaction` 응답에서 볼 수 있는 base58 서명을 얻으세요.
* \*\*`tx.meta.fee`\*\*는 u64이며 자바스크립트에서 정밀도를 잃지 않도록 문자열로 저장됩니다. 산술을 수행하기 전에 `Number(...)`로 감싸세요. 동일한 문자열-포-u64 관례는 여러 블록 레벨 필드에도 적용됩니다 — 전체 데이터 형식은 [Slot & Block Monitoring](/docs/ko/laserstream/guides/slot-and-block-monitoring)을 참조하세요.

### 롤링 통계

`setInterval`가 60초마다 스냅샷을 출력합니다: 총 트랜잭션, 성공 대 실패, 처리량, 고유 수수료 지불자 및 SOL로 총 수수료. 스크립트 종료 전 마지막 스냅샷을 위해 `Ctrl+C`를 누르세요.

***

## 스크립트 확장

이것을 확장할 몇 가지 방향:

* **명령어 디스크리미네이터 디코드**하여 거래를 `buy` / `sell` / `create`로 라벨링합니다 — 파싱 패턴은 [Decoding Transaction Data](/docs/ko/laserstream/guides/decoding-transaction-data)를 참조하세요.
* **롤링 통계 영구 저장** - 메모리 `Set` / 카운터 대신 데이터베이스(Postgres, Redis, ClickHouse)에 저장합니다.
* **임계값에 경고** - 큰 수수료 지불자, 갑작스러운 볼륨 급증, 새로운 본딩 곡선 계정에 대해 경고합니다.
* **초기 시작 시 누락된 활동 재생** - `SubscribeRequest`에서 `fromSlot`을 설정하여 최대 24시간의 과거 활동을 재생합니다 — [Historical Replay](/docs/ko/laserstream/historical-replay)를 참조하세요.
* **[Slot & Block Monitoring](/docs/ko/laserstream/guides/slot-and-block-monitoring)과 결합**하여 블록 레벨 컨텍스트 확보합니다.

***

## 다음 단계

<CardGroup cols={2}>
  <Card title="트랜잭션 모니터링" icon="receipt" href="/docs/ko/laserstream/guides/transaction-monitoring">
    이 스크립트가 사용한 일반적인 트랜잭션 필터링 패턴입니다.
  </Card>

  <Card title="트랜잭션 데이터 디코딩" icon="binary" href="/docs/ko/laserstream/guides/decoding-transaction-data">
    이진 트랜잭션 페이로드를 읽을 수 있는 Solana 트랜잭션으로 파싱합니다.
  </Card>

  <Card title="계정 구독" icon="user" href="/docs/ko/laserstream/guides/account-subscription">
    필터를 사용하여 특정 계정 상태 변경을 모니터링합니다.
  </Card>

  <Card title="히스토리컬 재생" icon="clock-rotate-left" href="/docs/ko/laserstream/historical-replay">
    시작 슬롯부터 최대 24시간의 과거 Pump.fun 활동을 재생합니다.
  </Card>
</CardGroup>
