> ## 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 スクリプト。ロール統計と署名デコード付き。

[LaserStream SDK](/ja/laserstream/clients) を使用して、すべての Pump.fun アカウントの更新とトランザクションをリアルタイムでストリームします。このページでは、エンドツーエンドで実行できる完全な TypeScript スクリプトを説明します：各トランザクションが着地するたびに印刷し、1分ごとにロール統計（スループット、ユニークな手数料支払者、SOLでの総手数料）を報告し、再接続を自動で保持します。

これは、取引ボット、分析ダッシュボード、アラートパイプラインのような Pump.fun の継続的な可視性を必要とするものの有用な出発点です。データの形を探求し、その上に何か特化されたものを構築することもできます。

<Info>
  **前提条件：** [Helius API key](https://dashboard.helius.dev/) （Mainnet LaserStream 用のビジネスまたはプロフェッショナルプラン）と Node.js 18+。[アカウントサブスクリプション](/ja/laserstream/guides/account-subscription) と [トランザクションモニタリング](/ja/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 地域](/ja/laserstream/grpc#mainnet-endpoints)を参照してください。

***

## スクリプト

これを `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 が文字列として格納されており、JavaScriptでの計算における精度の損失を防ぐために`Number.MAX_SAFE_INTEGER` より大きな値を保持します。計算を行う前に `Number(...)` でこれをラップします。同じ文字列-対-u64 の規則は、複数のブロックレベルのフィールドにも適用されます — 完全なデータ形状については [スロット & ブロックモニタリング](/ja/laserstream/guides/slot-and-block-monitoring) を参照してください。

### ロール統計

`setInterval` は、60秒ごとにスナップショットを印刷します：総取引、成功と失敗の比率、スループット、ユニークな手数料支払者、SOLでの総手数料。スクリプト終了前に最後のスナップショットを取得するには、`Ctrl+C` を押します。

***

## スクリプトの拡張

さらに進めるための方向性：

* **インストラクション識別子をデコード** して取引を `buy` / `sell` / `create` としてラベル付けする — 分析パターンについては [トランザクションデータのデコード](/ja/laserstream/guides/decoding-transaction-data) を参照してください。
* **ロール統計をデータベースに永続化** する（Postgres, Redis, ClickHouse）インメモリの `Set` / カウンターの代わりに使用します。
* **しきい値に達した際にアラート** を設定する — 大規模な手数料支払者、突然のボリュームスパイク、新しいボンディングカーブアカウント。
* **起動時に見逃した活動を再生** するには、`SubscribeRequest` に `fromSlot` を設定します（過去24時間まで — [履歴再生](/ja/laserstream/historical-replay) を参照）。
* **スロット & ブロックモニタリングと組み合わせて** ブロックレベルでのコンテキストを追加します。

***

## 次のステップ

<CardGroup cols={2}>
  <Card title="トランザクションモニタリング" icon="receipt" href="/ja/laserstream/guides/transaction-monitoring">
    このスクリプトが使用する一般的なトランザクションフィルタリングパターン。
  </Card>

  <Card title="トランザクションデータのデコード" icon="binary" href="/ja/laserstream/guides/decoding-transaction-data">
    バイナリトランザクションペイロードを読みやすい Solana トランザクションに解析します。
  </Card>

  <Card title="アカウントサブスクリプション" icon="user" href="/ja/laserstream/guides/account-subscription">
    特定のアカウント状態の変更をフィルターで監視します。
  </Card>

  <Card title="履歴再生" icon="clock-rotate-left" href="/ja/laserstream/historical-replay">
    開始スロットから過去24時間の Pump.fun アクティビティを再生します。
  </Card>
</CardGroup>
