> ## 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 de datos de Solana Pump AMM con LaserStream

> Script de LaserStream listo para copiar y pegar que transmite en tiempo real la actividad de cuentas y transacciones de Pump.fun, con estadísticas móviles y decodificación de firmas.

Transmite en tiempo real cada actualización de cuenta y transacción de Pump.fun mediante el [SDK de LaserStream](/docs/es/laserstream/clients). Esta página te guía por un script completo de TypeScript que puedes ejecutar de principio a fin: imprime cada transacción a medida que llega, muestra estadísticas móviles (rendimiento, pagadores de comisiones únicos y comisiones totales en SOL) una vez por minuto y mantiene la conexión automáticamente cuando se producen reconexiones.

Es un punto de partida útil para cualquier aplicación que necesite visibilidad continua de Pump.fun: bots de trading, paneles de análisis, canales de alertas o simplemente explorar la estructura de los datos para crear una solución más especializada.

<Info>
  **Requisitos previos:** Una [clave de API de Helius](https://dashboard.helius.dev/) (plan Business o Professional para LaserStream en Mainnet) y Node.js 18 o posterior. Es útil conocer las [suscripciones de cuentas](/docs/es/laserstream/guides/account-subscription) y el [monitoreo de transacciones](/docs/es/laserstream/guides/transaction-monitoring), pero no es obligatorio.
</Info>

***

## Configuración

Crea un proyecto nuevo, instala el SDK + `bs58` (que se usa para decodificar firmas de transacciones) y configura tu clave de 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
```

Elige el punto de conexión más cercano al lugar donde se ejecutará este script. Consulta las [regiones de LaserStream](/docs/es/laserstream/grpc#endpoints-de-mainnet).

***

## El script

Guárdalo como `index.ts` y ejecuta `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);
```

***

## Qué hace el script

### Una suscripción, dos bloques de filtros

Una sola llamada a `subscribe(...)` contiene dos grupos de filtros con nombre:

* El filtro **`accounts`** recibe todas las cuentas cuyo propietario es el programa Pump.fun (curvas de vinculación, estado de emisión, etc.) cada vez que cambian sus datos.
* El filtro **`transactions`** recibe todas las transacciones que interactúan con el programa Pump.fun. Las marcas `vote: false, failed: false` descartan los votos y las transacciones fallidas antes de que lleguen a tu controlador.

Ambos llegan a través de un único flujo gRPC, por lo que el SDK solo tiene que administrar una conexión. Si se interrumpe, el SDK vuelve a conectarse automáticamente y continúas recibiendo actualizaciones de ambos filtros.

### Lectura de los campos sin procesar

Algunos valores de la carga útil necesitan una pequeña conversión antes de poder usarlos fácilmente:

* **`tx.signature`** es un [`Buffer`](https://nodejs.org/api/buffer.html). Pásalo por `bs58.encode(...)` para obtener la firma base58 que verías en un explorador o en una respuesta de `getTransaction`.
* **`tx.meta.fee`** es un u64 almacenado como cadena para evitar que los valores superiores a `Number.MAX_SAFE_INTEGER` pierdan precisión en JavaScript. Envuélvelo en `Number(...)` antes de realizar operaciones aritméticas. La misma convención de usar cadenas para u64 también se aplica a varios campos de bloques. Consulta [Monitoreo de slots y bloques](/docs/es/laserstream/guides/slot-and-block-monitoring) para ver la estructura de datos completa.

### Estadísticas móviles

Un `setInterval` imprime una instantánea cada 60 segundos: transacciones totales, operaciones exitosas frente a fallidas, rendimiento, pagadores de comisiones únicos y comisiones totales en SOL. Presiona `Ctrl+C` para obtener una última instantánea antes de que finalice el script.

***

## Extensión del script

Estas son algunas formas de llevarlo más lejos:

* **Decodifica los discriminadores de instrucciones** para etiquetar las operaciones como `buy` / `sell` / `create`. Consulta [Decodificación de datos de transacciones](/docs/es/laserstream/guides/decoding-transaction-data) para ver el patrón de análisis.
* **Almacena** las estadísticas móviles en una base de datos (Postgres, Redis, ClickHouse) en lugar de usar `Set` / contadores en memoria.
* **Genera alertas** según ciertos umbrales: pagadores de comisiones grandes, picos repentinos de volumen o nuevas cuentas de curvas de vinculación.
* **Reproduce** la actividad perdida durante el inicio configurando `fromSlot` en `SubscribeRequest` (hasta 24 horas atrás; consulta [Reproducción histórica](/docs/es/laserstream/historical-replay)).
* **Combínalo** con el [monitoreo de slots y bloques](/docs/es/laserstream/guides/slot-and-block-monitoring) para obtener contexto a nivel de bloque.
* **Sigue un token** en lugar de todo el programa: coloca la emisión en `accountInclude` y configura `matchMints: true` en el filtro de transacciones para recibir cada transferencia, intercambio, emisión y quema de ese token (consulta [Filtrado por emisión de tokens](/docs/es/laserstream/mint-filtering)).

***

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Transaction Monitoring" icon="receipt" href="/docs/es/laserstream/guides/transaction-monitoring">
    Los patrones generales de filtrado de transacciones que usa este script.
  </Card>

  <Card title="Decoding Transaction Data" icon="binary" href="/docs/es/laserstream/guides/decoding-transaction-data">
    Analiza la carga útil binaria para convertirla en transacciones de Solana legibles.
  </Card>

  <Card title="Account Subscriptions" icon="user" href="/docs/es/laserstream/guides/account-subscription">
    Observa cambios de estado de cuentas específicas mediante filtros.
  </Card>

  <Card title="Historical Replay" icon="clock-rotate-left" href="/docs/es/laserstream/historical-replay">
    Reproduce hasta 24 horas de actividad pasada de Pump.fun desde un slot inicial.
  </Card>
</CardGroup>
