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

# Как использовать preconfSubscribe

> Получайте поток транзакций Solana с минимально возможной задержкой с помощью метода WebSocket preconfSubscribe — подписывайтесь, фильтруйте и декодируйте полезную нагрузку.

<Tip>
  **Используйте [Sender Max](/docs/ru/sending-transactions/sender-max) (минимальные чаевые: 0,001 SOL), чтобы
  реагировать на Preconfirmations.** Предварительное подтверждение приносит пользу, только если ваша
  транзакция попадает в блок
  первой — Sender Max позволяет сделать это быстрее всего. Используйте Sender Max с самого
  начала, чтобы получить все преимущества Preconfirmations.
</Tip>

## Что такое `preconfSubscribe`?

`preconfSubscribe` — это метод WebSocket от Helius, который передает поток [Preconfirmations](/docs/ru/pre-confirmations/overview) — транзакций, доставленных до того, как они будут собраны в записи и разделены на Shred. Это сигнал о транзакции с самой низкой задержкой, который предлагает Helius. Одна подписка доставляет как предварительные подтверждения Helius, отправляемые сразу после выполнения транзакции лидером и содержащие статус ее выполнения, так и [предварительные подтверждения BAM](/docs/ru/pre-confirmations/overview#предподтверждения-bam) от валидаторов, использующих клиент Jito Block Assembly Marketplace. Они отправляются, когда валидатор обязуется выполнить транзакцию. Для доступа требуется [тариф Professional или выше](/docs/ru/billing/plans) — см. раздел [Стоимость](#стоимость).

<Note>
  Поток не является непрерывным. Покрытие зависит от доли стейка,
  перенаправляемой в Helius или использующей BAM, поэтому в некоторых слотах сообщений не будет — корректно
  обрабатывайте такие пропуски. См. раздел [Покрытие](/docs/ru/pre-confirmations/overview#охват).
</Note>

`preconfSubscribe` обслуживается через `wss://beta.helius-rpc.com` — конечную точку Helius [Gatekeeper](/docs/ru/gatekeeper/overview), а не через `mainnet.helius-rpc.com`. Для аутентификации передайте ключ API в качестве параметра запроса.

```
wss://beta.helius-rpc.com/?api-key=<API_KEY>
```

<Note>
  Имя хоста `beta` относится к развертыванию [Gatekeeper](/docs/ru/gatekeeper/overview),
  а не к степени готовности Preconfirmations. Сначала Preconfirmations запускаются на
  конечной точке Gatekeeper; она станет стандартной конечной точкой по мере того, как Helius
  будет переносить трафик в Gatekeeper.
</Note>

## Подписка

Отправьте запрос JSON-RPC с методом `preconfSubscribe`. Сервер ответит идентификатором подписки, а затем будет передавать уведомление для каждой транзакции. Передайте необязательный [фильтр](#фильтрация) в качестве первого элемента `params`, чтобы получать только соответствующие транзакции; не указывайте `params`, чтобы получать полный поток как от Helius, так и от BAM.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe"
}
```

### Ответ на подписку

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": 24040,
  "id": 1
}
```

Сохраните `result` — это идентификатор подписки, который используется для [отмены подписки](#отмена-подписки). После этого подтверждения уведомления передаются в виде двоичных кадров (см. ниже).

## Фильтрация

По умолчанию `preconfSubscribe` передает каждую транзакцию из обоих источников. Чтобы сузить поток, передайте объект фильтра в качестве первого элемента `params`. Фильтрация выполняется на стороне сервера, поэтому вы получаете и оплачиваете только интересующие вас транзакции.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "includeBam": true,
      "failed": false,
      "regionInclude": ["ewr", "fra"],
      "accountInclude": ["9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"],
      "accountExclude": ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
      "accountRequired": ["11111111111111111111111111111111"],
      "signerExclude": ["8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR"]
    }
  ]
}
```

Все поля необязательны — отсутствие поля означает «без ограничений» для соответствующего предиката, поэтому пустой фильтр (или отсутствие `params`) соответствует каждой транзакции из обоих источников.

| Поле | Тип | Семантика |
| - | - | - |
| `includeBam` | `boolean` | По умолчанию — `true`. `false` исключает предварительные подтверждения BAM, поэтому вы получаете только предварительные подтверждения Helius. |
| `failed` | `boolean` | `true` возвращает только неуспешные (отмененные) транзакции; `false` возвращает только успешные транзакции. Оба значения исключают транзакции Helius с неизвестным статусом. Не указывайте поле, чтобы получать транзакции со всеми статусами. |
| `regionInclude` | `string[]` | Если список не пуст, транзакция должна поступить из **одного из** этих [регионов](#фильтрация-по-местоположению). |
| `accountInclude` | `string[]` | Если список не пуст, транзакция должна ссылаться **хотя бы на одну** из этих учетных записей. |
| `accountExclude` | `string[]` | Транзакция исключается, если ссылается **на любую** из этих учетных записей. Имеет приоритет над `accountInclude`. |
| `accountRequired` | `string[]` | Транзакция должна ссылаться **на все** эти учетные записи. |
| `signerInclude` | `string[]` | Если список не пуст, транзакция должна быть подписана **хотя бы одной** из этих учетных записей. |
| `signerExclude` | `string[]` | Транзакция исключается, если она подписана **любой** из этих учетных записей. Имеет приоритет над `signerInclude`. |
| `signatures` | `string[]` | Если список не пуст, первая подпись транзакции должна соответствовать **одной** из этих подписей. |
| `instructions` | `object[]` | Если список не пуст, хотя бы одна инструкция верхнего уровня должна соответствовать **одному** из этих [фильтров инструкций](#фильтрация-инструкций). |

Правила фильтрации:

* Все предикаты объединяются логическим И и вычисляются в следующем порядке: `includeBam` → `failed` → `regionInclude` → `signatures` → `accountExclude` → `accountRequired` → `accountInclude` → `signerExclude` → `signerInclude` → `instructions`.
* Предварительные подтверждения BAM с неизвестным статусом игнорируют фильтр `failed`. Предварительные подтверждения Helius с неизвестным статусом не соответствуют явно заданному фильтру `failed`.
* Учетные записи представляют собой открытые ключи в кодировке base58. Недопустимое значение возвращает ошибку JSON-RPC `-32602` (недопустимые параметры).
* Каждый список учетных записей или подписантов ограничен **10 000** элементами. `signatures` ограничен **1 000** элементами.

Чтобы получать только предварительные подтверждения Helius:

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [{ "includeBam": false }]
}
```

