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

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

Prácticas recomendadas y patrones para agentes que usan el [SDK de Rust de Helius](https://github.com/helius-labs/helius-rust-sdk). Para ver la instalación y los primeros pasos, consulta la [descripción general](/docs/es/agents/rust-sdk).

## Recomendaciones para agentes

### Usa `get_transactions_for_address` en lugar de una búsqueda de dos pasos

`get_transactions_for_address` combina la búsqueda de firmas y la obtención de transacciones en una sola llamada con filtrado del lado del servidor.

```rust theme={"system"}
// GOOD: Single call, server-side filtering
let txs = helius.rpc().get_transactions_for_address(
    "address".to_string(),
    GetTransactionsForAddressOptions {
        transaction_details: Some(TransactionDetails::Full),
        limit: Some(100),
        filters: Some(GetTransactionsFilters {
            token_accounts: Some(TokenAccountsFilter::BalanceChanged),
            ..Default::default()
        }),
        ..Default::default()
    },
).await?;

// BAD: Two calls, client-side filtering
let sigs = helius.connection().get_signatures_for_address(&address)?;
```

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

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

```rust theme={"system"}
let sig = helius.send_smart_transaction(SmartTransactionConfig {
    create_config: CreateSmartTransactionConfig {
        instructions: vec![your_instruction],
        signers: vec![wallet_signer],
        priority_fee_cap: Some(100_000),
        cu_buffer_multiplier: Some(1.1),
        ..Default::default()
    },
    ..Default::default()
}).await?;
```

### Usa Helius Sender para una latencia ultrabaja

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

```rust theme={"system"}
let sig = helius.send_smart_transaction_with_sender(
    SmartTransactionConfig {
        create_config: CreateSmartTransactionConfig {
            instructions: vec![your_instruction],
            signers: vec![wallet_signer],
            ..Default::default()
        },
        ..Default::default()
    },
    SenderSendOptions {
        region: "US_EAST".to_string(),    // Default, US_SLC, US_EAST, EU_WEST, EU_CENTRAL, EU_NORTH, AP_SINGAPORE, AP_TOKYO
        swqos_only: false,                // true = SWQOS only (lower tip), false = Dual (SWQOS + Jito)
        poll_timeout_ms: 60_000,
        poll_interval_ms: 2_000,
    },
).await?;
```

### Usa `get_asset_batch` para varios activos

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

```rust theme={"system"}
// GOOD: Single request
let assets = helius.rpc().get_asset_batch(GetAssetBatch {
    ids: vec!["mint1".to_string(), "mint2".to_string(), "mint3".to_string()],
    ..Default::default()
}).await?;

// BAD: N requests
for id in mints {
    let asset = helius.rpc().get_asset(GetAsset { id, ..Default::default() }).await?;
}
```

### Usa webhooks en lugar de sondeo

No consultes `get_transactions_for_address` dentro de un bucle. Usa webhooks para las notificaciones entre servidores.

```rust theme={"system"}
let webhook = helius.create_webhook(CreateWebhookRequest {
    webhook_url: "https://your-server.com/webhook".to_string(),
    webhook_type: WebhookType::Enhanced,
    transaction_types: vec![TransactionType::Transfer, TransactionType::NftSale, TransactionType::Swap],
    account_addresses: vec!["address_to_monitor".to_string()],
    auth_header: Some("Bearer your-secret".to_string()),
    ..Default::default()
}).await?;
```

## Paginación

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

```rust theme={"system"}
// get_transactions_for_address uses pagination_token
let mut pagination_token: Option<String> = None;
let mut all_txs = Vec::new();
loop {
    let result = helius.rpc().get_transactions_for_address(
        "address".to_string(),
        GetTransactionsForAddressOptions {
            limit: Some(100),
            pagination_token: pagination_token.clone(),
            ..Default::default()
        },
    ).await?;
    all_txs.extend(result.data);
    pagination_token = result.pagination_token;
    if pagination_token.is_none() { break; }
}

// Or use auto-paginating variants:
let all_accounts = helius.rpc().get_all_program_accounts(
    program_id.to_string(),
    GetProgramAccountsV2Config::default(),
).await?;
```

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

```rust theme={"system"}
let mut page = 1;
let mut all_assets = Vec::new();
loop {
    let result = helius.rpc().get_assets_by_owner(GetAssetsByOwner {
        owner_address: "...".to_string(),
        page,
        limit: Some(1000),
        ..Default::default()
    }).await?;
    let count = result.items.len();
    all_assets.extend(result.items);
    if count < 1000 { break; }
    page += 1;
}
```

## Filtro `token_accounts`

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

| Valor            | Comportamiento                                                       | Cuándo usarlo                                                                                            |
| ---------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `None`           | Solo 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)                         |

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

`changed_since_slot` devuelve solo las cuentas modificadas después de un slot determinado. Es útil para flujos de trabajo de sincronización o indexación. Es compatible con `get_program_accounts_v2`, `get_token_accounts_by_owner_v2`, `get_account_info`, `get_multiple_accounts`, `get_program_accounts` y `get_token_accounts_by_owner`.

