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

# Surveillance des transactions avec LaserStream

> Diffusez les transactions Solana en temps réel avec LaserStream — filtrage de programme, détails d'exécution, changements de solde de jetons, et relecture sécurisée en cas de reconnexion.

La surveillance des transactions vous permet de suivre l'exécution des transactions, le statut de réussite/échec, les interactions de programme et les changements de solde de jetons sur Solana en temps réel. Ce guide couvre les stratégies de filtrage et les implémentations pratiques à l'aide du SDK [`helius-laserstream`](/docs/fr/laserstream/clients).

<Info>
  **Prérequis :** Ce guide suppose que vous avez complété le [Démarrage rapide LaserStream gRPC](/docs/fr/laserstream/grpc) et que vous avez une clé API.
</Info>

***

## Options de filtrage des transactions

LaserStream utilise la même structure de filtre que Yellowstone gRPC, y compris le filtre `tokenAccounts` (expansion ATA). Les champs à définir dans `transactions.<label>` :

* **`accountInclude`** — correspond si l'un de ces comptes apparaît (OU logique)
* **`accountRequired`** — correspond uniquement si tous ces comptes apparaissent (ET logique)
* **`accountExclude`** — omettre si l'un de ces comptes apparaît
* **`vote` / `failed`** — indicateurs booléens pour les transactions de vote et échouées
* **`tokenAccounts`** — expansion opt-in du compte de tokens associé (ATA) (`"balanceChanged"`, `"all"`, ou `"none"`), ainsi un portefeuille `accountInclude` correspond également aux transactions où il possède un solde de jetons SPL. Voir [Filtrage des comptes de tokens (ATA)](/docs/fr/laserstream/token-account-filtering) et l'onglet **Surveillance d'un portefeuille** ci-dessous.