### Фильтрация по подписанту и подписи

Используйте `signerInclude`, чтобы находить транзакции, подписанные определенной учетной записью. Используйте `signerExclude`, чтобы исключать транзакции, подписанные любой из перечисленных учетных записей. Учетная запись, на которую ссылается транзакция, не считается подписантом.

Используйте `signatures`, если вы уже знаете, какие транзакции хотите отслеживать. Фильтр сопоставляет первую подпись транзакции — именно эту подпись используют методы Solana RPC. После оформления подписки фильтр изменить нельзя, поэтому для отслеживания новых подписей создайте новую подписку.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "signerInclude": ["9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"],
      "signerExclude": ["8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR"]
    }
  ]
}
```

### Фильтрация инструкций

Используйте `instructions`, чтобы сопоставлять инструкции верхнего уровня по программе и данным инструкции. Каждый фильтр инструкций поддерживает следующие поля:

| Поле | Тип | Семантика |
| - | - | - |
| `programId` | `string` | Обязательное. Программа, вызываемая инструкцией. |
| `memcmp` | `object[]` | Необязательное. Каждый элемент сравнивает декодированные `bytes` по смещению `offset`. Все элементы должны совпасть. |
| `dataSize` | `number` | Необязательное. Данные инструкции должны иметь в точности такую длину в байтах. |

Каждый элемент `memcmp` принимает кодировку `base58`, `base64` или `hex`. По умолчанию используется `base58`. Транзакция соответствует фильтру, если одна инструкция верхнего уровня удовлетворяет всем условиям любого фильтра инструкций.

Следующий запрос сопоставляет инструкции pump.fun `buy` по их дискриминатору Anchor:

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "instructions": [
        {
          "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
          "memcmp": [
            {
              "offset": 0,
              "bytes": "66063d1201daebea",
              "encoding": "hex"
            }
          ]
        }
      ]
    }
  ]
}
```