```rust theme={"system"}
// First fetch: get all accounts
let baseline = helius.rpc().get_program_accounts_v2(
    program_id.to_string(),
    GetProgramAccountsV2Config { limit: Some(10_000), ..Default::default() },
).await?;
let last_slot = current_slot;

// Later: only get accounts that changed since your last fetch
let updates = helius.rpc().get_program_accounts_v2(
    program_id.to_string(),
    GetProgramAccountsV2Config {
        limit: Some(10_000),
        changed_since_slot: Some(last_slot),
        ..Default::default()
    },
).await?;
```

## Errores comunes

1. **`transaction_details: Some(TransactionDetails::Full)` no es el valor predeterminado**: de forma predeterminada, `get_transactions_for_address` solo devuelve firmas. Configura `TransactionDetails::Full` para obtener los datos completos de las transacciones.

2. **No agregues instrucciones ComputeBudget con `send_smart_transaction`**: el SDK las agrega automáticamente. Si agregas tus propias instrucciones, se produce un error `HeliusError::InvalidInput`.

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

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

5. **`async_connection()` requiere `new_async` o `HeliusBuilder`**: llamar a `helius.async_connection()` en un cliente creado con `Helius::new()` devuelve `Err(HeliusError::ClientNotInitialized)`.

6. **`get_asset` devuelve `Option<Asset>`**: una respuesta correcta aún puede ser `None` si el activo no existe. Maneja `Option` de forma explícita.

7. **Las propinas de Sender son obligatorias**: `send_smart_transaction_with_sender` determina y agrega automáticamente las propinas. El mínimo es de 0.0002 SOL (modo dual) o 0.000005 SOL (solo SWQOS).

8. **Indicadores de características de TLS**: el crate usa `native-tls` de forma predeterminada. Usa `features = ["rustls"]` (e `default-features = false`) para TLS implementado completamente en Rust cuando OpenSSL no esté disponible.

9. **Establece la versión máxima de transacción compatible en 1 al obtener transacciones.** De lo contrario, `get_transaction`, `get_block` e `get_transactions_for_address` con `TransactionDetails::Full` fallan con el error `-32015` en las transacciones v1. En las transacciones v1, la tarifa de prioridad es el `transactionConfig.priorityFee` del mensaje, un total expresado en lamports; no hay instrucciones ComputeBudget que examinar. Consulta [Compatibilidad con transacciones v1](/docs/es/rpc/transaction-v1).

## Manejo de errores y reintentos

El SDK proporciona variantes de error con tipo mediante la enumeración `HeliusError`, por lo que puedes compararlas directamente:

```rust theme={"system"}
use helius::error::{HeliusError, Result};

match helius.rpc().get_asset(request).await {
    Ok(asset) => { /* success */ }
    Err(HeliusError::Unauthorized { .. }) => { /* 401: invalid or missing API key */ }
    Err(HeliusError::RateLimitExceeded { .. }) => { /* 429: too many requests or out of credits */ }
    Err(HeliusError::InternalError { .. }) => { /* 5xx: server error, retry with backoff */ }
    Err(HeliusError::NotFound { .. }) => { /* 404: resource not found */ }
    Err(HeliusError::BadRequest { .. }) => { /* 400: malformed request */ }
    Err(HeliusError::Timeout { .. }) => { /* transaction confirmation timed out */ }
    Err(e) => { /* other errors: Network, SerdeJson, etc. */ }
}
```

### Estrategia de reintentos

Reintenta cuando se produzcan `RateLimitExceeded` e `InternalError` con espera exponencial:

```rust theme={"system"}
async fn with_retry<T, F, Fut>(f: F, max_retries: u32) -> Result<T>
where
    F: Fn() -> Fut,
    Fut: std::future::Future<Output = Result<T>>,
{
    for attempt in 0..=max_retries {
        match f().await {
            Ok(val) => return Ok(val),
            Err(HeliusError::RateLimitExceeded { .. })
            | Err(HeliusError::InternalError { .. }) if attempt < max_retries => {
                tokio::time::sleep(std::time::Duration::from_millis(1000 * 2u64.pow(attempt))).await;
            }
            Err(e) => return Err(e),
        }
    }
    unreachable!()
}
```

| Variante de error   | Estado HTTP | Acción                                            |
| ------------------- | ----------- | ------------------------------------------------- |
| `Unauthorized`      | 401         | Comprueba la clave de API                         |
| `RateLimitExceeded` | 429         | Espera y vuelve a intentarlo                      |
| `InternalError`     | 5xx         | Vuelve a intentarlo con espera exponencial        |
| `BadRequest`        | 400         | Corrige los parámetros de la solicitud            |
| `NotFound`          | 404         | Comprueba que el recurso exista                   |
| `Timeout`           | —           | Aumenta el tiempo de espera o vuelve a intentarlo |
