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

# Streaming Data AMM Pump Solana dengan LaserStream

> Skrip LaserStream siap salin-tempel yang melakukan streaming aktivitas akun dan transaksi Pump.fun secara real-time, dengan statistik bergulir dan dekode tanda tangan.

Lakukan streaming setiap pembaruan akun dan transaksi Pump.fun secara real-time menggunakan [SDK LaserStream](/docs/id/laserstream/clients). Halaman ini memandu Anda menjalankan skrip TypeScript lengkap dari awal hingga akhir: skrip mencetak setiap transaksi saat diterima, melaporkan statistik bergulir (throughput, pembayar biaya unik, total biaya dalam SOL) setiap menit, dan tetap terhubung secara otomatis saat terjadi koneksi ulang.

Skrip ini merupakan titik awal yang berguna untuk apa pun yang memerlukan visibilitas Pump.fun secara berkelanjutan — bot perdagangan, dasbor analitik, pipeline peringatan, atau sekadar menjelajahi struktur data agar Anda dapat membangun sesuatu yang lebih khusus di atasnya.

<Info>
  **Prasyarat:** [Kunci API Helius](https://dashboard.helius.dev/) (paket Business atau Professional untuk Mainnet LaserStream) dan Node.js 18+. Pemahaman tentang [Langganan Akun](/docs/id/laserstream/guides/account-subscription) dan [Pemantauan Transaksi](/docs/id/laserstream/guides/transaction-monitoring) akan membantu, tetapi tidak diwajibkan.
</Info>

***

## Penyiapan

Buat proyek baru, instal SDK + `bs58` (digunakan untuk mendekode tanda tangan transaksi), lalu tetapkan kunci API Anda:

```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
```

Pilih endpoint yang paling dekat dengan lokasi tempat skrip ini akan dijalankan — lihat [wilayah LaserStream](/docs/id/laserstream/grpc#endpoint-mainnet).

***

## Skrip

Simpan sebagai `index.ts`, lalu jalankan `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);
```

***

## Fungsi skrip

### Satu langganan, dua blok filter

Satu pemanggilan `subscribe(...)` memuat dua grup filter bernama:

* Filter **`accounts`** menerima setiap akun yang dimiliki oleh program Pump.fun (bonding curve, status mint, dan sebagainya) setiap kali datanya berubah.
* Filter **`transactions`** menerima setiap transaksi yang berinteraksi dengan program Pump.fun. Flag `vote: false, failed: false` membuang vote dan transaksi yang gagal sebelum mencapai handler Anda.

Keduanya diterima melalui satu stream gRPC, sehingga SDK hanya perlu mengelola satu koneksi. Jika koneksi terputus, SDK akan terhubung kembali secara otomatis dan Anda tetap menerima pembaruan dari kedua filter.

### Membaca field mentah

Beberapa nilai dalam payload memerlukan sedikit konversi agar mudah digunakan:

* **`tx.signature`** adalah [`Buffer`](https://nodejs.org/api/buffer.html). Proses dengan `bs58.encode(...)` untuk mendapatkan tanda tangan base58 yang akan Anda lihat di explorer atau dalam respons `getTransaction`.
* **`tx.meta.fee`** adalah u64 yang disimpan sebagai string agar nilai di atas `Number.MAX_SAFE_INTEGER` tidak kehilangan presisi di JavaScript. Bungkus dengan `Number(...)` sebelum melakukan operasi aritmetika. Konvensi string-untuk-u64 yang sama juga berlaku untuk beberapa field tingkat blok — lihat [Pemantauan Slot & Blok](/docs/id/laserstream/guides/slot-and-block-monitoring) untuk struktur data lengkapnya.

### Statistik bergulir

`setInterval` mencetak snapshot setiap 60 detik: total transaksi, transaksi berhasil dibandingkan dengan transaksi gagal, throughput, pembayar biaya unik, dan total biaya dalam SOL. Tekan `Ctrl+C` untuk mendapatkan satu snapshot terakhir sebelum skrip berhenti.

***

## Memperluas skrip

Beberapa cara untuk mengembangkan skrip ini lebih lanjut:

* **Dekode diskriminator instruksi** untuk memberi label perdagangan sebagai `buy` / `sell` / `create` — lihat [Mendekode Data Transaksi](/docs/id/laserstream/guides/decoding-transaction-data) untuk pola parsing.
* **Simpan secara persisten** statistik bergulir ke database (Postgres, Redis, ClickHouse), bukan di `Set` / penghitung dalam memori.
* **Kirim peringatan** saat ambang batas tercapai — pembayar biaya besar, lonjakan volume mendadak, atau akun bonding curve baru.
* **Putar ulang** aktivitas yang terlewat saat memulai dengan menetapkan `fromSlot` pada `SubscribeRequest` (hingga 48 jam ke belakang — lihat [Pemutaran Ulang Historis](/docs/id/laserstream/historical-replay)).
* **Gabungkan** dengan [Pemantauan Slot & Blok](/docs/id/laserstream/guides/slot-and-block-monitoring) untuk mendapatkan konteks tingkat blok.
* **Ikuti satu token** alih-alih seluruh program: masukkan mint ke `accountInclude` dan tetapkan `matchMints: true` pada filter transaksi untuk menerima setiap transfer, swap, mint, dan burn bagi token tersebut (lihat [Pemfilteran Mint Token](/docs/id/laserstream/mint-filtering)).

***

## Langkah Berikutnya

<CardGroup cols={2}>
  <Card title="Transaction Monitoring" icon="receipt" href="/docs/id/laserstream/guides/transaction-monitoring">
    Pola umum pemfilteran transaksi yang digunakan skrip ini.
  </Card>

  <Card title="Decoding Transaction Data" icon="binary" href="/docs/id/laserstream/guides/decoding-transaction-data">
    Uraikan payload transaksi biner menjadi transaksi Solana yang mudah dibaca.
  </Card>

  <Card title="Account Subscriptions" icon="user" href="/docs/id/laserstream/guides/account-subscription">
    Pantau perubahan status akun tertentu dengan filter.
  </Card>

  <Card title="Historical Replay" icon="clock-rotate-left" href="/docs/id/laserstream/historical-replay">
    Putar ulang hingga 24 jam aktivitas Pump.fun sebelumnya dari slot awal.
  </Card>
</CardGroup>