<Tabs>
  <Tab title="Filtrage par programme">
    **Surveiller les transactions impliquant des programmes spécifiques**

    Suivre toutes les transactions qui touchent les programmes qui vous intéressent :

    ```typescript theme={"system"}
    import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';

    const subscriptionRequest: SubscribeRequest = {
      transactions: {
        "program-filter": {
          accountInclude: [
            "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // Token Program
            "11111111111111111111111111111111",              // System Program
            "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"  // Your program
          ],
          accountExclude: [],
          accountRequired: [],
          vote: false,
          failed: false
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {},
      slots: {},
      transactionsStatus: {},
      blocks: {},
      blocksMeta: {},
      entry: {},
      accountsDataSlice: [],
    };
    ```

    **Idéal pour :** Surveillance spécifique aux programmes, suivi de protocoles DeFi, interactions avec des contrats intelligents.
  </Tab>

  <Tab title="Spécifique au compte">
    **Surveiller les transactions affectant des comptes spécifiques**

    ```typescript theme={"system"}
    const subscriptionRequest: SubscribeRequest = {
      transactions: {
        "wallet-filter": {
          accountInclude: [
            "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint
            "YourWalletAddress"                                // Your wallet
          ],
          accountExclude: [],
          accountRequired: [],
          vote: false,
          failed: true // Include failures to track errors
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, slots: {}, transactionsStatus: {},
      blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    **Cas d'utilisation :** Surveillance de portefeuille, suivi de la frappe de tokens, tableaux de bord d'activité de compte.
  </Tab>

  <Tab title="Filtrage avancé">
    **Combiner plusieurs critères de filtrage**

    ```typescript theme={"system"}
    const subscriptionRequest: SubscribeRequest = {
      transactions: {
        "advanced-filter": {
          accountInclude: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
          accountRequired: ["YourProgramId"], // Must include this program
          accountExclude: ["VoteProgram"],     // Exclude vote-related txs
          vote: false,
          failed: false
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, slots: {}, transactionsStatus: {},
      blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    **Logique de filtrage :** `accountInclude` (OU) **ET** `accountRequired` (ET) **ET PAS** `accountExclude`.
  </Tab>

  <Tab title="Surveillance d'un portefeuille">
    **Attraper les transferts de tokens entrants, pas seulement l'activité directe**

    `accountInclude` ne correspond qu'aux transactions où le portefeuille apparaît directement dans les clés de compte. Lorsqu'une personne envoie un token SPL au portefeuille, le transfert touche le **compte de tokens associé (ATA)** du portefeuille, pas la clé publique du portefeuille — donc une `accountInclude: [wallet]` simple ne le voit jamais.

    Réglez `tokenAccounts` pour étendre la correspondance aux transactions où le portefeuille **possède** un solde de jetons. Cela prend une chaîne :

    * **`"balanceChanged"`** — correspond lorsque le solde de tokens possédé a changé (ou que son compte de tokens a été fermé). Idéal pour "me dire quand l'argent a vraiment bougé" — plus restrictif, de moindre volume, recommandé par défaut.
    * **`"all"`** — correspond à toute transaction faisant référence à un solde de tokens possédé, même si inchangé. Volume considérablement plus élevé.
    * **`"none"`** — pas d'expansion (identique à l'omission du champ).

    ```typescript theme={"system"}
    const subscriptionRequest: SubscribeRequest = {
      transactions: {
        "wallet-with-tokens": {
          accountInclude: ["YourWalletAddress"],
          accountExclude: [],
          accountRequired: [],
          vote: false,
          failed: false,
          tokenAccounts: "balanceChanged" // also match the wallet's ATAs
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, slots: {}, transactionsStatus: {},
      blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    <Note>
      La correspondance est basée sur le propriétaire — elle attrape tout compte de tokens que le portefeuille possède (y compris ceux non canoniques), pas seulement l'adresse ATA dérivée. Le SDK convertit la chaîne en l'énumération `TokenAccountExpansionControlFlag` pour vous.
    </Note>
  </Tab>
</Tabs>

***

## Exemples pratiques

### Exemple 1 : Surveiller les transactions DEX

Suivez les transactions touchant des programmes DEX populaires :

```typescript [expandable] theme={"system"}
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';
import bs58 from 'bs58';

async function monitorDEXTransactions() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      "dex-filter": {
        accountInclude: [
          "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", // Raydium
          "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK", // Raydium CLMM
          "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"   // Jupiter
        ],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {}, slots: {}, transactionsStatus: {},
    blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // Choose your closest region
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.transaction?.transaction) return;
    const tx = data.transaction.transaction;
    console.log(`\n🔄 DEX Transaction:`);
    console.log(`  Signature: ${bs58.encode(tx.signature)}`);
    console.log(`  Slot: ${data.transaction.slot}`);
    console.log(`  Status: ${tx.meta?.err ? 'Failed' : 'Success'}`);
    console.log(`  Fee: ${tx.meta?.fee || 0} lamports`);
    console.log(`  Compute Units: ${tx.meta?.computeUnitsConsumed || 0}`);

    // Token balance changes
    if (tx.meta?.preTokenBalances?.length > 0) {
      console.log(`  Token Balance Changes:`);
      tx.meta.preTokenBalances.forEach((preBalance: any, index: number) => {
        const postBalance = tx.meta.postTokenBalances[index];
        if (preBalance && postBalance) {
          const change = postBalance.uiTokenAmount.uiAmount - preBalance.uiTokenAmount.uiAmount;
          if (change !== 0) {
            console.log(`    ${preBalance.mint}: ${change > 0 ? '+' : ''}${change}`);
          }
        }
      });
    }
  }, async (error) => {
    console.error('Stream error:', error);
  });
}

