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

# Prácticas recomendadas del SDK de TypeScript

> Patrones recomendados de Solana para agentes de IA que usan el SDK de TypeScript de Helius: historial de transacciones, envíos, procesamiento por lotes, paginación y manejo de errores.

Prácticas recomendadas y patrones sugeridos para agentes que usan el [SDK de TypeScript de Helius](https://github.com/helius-labs/helius-sdk). Para instalarlo y comenzar, consulta la [descripción general](/docs/es/agents/typescript-sdk).

## Recomendaciones para agentes

### Usa `getTransactionsForAddress` en lugar de una consulta en dos pasos

`getTransactionsForAddress` combina la búsqueda de firmas y la obtención de transacciones en una sola llamada con filtrado del lado del servidor. Admite rangos de tiempo/slots, filtrado de cuentas de tokens y paginación.

```typescript theme={"system"}
// GOOD: Single call, server-side filtering
const txs = await helius.getTransactionsForAddress([
  "address",
  {
    transactionDetails: "full",
    limit: 100,
    filters: {
      tokenAccounts: "balanceChanged",
      blockTime: { gte: Math.floor(Date.now() / 1000) - 86400 },
    },
  },
]);

// BAD: Two calls, client-side filtering, no token account support
const sigs = await helius.raw.getSignaturesForAddress(address).send();
const txs = await Promise.all(sigs.map(s => helius.raw.getTransaction(s.signature).send()));
```

### Usa `sendSmartTransaction` para envíos estándar

Simula automáticamente, estima las unidades de cómputo, obtiene las comisiones de prioridad y confirma. No crees manualmente instrucciones de ComputeBudget; el SDK las agrega de forma automática.

```typescript theme={"system"}
const sig = await helius.tx.sendSmartTransaction({
  instructions: [yourInstruction],
  signers: [walletSigner],
  commitment: "confirmed",
  priorityFeeCap: 100_000,   // Optional: cap fees in microlamports/CU
  bufferPct: 0.1,            // 10% compute unit headroom (default)
});
```

### Usa Helius Sender para lograr una latencia ultrabaja

Para transacciones sensibles al tiempo (arbitraje, sniping y liquidaciones), usa `sendTransactionWithSender`. Enruta las transacciones a través de la infraestructura multirregional de Helius y Jito.

```typescript theme={"system"}
const sig = await helius.tx.sendTransactionWithSender({
  instructions: [yourInstruction],
  signers: [walletSigner],
  region: "US_EAST",          // Default, US_SLC, US_EAST, EU_WEST, EU_CENTRAL, EU_NORTH, AP_SINGAPORE, AP_TOKYO
  swqosOnly: true,            // Route through SWQOS only (lower tip requirement)
  pollTimeoutMs: 60_000,
  pollIntervalMs: 2_000,
});
```

### Usa `getAssetBatch` para varios activos

Cuando obtengas más de un activo, agrúpalos en lotes. No llames a `getAsset` dentro de un bucle.

```typescript theme={"system"}
// GOOD: Single request
const assets = await helius.getAssetBatch({
  ids: ["mint1", "mint2", "mint3"],
  options: { showFungible: true, showCollectionMetadata: true },
});

// BAD: N requests
const assets = await Promise.all(mints.map(id => helius.getAsset({ id })));
```

### Usa webhooks o WebSockets en lugar de sondeos

No sondees `getTransactionsForAddress` dentro de un bucle. Usa webhooks para notificaciones entre servidores o WebSockets para transmitir datos en tiempo real del lado del cliente.

```typescript theme={"system"}
// Webhook: server receives POST on matching transactions
const webhook = await helius.webhooks.create({
  webhookURL: "https://your-server.com/webhook",
  webhookType: "enhanced",
  transactionTypes: ["TRANSFER", "NFT_SALE", "SWAP"],
  accountAddresses: ["address_to_monitor"],
  authHeader: "Bearer your-secret",
});

// WebSocket: stream logs in real-time
const req = await helius.ws.logsNotifications({ mentions: ["address"] });
const stream = await req.subscribe({ abortSignal: controller.signal });
for await (const log of stream) {
  console.log(log);
}
```

## Paginación

El SDK usa distintas estrategias de paginación según el método.

### Basada en tokens/cursores (métodos RPC V2)

```typescript theme={"system"}
// getTransactionsForAddress uses paginationToken
let paginationToken = null;
const allTxs = [];
do {
  const result = await helius.getTransactionsForAddress([
    "address",
    { limit: 100, paginationToken },
  ]);
  allTxs.push(...result.data);
  paginationToken = result.paginationToken;
} while (paginationToken);

// getProgramAccountsV2 uses paginationKey
let paginationKey = null;
do {
  const result = await helius.getProgramAccountsV2([
    programId,
    { limit: 1000, paginationKey },
  ]);
  // process result.accounts
  paginationKey = result.paginationKey;
} while (paginationKey);
```

### Basada en páginas (API de DAS)

```typescript theme={"system"}
let page = 1;
const allAssets = [];
while (true) {
  const result = await helius.getAssetsByOwner({ ownerAddress: "...", page, limit: 1000 });
  allAssets.push(...result.items);
  if (result.items.length < 1000) break;
  page++;
}
```

## Filtro `tokenAccounts`

Al consultar `getTransactionsForAddress`, el filtro `tokenAccounts` controla si se incluye la actividad de las cuentas de tokens:

| Valor              | Comportamiento                                                       | Cuándo usarlo                                                                                            |
| ------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| omitido / `"none"` | Solo las transacciones que involucran directamente a la dirección    | Solo te interesan las transferencias de SOL y las llamadas a programas                                   |
| `"balanceChanged"` | También incluye las transacciones de tokens que modificaron un saldo | **Recomendado para la mayoría de los agentes**: muestra los envíos y las recepciones de tokens sin ruido |
| `"all"`            | Incluye todas las transacciones de las cuentas de tokens             | Necesitas la actividad completa de los tokens (puede devolver muchos resultados)                         |

## `changedSinceSlot`: obtención incremental de cuentas

`changedSinceSlot` devuelve únicamente las cuentas modificadas después de un slot determinado. Resulta útil para flujos de trabajo de sincronización o indexación. Es compatible con `getProgramAccountsV2`, `getTokenAccountsByOwnerV2`, `getAccountInfo`, `getMultipleAccounts`, `getProgramAccounts` e `getTokenAccountsByOwner`.

```typescript theme={"system"}
// First fetch: get all accounts
const baseline = await helius.getProgramAccountsV2([programId, { limit: 10_000 }]);
const lastSlot = currentSlot;

// Later: only get accounts that changed since your last fetch
const updates = await helius.getProgramAccountsV2([
  programId,
  { limit: 10_000, changedSinceSlot: lastSlot },
]);
```

## Errores comunes

1. **`transactionDetails: "full"` no es el valor predeterminado**: de forma predeterminada, `getTransactionsForAddress` solo devuelve firmas. Configura `transactionDetails: "full"` para obtener los datos completos de las transacciones.

2. **No agregues instrucciones de ComputeBudget con `sendSmartTransaction`**: el SDK las agrega automáticamente. Si agregas tus propias instrucciones, se duplicarán y la transacción fallará.

3. **Las comisiones de prioridad se expresan en microlamports por unidad de cómputo**: no en lamports. Los valores de `getPriorityFeeEstimate` ya están en la unidad correcta para `SetComputeUnitPrice`.

4. **La paginación de DAS comienza en 1**: `page: 1` es la primera página, no `page: 0`.

5. **`blockTime` usa segundos Unix, no milisegundos**: usa `Math.floor(Date.now() / 1000)` cuando filtres por `blockTime`.

6. **`getAsset` oculta los tokens fungibles de forma predeterminada**: pasa `options: { showFungible: true }` para incluirlos.

7. **Los flujos de WebSocket necesitan limpieza**: usa siempre una señal de AbortController y llama a `helius.ws.close()` cuando termines para evitar fugas de conexiones.

8. **Configura `maxSupportedTransactionVersion: 1` al obtener transacciones.** De lo contrario, `getTransaction`, `getBlock` e `getTransactionsForAddress` con `transactionDetails: "full"` fallan con el error `-32015` en las transacciones v1. En las transacciones v1, la comisión de prioridad es `message.transactionConfig.priorityFee`, un total expresado en lamports; no hay instrucciones de ComputeBudget que analizar. Consulta [Compatibilidad con transacciones v1](/docs/es/rpc/transaction-v1).

## Manejo de errores y reintentos

El SDK lanza objetos nativos `Error` con el código de estado HTTP integrado en la cadena del mensaje (por ejemplo, `"API error (429): ..."`). El objeto de error no tiene una propiedad `.status`, por lo que debes analizar el mensaje para detectar el estado.

```typescript theme={"system"}
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const msg = error instanceof Error ? error.message : "";
      const status = msg.match(/\b(\d{3})\b/)?.[1];
      const retryable = status === "429" || (status && status.startsWith("5"));
      if (!retryable || attempt === maxRetries) throw error;
      await new Promise(r => setTimeout(r, 1000 * 2 ** attempt));
    }
  }
  throw new Error("Unreachable");
}
```

| Estado | Significado                                         | Acción                                     |
| ------ | --------------------------------------------------- | ------------------------------------------ |
| 401    | La clave de API no es válida o falta                | Comprueba la clave de API                  |
| 429    | Límite de solicitudes alcanzado o créditos agotados | Espera y vuelve a intentarlo               |
| 5xx    | Error del servidor                                  | Vuelve a intentarlo con espera exponencial |
