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

# Monitoreo de transacciones con LaserStream

> Transmite transacciones de Solana en tiempo real con LaserStream: filtrado por programa, detalles de ejecución, cambios en los saldos de tokens y reproducción segura tras una reconexión.

El monitoreo de transacciones te permite seguir en tiempo real la ejecución de transacciones, su estado de éxito o fallo, las interacciones con programas y los cambios en los saldos de tokens en Solana. Esta guía abarca estrategias de filtrado e implementaciones prácticas mediante el SDK [`helius-laserstream`](/docs/es/laserstream/clients).

<Info>
  **Requisitos previos:** Esta guía supone que completaste el [inicio rápido de gRPC de LaserStream](/docs/es/laserstream/grpc) y que tienes una clave de API.
</Info>

***

## Opciones de filtrado de transacciones

LaserStream usa la misma estructura de filtros que Yellowstone gRPC, incluido el filtro `tokenAccounts` (expansión de ATA). Estos son los campos que debes configurar dentro de `transactions.<label>`:

* **`accountInclude`** — encuentra coincidencias si aparece cualquiera de estas cuentas (OR lógico)
* **`accountRequired`** — encuentra coincidencias solo si aparecen todas estas cuentas (AND lógico)
* **`accountExclude`** — descarta la transacción si aparece cualquiera de estas cuentas
* **`vote` / `failed`** — indicadores booleanos para transacciones de voto y fallidas
* **`tokenAccounts`** — expansión opcional de cuentas de token asociadas (ATA) (`"balanceChanged"`, `"all"` o `"none"`), para que una billetera en `accountInclude` también coincida con transacciones en las que sea propietaria de un saldo de tokens SPL. Consulta [Filtrado de cuentas de token (ATA)](/docs/es/laserstream/token-account-filtering) y la pestaña **Watching a Wallet** a continuación.
* **`matchMints`** — indicador opcional que también compara las listas de cuentas con las acuñaciones de los saldos de tokens previos y posteriores de una transacción, para que una acuñación en `accountInclude` detecte cada transferencia, intercambio, acuñación y quema de ese token. Consulta [Filtrado por acuñación de tokens](/docs/es/laserstream/mint-filtering) y la pestaña **Watching a Token** a continuación.

<Tabs>
  <Tab title="Program Filtering">
    **Monitorea transacciones que involucren programas específicos**

    Sigue todas las transacciones que interactúen con los programas que te interesan:

    ```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: [],
    };
    ```

    **Ideal para:** Monitoreo específico de programas, seguimiento de protocolos DeFi e interacciones con contratos inteligentes.
  </Tab>

  <Tab title="Account-Specific">
    **Monitorea transacciones que afecten cuentas específicas**

    ```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: [],
    };
    ```

    **Caso de uso:** Monitoreo de billeteras, seguimiento de acuñaciones de tokens y paneles de actividad de cuentas.
  </Tab>

  <Tab title="Advanced Filtering">
    **Combina varios criterios de filtrado**

    ```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: [],
    };
    ```

    **Lógica del filtro:** `accountInclude` (OR) **AND** `accountRequired` (AND) **AND NOT** `accountExclude`.
  </Tab>

  <Tab title="Watching a Wallet">
    **Detecta transferencias de tokens entrantes, no solo actividad directa**

    `accountInclude` solo coincide con transacciones en las que la billetera aparece directamente en las claves de cuenta. Cuando alguien envía un token SPL a la billetera, la transferencia interactúa con la **cuenta de token asociada (ATA)** de la billetera, no con la clave pública de la billetera; por eso, un filtro `accountInclude: [wallet]` simple nunca la detecta.

    Configura `tokenAccounts` para ampliar las coincidencias a transacciones en las que la billetera **posea** un saldo de tokens. Acepta una cadena:

    * **`"balanceChanged"`** — coincide cuando cambia un saldo de tokens en propiedad (o se cierra su cuenta de token). Es ideal para «avísame cuando realmente se mueva dinero»: es más específico, genera menos volumen y es la opción predeterminada recomendada.
    * **`"all"`** — coincide con cualquier transacción que haga referencia a un saldo de tokens en propiedad, aunque no haya cambiado. Genera un volumen considerablemente mayor.
    * **`"none"`** — sin expansión (equivale a omitir el campo).

    ```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 coincidencia se basa en el propietario: detecta cualquier cuenta de token que pertenezca a la billetera (incluidas las no canónicas), no solo la dirección ATA derivada. El SDK convierte la cadena en la enumeración `TokenAccountExpansionControlFlag` del protocolo por ti.
    </Note>
  </Tab>

  <Tab title="Watching a Token">
    **Detecta todas las transacciones de una acuñación, no solo las que la mencionan**

    Un filtro `accountInclude: [mint]` simple solo coincide con transacciones cuyas claves de cuenta contienen la acuñación, como `MintTo`, `Burn` o `TransferChecked`. Una operación SPL `Transfer` clásica nunca hace referencia a la acuñación, por lo que no se detecta la mayoría de las transferencias del token.

    Configura `matchMints: true` para que las listas de cuentas también se comparen con las acuñaciones de `preTokenBalances` y `postTokenBalances` de la transacción:

    ```typescript theme={"system"}
    const USDC = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';

    const subscriptionRequest: SubscribeRequest = {
      transactions: {
        "usdc-activity": {
          accountInclude: [USDC],
          accountExclude: [],
          accountRequired: [],
          vote: false,
          failed: false,
          matchMints: true // also match via pre/post token-balance mints
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, slots: {}, transactionsStatus: {},
      blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    Combínalo con `tokenAccounts` para observar un token de una billetera: coloca la billetera en `accountInclude` con `tokenAccounts: "balanceChanged"` y la acuñación en `accountRequired` con `matchMints: true`. Requiere `helius-laserstream` 0.8.5+ (JS), 0.6.4+ (Rust) o `go/v0.3.0`+ (Go). Consulta [Filtrado por acuñación de tokens](/docs/es/laserstream/mint-filtering) para conocer la semántica completa.
  </Tab>
</Tabs>

***

## Ejemplos prácticos

### Ejemplo 1: Monitorea transacciones de DEX

Sigue las transacciones que interactúen con programas DEX populares:

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

### Ejemplo 2: Monitorea transacciones fallidas

Sigue las transacciones fallidas para detectar problemas de la aplicación:

```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);
  });
}
```

### Ejemplo 3: Monitorea transacciones de alto valor

Sigue las transacciones con transferencias significativas 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);
  });
}
```

### Ejemplo 4: Observa una billetera (incluidas las transferencias de tokens)

Monitorea todo lo que mueva dinero en una billetera, incluidas las transferencias entrantes de tokens SPL que interactúen con sus ATA, agregando `tokenAccounts` a un filtro `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);
  });
}
```

***

## Estructura de datos de las transacciones

<Accordion title="Transaction Message Structure">
  ```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="Token Balance Changes">
  ```typescript theme={"system"}
  {
    accountIndex: number;
    mint: string;
    owner: string;
    uiTokenAmount: {
      amount: string;
      decimals: number;
      uiAmount: number;
      uiAmountString: string;
    };
  }
  ```