monitorDEXTransactions().catch(console.error);
```

### Exemple 2 : Surveiller les transactions échouées

Suivez les transactions échouées pour mettre en évidence les problèmes d'application :

```typescript [expandable] theme={"system"}
async function monitorFailedTransactions() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      "failures": {
        accountInclude: ["YourProgramId"],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: true // Only failed transactions
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {}, slots: {}, transactionsStatus: {},
    blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.transaction?.transaction?.meta?.err) return;
    const tx = data.transaction.transaction;
    console.log(`\n❌ Failed Transaction:`);
    console.log(`  Signature: ${bs58.encode(tx.signature)}`);
    console.log(`  Slot: ${data.transaction.slot}`);
    console.log(`  Error: ${JSON.stringify(tx.meta.err)}`);
    console.log(`  Fee: ${tx.meta.fee} lamports`);
    console.log(`  Compute Units: ${tx.meta.computeUnitsConsumed || 0}`);
  }, async (error) => {
    console.error('Stream error:', error);
  });
}
```

### Exemple 3 : Surveiller les transactions de haute valeur

Suivez les transactions avec transferts significatifs de SOL :

```typescript [expandable] theme={"system"}
async function monitorHighValueTransactions() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      "system-program": {
        accountInclude: ["11111111111111111111111111111111"],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {}, slots: {}, transactionsStatus: {},
    blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.transaction?.transaction?.meta) return;
    const tx = data.transaction.transaction;
    const preBalances = tx.meta.preBalances || [];
    const postBalances = tx.meta.postBalances || [];

    let maxChange = 0;
    preBalances.forEach((preBalance: number, index: number) => {
      const postBalance = postBalances[index] || 0;
      maxChange = Math.max(maxChange, Math.abs(postBalance - preBalance));
    });

    const changeInSOL = maxChange / 1e9;
    if (changeInSOL > 10) {
      console.log(`\n💰 High-Value Transaction:`);
      console.log(`  Signature: ${bs58.encode(tx.signature)}`);
      console.log(`  Slot: ${data.transaction.slot}`);
      console.log(`  Max SOL Transfer: ${changeInSOL.toFixed(2)} SOL`);
      console.log(`  Fee: ${tx.meta.fee / 1e9} SOL`);
    }
  }, async (error) => {
    console.error('Stream error:', error);
  });
}
```

### Exemple 4 : Surveiller un portefeuille (y compris les transferts de tokens)

Surveillez tout ce qui déplace de l'argent pour un portefeuille — y compris les transferts entrants de tokens SPL qui touchent ses ATAs — en ajoutant `tokenAccounts` à un filtre `accountInclude` simple :

```typescript [expandable] theme={"system"}
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';
import bs58 from 'bs58';

