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

# Praktik Terbaik SDK TypeScript

> Pola Solana yang direkomendasikan untuk agen AI yang menggunakan Helius TypeScript SDK — riwayat transaksi, pengiriman, batching, paginasi, dan penanganan kesalahan.

Praktik terbaik dan pola yang direkomendasikan untuk agen yang menggunakan [Helius TypeScript SDK](https://github.com/helius-labs/helius-sdk). Untuk instalasi dan langkah awal, lihat [ringkasan](/docs/id/agents/typescript-sdk).

## Rekomendasi untuk Agen

### Gunakan `getTransactionsForAddress` alih-alih pencarian dua langkah

`getTransactionsForAddress` menggabungkan pencarian tanda tangan dan pengambilan transaksi dalam satu panggilan dengan pemfilteran di sisi server. Fitur ini mendukung rentang waktu/slot, pemfilteran akun token, dan paginasi.

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

### Gunakan `sendSmartTransaction` untuk pengiriman standar

Metode ini secara otomatis menjalankan simulasi, memperkirakan unit komputasi, mengambil biaya prioritas, dan melakukan konfirmasi. Jangan membuat instruksi ComputeBudget secara manual — SDK menambahkannya secara otomatis.

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

### Gunakan Helius Sender untuk latensi sangat rendah

Untuk transaksi yang sensitif terhadap waktu (arbitrase, sniping, likuidasi), gunakan `sendTransactionWithSender`. Metode ini merutekan transaksi melalui infrastruktur multiwilayah Helius dan 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,
});
```

### Gunakan `getAssetBatch` untuk beberapa aset

Saat mengambil lebih dari satu aset, kelompokkan aset tersebut dalam satu batch. Jangan panggil `getAsset` dalam perulangan.

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

### Gunakan webhook atau WebSocket alih-alih polling

Jangan lakukan polling terhadap `getTransactionsForAddress` dalam perulangan. Gunakan webhook untuk notifikasi antarserver atau WebSocket untuk streaming sisi klien secara real-time.

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

## Paginasi

SDK menggunakan strategi paginasi yang berbeda, tergantung pada metodenya.

### Berbasis Token/Kursor (Metode 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);
```

### Berbasis Halaman (DAS API)

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

## Filter `tokenAccounts`

Saat membuat kueri terhadap `getTransactionsForAddress`, filter `tokenAccounts` mengatur apakah aktivitas akun token disertakan:

| Nilai                  | Perilaku                                                        | Gunakan Saat                                                                                         |
| ---------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| dihilangkan / `"none"` | Hanya transaksi yang secara langsung melibatkan alamat tersebut | Anda hanya memerlukan transfer SOL dan panggilan program                                             |
| `"balanceChanged"`     | Juga menyertakan transaksi token yang mengubah saldo            | **Direkomendasikan untuk sebagian besar agen** — menampilkan pengiriman/penerimaan token tanpa derau |
| `"all"`                | Menyertakan semua transaksi akun token                          | Anda memerlukan aktivitas token lengkap (dapat memberikan banyak hasil)                              |

## `changedSinceSlot` — Pengambilan Akun Inkremental

`changedSinceSlot` hanya mengembalikan akun yang diubah setelah slot tertentu. Berguna untuk alur kerja sinkronisasi atau pengindeksan. Didukung oleh `getProgramAccountsV2`, `getTokenAccountsByOwnerV2`, `getAccountInfo`, `getMultipleAccounts`, `getProgramAccounts`, dan `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 },
]);
```

## Kesalahan Umum

1. **`transactionDetails: "full"` bukan nilai default** — Secara default, `getTransactionsForAddress` hanya mengembalikan tanda tangan. Atur `transactionDetails: "full"` untuk mendapatkan data transaksi lengkap.

2. **Jangan tambahkan instruksi ComputeBudget dengan `sendSmartTransaction`** — SDK menambahkannya secara otomatis. Menambahkan instruksi Anda sendiri menyebabkan instruksi duplikat dan kegagalan transaksi.

3. **Biaya prioritas dinyatakan dalam microlamport per unit komputasi** — Bukan lamport. Nilai dari `getPriorityFeeEstimate` sudah menggunakan unit yang tepat untuk `SetComputeUnitPrice`.

4. **Paginasi DAS dimulai dari indeks 1** — `page: 1` adalah halaman pertama, bukan `page: 0`.

5. **`blockTime` menggunakan detik Unix, bukan milidetik** — Gunakan `Math.floor(Date.now() / 1000)` saat memfilter berdasarkan `blockTime`.

6. **`getAsset` menyembunyikan token fungibel secara default** — Teruskan `options: { showFungible: true }` untuk menyertakannya.

7. **Stream WebSocket perlu dibersihkan** — Selalu gunakan sinyal AbortController dan panggil `helius.ws.close()` setelah selesai untuk menghindari kebocoran koneksi.

8. **Atur `maxSupportedTransactionVersion: 1` saat mengambil transaksi.** Jika tidak, `getTransaction`, `getBlock`, dan `getTransactionsForAddress` dengan `transactionDetails: "full"` akan gagal dengan kesalahan `-32015` pada transaksi v1. Pada transaksi v1, biaya prioritas adalah `message.transactionConfig.priorityFee`, yaitu jumlah total dalam lamport; tidak ada instruksi ComputeBudget yang perlu dipindai. Lihat [Dukungan transaksi v1](/docs/id/rpc/transaction-v1).

## Penanganan Kesalahan dan Percobaan Ulang

SDK melempar objek `Error` native dengan kode status HTTP yang disematkan dalam string pesan (misalnya, `"API error (429): ..."`). Objek kesalahan tidak memiliki properti `.status`, sehingga pendeteksian status memerlukan penguraian pesan.

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

| Status | Arti                                          | Tindakan                           |
| ------ | --------------------------------------------- | ---------------------------------- |
| 401    | Kunci API tidak valid atau tidak tersedia     | Periksa kunci API                  |
| 429    | Terkena pembatasan laju atau kehabisan kredit | Tingkatkan jeda dan coba lagi      |
| 5xx    | Kesalahan server                              | Coba lagi dengan jeda eksponensial |