Фильтр проверяет только инструкции верхнего уровня. Он не может сопоставлять инструкции, вызываемые посредством межпрограммного вызова (CPI), поскольку до выполнения этих инструкций не существует.

Можно указать до 16 фильтров инструкций и до четырех элементов `memcmp` на каждый фильтр инструкций. Каждое значение `memcmp` должно декодироваться в последовательность длиной от 1 до 128 байт. Конечное смещение `memcmp` и `dataSize` не должны превышать 4 096 байт.

### Разрешение таблиц поиска адресов (ALT)

Фильтры учетных записей сопоставляются не только со статическими ключами учетных записей транзакции — Helius разрешает [таблицы поиска адресов](/docs/ru/glossary#таблица-поиска-адресов-alt) v0 на стороне сервера, поэтому `accountInclude`, `accountExclude` и `accountRequired` также сопоставляются с учетными записями, которые транзакция загружает через ALT.

Это означает, что вы можете фильтровать по любой учетной записи, с которой взаимодействует транзакция, даже если она указана только через таблицу поиска. Вам не нужно поддерживать сопоставления ALT или самостоятельно разрешать таблицы. Просто передайте открытый ключ учетной записи, и Helius выполнит разрешение перед применением фильтра.

### Фильтрация по местоположению

Используйте `regionInclude`, чтобы получать только транзакции, поступающие из определенных регионов. Передайте один или несколько кодов регионов; транзакция проходит фильтр, если регион ее происхождения соответствует любому из них.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [{ "regionInclude": ["ewr", "fra"] }]
}
```

Регион происхождения зависит от источника. Для предварительных подтверждений Helius это регион Helius, который принял транзакцию. Для предварительных подтверждений BAM это региональная конечная точка BAM, отправившая предварительное подтверждение, а не место, где его принял Helius. Конечные точки BAM в Сингапуре и Далласе соответствуют `sgp` и `dal`.

Допустимые коды регионов:

| Код | Местоположение |
| - | - |
| `slc` | Солт-Лейк-Сити |
| `fra` | Франкфурт |
| `lon` | Лондон |
| `pit` | Питтсбург |
| `sgp` | Сингапур |
| `ewr` | Ньюарк |
| `tyo` | Токио |
| `ams` | Амстердам |
| `dal` | Даллас |
| `dub` | Дублин |
| `mia` | Майами |
| `lax` | Лос-Анджелес |
| `iad` | Ашберн |
| `sea` | Сиэтл |
| `hkg` | Гонконг |
| `sqq` | Шяуляй, Литва |

<Note>
  Если задан `regionInclude`, транзакции без информации о регионе исключаются. Нераспознанный код региона возвращает ошибку JSON-RPC `-32602` (недопустимые параметры).
</Note>

## Полезная нагрузка уведомления

Уведомления доставляются в виде **двоичных** кадров WebSocket (не JSON). Предварительные подтверждения Helius и BAM имеют одинаковую структуру. Каждый кадр представляет собой упакованную последовательность байтов, содержащую одну транзакцию:

| Байты | Поле | Тип | Описание |
| - | - | - | - |
| 0 | `version` | `u8` | Версия схемы полезной нагрузки. Сейчас — `1`. |
| 1–8 | `slot` | `u64` (обратный порядок байтов) | Слот, к которому относится транзакция. |
| 9–16 | `tx_index` | `u64` (обратный порядок байтов) | Индекс транзакции в слоте, если он доступен. Предварительные подтверждения BAM всегда возвращают `0`; другие источники также могут возвращать `0`, если индекс транзакции недоступен. |
| 17 | `status` | `u8` | Статус транзакции: `0` = ошибка, `1` = успех, `2` = неизвестно. |
| 18+ | `transaction` | `bytes` | Транзакция в сетевом формате Solana. См. раздел [Декодирование транзакции](#декодирование-транзакции). |

Полезная нагрузка не содержит поля источника. Не делайте вывод о происхождении из BAM на основании `tx_index = 0`, поскольку другие источники также могут возвращать `0`.

### Как различать два источника

Поскольку поле источника отсутствует, произвольное сообщение нельзя однозначно отнести к Helius или BAM. Байт `status` позволяет выполнить одностороннюю классификацию:

* **`status` равен `0` или `1`** — сообщение является предварительным подтверждением Helius, а транзакция была выполнена. BAM никогда не возвращает эти значения.
* **`status` равен `2`** — источник неоднозначен: это либо предварительное подтверждение BAM, либо предварительное подтверждение Helius, для которого статус выполнения был недоступен.

Других различающих полей нет. Идентификатор последовательности и позиция в пакете BAM не передаются в этом потоке, поэтому метаданные порядка BAM, которые можно было бы использовать в качестве ключа, отсутствуют. `regionInclude` — это фильтр подписки, а не поле полезной нагрузки, поэтому его нельзя прочитать для отдельного сообщения.

Если требуется, чтобы каждое сообщение в потоке содержало свидетельство одного типа, задайте `includeBam: false` — в потоке останутся только предварительные подтверждения Helius, отправляемые во время выполнения лидером. Фильтра только для BAM нет.

<Warning>
  **Всегда сначала считывайте и проверяйте байт `version`.** Сейчас он равен `1`. Если
  Helius потребуется обновить формат полезной нагрузки, номер версии увеличится — выполняйте ветвление
  по нему, чтобы декодер продолжал работать после изменений схемы.
</Warning>

<Note>
  Предварительное подтверждение — это ранний сигнал, а не гарантия. Транзакция еще не
  попала в блокчейн и все еще может быть исключена, а статус выполнения в предварительном подтверждении Helius
  отражает локальный результат лидера, который не является окончательным до
  подтверждения блока. Прежде чем считать транзакцию окончательной, подтвердите ее попадание в блок
  с помощью стандартных проверок уровня подтверждения.
</Note>

### Декодирование транзакции

Байты транзакции передаются именно в том виде, в котором их сериализовал валидатор, в стандартной сетевой кодировке соответствующей версии транзакции. Транзакции устаревшего формата и v0 используют структуру с подписями в начале, которую создает `bincode`. Транзакции v1 ([SIMD-0385](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md)) используют структуру с сообщением в начале и подписями в конце, поэтому `bincode` не может обработать полезную нагрузку v1. Используйте декодер, поддерживающий все версии:

* **Rust:** [`agave-transaction-view`](https://docs.rs/agave-transaction-view) разбирает транзакции устаревшего формата, v0 и v1 на месте, без промежуточного копирования. Это рекомендуемый вариант. [`wincode`](https://docs.rs/wincode), совместимый с bincode сериализатор, используемый текущими SDK Solana, также декодирует v1 в `VersionedTransaction`.
* **JavaScript / TypeScript:** убедитесь, что версия вашей библиотеки поддерживает транзакции v1. Старые реализации `VersionedTransaction.deserialize` поддерживают только устаревший формат и v0. Используйте `@solana/kit` 8.0+ или `@solana/web3.js` v3. См. раздел [Поддержка транзакций v1](/docs/ru/rpc/transaction-v1).

```rust theme={"system"}
use agave_transaction_view::transaction_view::TransactionView;