</Accordion>

<Accordion title="Instruction Details">
  ```typescript theme={"system"}
  {
    programIdIndex: number; // Index in accountKeys array
    accounts: number[];
    data: string;           // Instruction data (base58)
  }
  ```
</Accordion>

***

## Referencia de la lógica de filtros

<CardGroup cols={2}>
  <Card title="Include Logic (OR)" icon="plus">
    **`accountInclude`:** La transacción debe involucrar CUALQUIERA de estas cuentas.

    `["A", "B"]` coincide con transacciones que involucren la cuenta A O la cuenta B.
  </Card>

  <Card title="Required Logic (AND)" icon="check">
    **`accountRequired`:** La transacción debe involucrar TODAS estas cuentas.

    `["A", "B"]` coincide con transacciones que involucren la cuenta A Y la cuenta B.
  </Card>

  <Card title="Exclude Logic (NOT)" icon="minus">
    **`accountExclude`:** La transacción NO debe involucrar ninguna de estas cuentas.
  </Card>

  <Card title="Combined Logic" icon="code">
    Filtro final: `(accountInclude OR empty) AND (accountRequired AND all) AND NOT (accountExclude OR any)`.
  </Card>
</CardGroup>

***

## Consideraciones de rendimiento

<Tabs>
  <Tab title="Volume Management">
    Los flujos de transacciones pueden tener un gran volumen. Para mantener el ritmo:

    * Comienza con filtros de programas específicos (no te suscribas a «todas las transacciones»)
    * Usa `confirmed` en lugar de `processed` cuando puedas tolerar \~1.5 s de latencia adicional
    * Monitorea tu capacidad de procesamiento con un contador
    * Considera ejecutar consumidores en paralelo detrás de una cola

    ```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="Data Processing">
    Extrae solo lo necesario para mantener bajo el uso de memoria:

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

***

## Manejo de errores

<Accordion title="Too Many Transactions">
  **Síntoma:** Volumen abrumador de transacciones.

  **Soluciones:** Agrega filtros más estrictos (`accountRequired`, `accountExclude`); usa un nivel de compromiso mayor; implementa muestreo o limitación de solicitudes; procesa de forma asíncrona.
</Accordion>

<Accordion title="Missing Transactions">
  **Síntoma:** No aparecen las transacciones esperadas.

  **Soluciones:** Verifica que las direcciones de los programas sean correctas; comprueba que las transacciones realmente existan; prueba `processed` para obtener actualizaciones más rápidas; flexibiliza los filtros restrictivos `accountRequired`/`accountExclude`.
</Accordion>

<Accordion title="Parse Errors">
  **Síntoma:** No se pueden analizar los datos de la transacción.

  **Soluciones:** Maneja adecuadamente los campos faltantes; valida la estructura antes de procesarla; encapsula el análisis en try/catch; consulta [Decodificación de datos de transacciones](/docs/es/laserstream/guides/decoding-transaction-data).
</Accordion>

***

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Slot & Block Monitoring" icon="cube" href="/docs/es/laserstream/guides/slot-and-block-monitoring">
    Sigue el consenso de la red y la producción de bloques.
  </Card>

  <Card title="Stream Pump AMM Data" icon="chart-line" href="/docs/es/laserstream/guides/stream-pump-amm-data">
    Ejemplo del mundo real: monitorea transacciones de Pump.fun AMM.
  </Card>

  <Card title="Decoding Transaction Data" icon="binary" href="/docs/es/laserstream/guides/decoding-transaction-data">
    Analiza las cargas útiles binarias de las transacciones para convertirlas en transacciones de Solana legibles.
  </Card>

  <Card title="Yellowstone protocol reference" icon="book" href="/docs/es/grpc/transaction-monitoring">
    El mismo flujo de trabajo con el protocolo Yellowstone gRPC sin procesar.
  </Card>
</CardGroup>