async function watchWallet(wallet: string) {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      "wallet-activity": {
        accountInclude: [wallet],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false,
        // Also match txs touching token accounts this wallet owns.
        // "balanceChanged" = only when an owned token balance actually moved.
        tokenAccounts: "balanceChanged"
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {}, slots: {}, transactionsStatus: {},
    blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.transaction?.transaction) return;
    const tx = data.transaction.transaction;
    console.log(`\n👛 Wallet activity:`);
    console.log(`  Signature: ${bs58.encode(tx.signature)}`);
    console.log(`  Slot: ${data.transaction.slot}`);

    // Surface token balances this wallet owns that changed in the tx
    const owned = (tx.meta?.postTokenBalances || []).filter((b: any) => b.owner === wallet);
    owned.forEach((post: any) => {
      const pre = (tx.meta.preTokenBalances || []).find(
        (b: any) => b.accountIndex === post.accountIndex
      );
      const before = pre?.uiTokenAmount?.uiAmount || 0;
      const after = post.uiTokenAmount?.uiAmount || 0;
      if (after !== before) {
        console.log(`  ${post.mint}: ${after - before > 0 ? '+' : ''}${after - before}`);
      }
    });
  }, async (error) => {
    console.error('Stream error:', error);
  });
}
```

***

## Structure des données de transaction

<Accordion title="Structure du message de transaction">
  ```typescript theme={"system"}
  {
    signature: string;
    isVote: boolean;
    transaction: {
      message: {
        accountKeys: string[];        // All accounts involved
        instructions: Instruction[];  // Program instructions
        recentBlockhash: string;
      };
      signatures: string[];
    };
    meta: {
      err: any;                      // Error details if failed
      fee: number;                   // Transaction fee in lamports
      computeUnitsConsumed: number;
      preBalances: number[];
      postBalances: number[];
      preTokenBalances: TokenBalance[];
      postTokenBalances: TokenBalance[];
      logMessages: string[];
    };
  }
  ```
</Accordion>

<Accordion title="Changements de solde de tokens">
  ```typescript theme={"system"}
  {
    accountIndex: number;
    mint: string;
    owner: string;
    uiTokenAmount: {
      amount: string;
      decimals: number;
      uiAmount: number;
      uiAmountString: string;
    };
  }
  ```
</Accordion>

<Accordion title="Détails de l'instruction">
  ```typescript theme={"system"}
  {
    programIdIndex: number; // Index in accountKeys array
    accounts: number[];
    data: string;           // Instruction data (base58)
  }
  ```
</Accordion>

***

## Référence de la logique de filtrage

<CardGroup cols={2}>
  <Card title="Logique d'inclusion (OU)" icon="plus">
    **`accountInclude` :** La transaction doit impliquer n'importe lequel de ces comptes.

    `["A", "B"]` correspond aux transactions impliquant le compte A OU le compte B.
  </Card>

  <Card title="Logique requise (ET)" icon="check">
    **`accountRequired` :** La transaction doit impliquer TOUS ces comptes.

    `["A", "B"]` correspond aux transactions impliquant le compte A ET le compte B.
  </Card>

  <Card title="Logique d'exclusion (PAS)" icon="minus">
    **`accountExclude` :** La transaction ne doit pas impliquer n'importe lequel de ces comptes.
  </Card>

  <Card title="Logique combinée" icon="code">
    Filtre final : `(accountInclude OR empty) AND (accountRequired AND all) AND NOT (accountExclude OR any)`.
  </Card>
</CardGroup>

***

## Considérations de performance

<Tabs>
  <Tab title="Gestion du volume">
    Les flux de transactions peuvent être de haut volume. Pour maintenir le rythme :

    * Commencez par des filtres de programme spécifiques (ne vous abonnez pas à "toutes les transactions")
    * Utilisez `confirmed` plutôt que `processed` lorsque vous pouvez tolérer \~1,5s de latence supplémentaire
    * Surveillez votre capacité de traitement avec un compteur
    * Envisagez de faire tourner des consommateurs parallèles derrière une file d'attente

    ```typescript theme={"system"}
    let count = 0;
    const startTime = Date.now();
    // inside your subscribe handler:
    count++;
    if (count % 100 === 0) {
      const elapsed = (Date.now() - startTime) / 1000;
      console.log(`Processing ${(count / elapsed).toFixed(1)} tx/sec`);
    }
    ```
  </Tab>

  <Tab title="Traitement des données">
    Extrayez seulement ce dont vous avez besoin pour conserver une faible mémoire :

    ```typescript theme={"system"}
    import bs58 from 'bs58';

    function extractTransactionData(tx: any) {
      return {
        signature: bs58.encode(tx.signature),
        slot: tx.slot,
        success: !tx.meta?.err,
        fee: tx.meta?.fee || 0,
        computeUnits: tx.meta?.computeUnitsConsumed || 0,
      };
    }
    ```
  </Tab>
</Tabs>

***

## Gestion des erreurs

<Accordion title="Trop de transactions">
  **Symptôme :** Volume de transactions écrasant.

  **Solutions :** Ajoutez des filtres plus stricts (`accountRequired`, `accountExclude`) ; utilisez un engagement plus élevé ; implémentez un échantillonnage ou une limitation de débit ; traitez de manière asynchrone.
</Accordion>

<Accordion title="Transactions manquantes">
  **Symptôme :** Transactions attendues non apparues.

  **Solutions :** Vérifiez que les adresses des programmes sont correctes ; vérifiez que les transactions existent réellement ; essayez `processed` pour des mises à jour plus rapides ; assouplissez les filtres restrictifs `accountRequired`/`accountExclude`.
</Accordion>

<Accordion title="Erreurs d'analyse">
  **Symptôme :** Impossible d'analyser les données de la transaction.

  **Solutions :** Gérez les champs manquants avec grâce ; validez la structure avant le traitement ; enveloppez l'analyse dans un try/catch ; voir [Décodage des données de transaction](/docs/fr/laserstream/guides/decoding-transaction-data).
</Accordion>

***

## Prochaines étapes

<CardGroup cols={2}>
  <Card title="Surveillance des slots et des blocs" icon="cube" href="/docs/fr/laserstream/guides/slot-and-block-monitoring">
    Suivre le consensus du réseau et la production de blocs.
  </Card>

  <Card title="Diffuser les données AMM Pump" icon="chart-line" href="/docs/fr/laserstream/guides/stream-pump-amm-data">
    Exemple du monde réel : surveiller les transactions AMM de Pump.fun.
  </Card>

  <Card title="Décodage des données de transaction" icon="binary" href="/docs/fr/laserstream/guides/decoding-transaction-data">
    Analyser les charges utiles des transactions binaires en transactions Solana lisibles.
  </Card>

  <Card title="Référence du protocole Yellowstone" icon="book" href="/docs/fr/grpc/transaction-monitoring">
    Le même flux de travail contre le protocole brut de Yellowstone gRPC.
  </Card>
</CardGroup>