// `frame` is the full binary WebSocket message
let tx_bytes = &frame[18..];
let tx = TransactionView::try_new_unsanitized(tx_bytes)?;

println!("version: {:?}", tx.version()); // Legacy, V0, or V1
println!("signature: {}", tx.signatures()[0]);
for ix in tx.instructions_iter() {
    println!("program index {}: {} bytes", ix.program_id_index, ix.data.len());
}
```

## Дублирующиеся уведомления

Предварительные подтверждения Helius и BAM дедуплицируются отдельно для каждого источника, но не между источниками. Небольшая доля транзакций поступает в Helius обоими способами, поэтому одну и ту же подпись можно получить дважды, причем две копии могут указывать разные слоты.

Выполняйте дедупликацию по подписи на стороне клиента и сделайте действия, запускаемые транзакциями, идемпотентными, чтобы второе уведомление не запускало одно и то же действие повторно. Подтверждайте выполнение и попадание в блок с помощью стандартных проверок уровня подтверждения.

## Пример

```javascript theme={"system"}
const WebSocket = require('ws');

const ws = new WebSocket('wss://beta.helius-rpc.com/?api-key=<API_KEY>');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'preconfSubscribe' // Helius and BAM preconfirmations by default
    // Optional: txs from EWR/FRA touching a given account; Helius txs must be successful.
    // BAM ignores the status filter; region and account filters still apply.
    // params: [{ failed: false, regionInclude: ['ewr', 'fra'], accountInclude: ['9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM'] }]
    // Optional: Helius preconfirmations only
    // params: [{ includeBam: false }]
  }));

  // Keep the connection alive
  setInterval(() => ws.ping(), 30_000);
});

