> ## 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 с помощью LaserStream

> Готовый к копированию скрипт LaserStream, который в реальном времени передает данные об активности аккаунтов и транзакций Pump.fun, рассчитывает скользящую статистику и декодирует подписи.

Передавайте все обновления аккаунтов и транзакции Pump.fun в реальном времени с помощью [LaserStream SDK](/docs/ru/laserstream/clients). На этой странице разбирается полный скрипт TypeScript, который можно запустить от начала до конца: он выводит каждую транзакцию по мере ее поступления, раз в минуту показывает скользящую статистику (пропускную способность, количество уникальных плательщиков комиссий и общую сумму комиссий в SOL) и автоматически сохраняет подключение при повторных соединениях.

Это удобная отправная точка для любых решений, которым нужен непрерывный мониторинг Pump.fun: торговых ботов, аналитических панелей, конвейеров оповещений или простого изучения структуры данных, на основе которой можно создать более специализированное решение.

<Info>
  **Предварительные требования:** [ключ API Helius](https://dashboard.helius.dev/) (тариф Business или Professional для Mainnet LaserStream) и Node.js 18+. Знакомство с разделами [Подписки на аккаунты](/docs/ru/laserstream/guides/account-subscription) и [Мониторинг транзакций](/docs/ru/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/ru/laserstream/grpc#конечные-точки-mainnet).

***

## Скрипт

Сохраните этот код как `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(...)`, чтобы получить подпись в формате base58, которую вы увидели бы в обозревателе или ответе `getTransaction`.
* **`tx.meta.fee`** — это значение u64, хранящееся в виде строки, чтобы значения выше `Number.MAX_SAFE_INTEGER` не теряли точность в JavaScript. Перед арифметическими операциями оберните его в `Number(...)`. То же соглашение о хранении u64 в виде строк применяется к нескольким полям уровня блока. Полную структуру данных см. в разделе [Мониторинг слотов и блоков](/docs/ru/laserstream/guides/slot-and-block-monitoring).

### Скользящая статистика

`setInterval` выводит сводку каждые 60 секунд: общее количество транзакций, число успешных и неуспешных транзакций, пропускную способность, количество уникальных плательщиков комиссий и общую сумму комиссий в SOL. Нажмите `Ctrl+C`, чтобы вывести последнюю сводку перед завершением работы скрипта.

***

## Расширение скрипта

Вот несколько вариантов дальнейшего развития:

* **Декодируйте дискриминаторы инструкций**, чтобы помечать сделки как `buy` / `sell` / `create`. Шаблон разбора см. в разделе [Декодирование данных транзакций](/docs/ru/laserstream/guides/decoding-transaction-data).
* **Сохраняйте** скользящую статистику в базе данных (Postgres, Redis, ClickHouse), а не во внутренних `Set` / счетчиках в памяти.
* **Настройте оповещения** по пороговым значениям: крупные плательщики комиссий, внезапные всплески объема, новые аккаунты кривых бондинга.
* **Воспроизводите** пропущенную активность при запуске, задав `fromSlot` в `SubscribeRequest` (не более чем за последние 48 часов; см. [Воспроизведение исторических данных](/docs/ru/laserstream/historical-replay)).
* **Объедините** скрипт с [мониторингом слотов и блоков](/docs/ru/laserstream/guides/slot-and-block-monitoring), чтобы получить контекст на уровне блоков.
* **Отслеживайте один токен** вместо всей программы: укажите адрес выпуска токена в `accountInclude` и задайте `matchMints: true` в фильтре транзакций, чтобы получать каждую передачу, обмен, выпуск и сжигание этого токена (см. [Фильтрация по выпуску токена](/docs/ru/laserstream/mint-filtering)).

***

## Следующие шаги

<CardGroup cols={2}>
  <Card title="Transaction Monitoring" icon="receipt" href="/docs/ru/laserstream/guides/transaction-monitoring">
    Общие шаблоны фильтрации транзакций, используемые этим скриптом.
  </Card>

  <Card title="Decoding Transaction Data" icon="binary" href="/docs/ru/laserstream/guides/decoding-transaction-data">
    Преобразуйте двоичную полезную нагрузку транзакции в читаемые транзакции Solana.
  </Card>

  <Card title="Account Subscriptions" icon="user" href="/docs/ru/laserstream/guides/account-subscription">
    Отслеживайте изменения состояния определенных аккаунтов с помощью фильтров.
  </Card>

  <Card title="Historical Replay" icon="clock-rotate-left" href="/docs/ru/laserstream/historical-replay">
    Воспроизводите до 24 часов прошлой активности Pump.fun, начиная с указанного слота.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.