ws.on('message', (data, isBinary) => {
  // The subscribe acknowledgement arrives as a JSON text frame
  if (!isBinary) {
    const msg = JSON.parse(data.toString());
    if (msg.id === 1) console.log('Subscribed, ID:', msg.result);
    return;
  }

  // Notifications arrive as binary frames:
  // version (u8) | slot (u64 LE) | tx_index (u64 LE) | status (u8) | transaction bytes
  const buf = Buffer.from(data);
  const version = buf.readUInt8(0); // currently 1 — branch on this if it changes
  if (version !== 1) return; // unknown schema version; update your decoder
  const slot = buf.readBigUInt64LE(1);
  const txIndex = buf.readBigUInt64LE(9); // always 0 for BAM; may be 0 for other sources
  const status = buf.readUInt8(17); // 0 = failed, 1 = success, 2 = unknown
  const txBytes = buf.subarray(18); // transaction in Solana wire format (legacy, v0, or v1)

  console.log('Preconfirmation:', { version, slot, txIndex, status, bytes: txBytes.length });
  // Decode txBytes with a decoder that supports transaction v1 (see "Decoding the transaction")
});

ws.on('error', console.error);
ws.on('close', () => process.exit(1));
```

## Отмена подписки

Чтобы прекратить получать уведомления, вызовите `preconfUnsubscribe` с идентификатором подписки, возвращенным из `preconfSubscribe`.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "preconfUnsubscribe",
  "params": [24040]
}
```

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": true,
  "id": 2
}
```

## Стоимость

<Note>
  Минимум в 300 кредитов за слот вступает в силу **14 октября 2026 года**. До
  этого момента Preconfirmations оплачиваются по 10 кредитов за сообщение без минимальной суммы.
</Note>

Для использования Preconfirmations требуется **тариф Professional или выше**. Стоимость составляет **10 кредитов за сообщение**, при этом для каждой подписки действует **минимум 300 кредитов за слот**, списываемых с вашего тарифа. Подробнее см. в разделе [Кредиты](/docs/ru/billing/credits).

Минимальная сумма применяется только к слотам с [покрытием](/docs/ru/pre-confirmations/overview#охват) предварительных подтверждений. В каждом покрытом слоте за подписку списывается большая из двух сумм: 10 кредитов за каждое доставленное сообщение или 300 кредитов. Слоты без покрытия не оплачиваются. В разделе [Стоимость](/docs/ru/pre-confirmations/overview#тарификация) указано, какие слоты учитываются при расчете минимума.

| Сообщения, доставленные в покрытом слоте | Списанные кредиты |
| - | - |
| 0 | 300 |
| 10 | 300 |
| 30 | 300 |
| 100 | 1 000 |

Минимум рассчитывается отдельно для каждой подписки, поэтому за каждую открытую подписку `preconfSubscribe` списывается не менее 300 кредитов за покрытый слот. Закрывайте ненужные подписки с помощью `preconfUnsubscribe`.

Оплата рассчитывается за каждое сообщение, а не за уникальную подпись. Транзакция, доставленная как Helius, так и BAM, учитывается дважды. Установите `includeBam: false`, если хотите получать только предварительные подтверждения Helius.

<Note>
  Preconfirmations — новый продукт, и его стоимость может измениться.
</Note>

## Связанные материалы

<CardGroup cols={2}>
  <Card title="Preconfirmations Overview" icon="bolt" href="/docs/ru/pre-confirmations/overview">
    Что такое Preconfirmations и какое место они занимают в конвейере валидатора.
  </Card>

  <Card title="transactionSubscribe" icon="tower-broadcast" href="/docs/ru/rpc/websocket/transaction-subscribe">
    Получайте поток транзакций с уровнем подтверждения confirmed и расширенной фильтрацией.
  </Card>

  <Card title="preconfSubscribe API reference" icon="code" href="/docs/ru/api-reference/pre-confirmations/preconfsubscribe">
    Параметры запроса, поля фильтра и структура двоичного уведомления.
  </Card>
</CardGroup>


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