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

# Các phương pháp hay nhất cho TypeScript SDK

> Các mẫu Solana được đề xuất cho tác nhân AI sử dụng Helius TypeScript SDK — lịch sử giao dịch, gửi, xử lý theo lô, phân trang và xử lý lỗi.

Các phương pháp hay nhất và mẫu được đề xuất cho tác nhân sử dụng [Helius TypeScript SDK](https://github.com/helius-labs/helius-sdk). Để biết cách cài đặt và bắt đầu, hãy xem phần [tổng quan](/docs/vi/agents/typescript-sdk).

## Khuyến nghị cho tác nhân

### Sử dụng `getTransactionsForAddress` thay vì tra cứu hai bước

`getTransactionsForAddress` kết hợp việc tra cứu chữ ký và truy xuất giao dịch vào một lệnh gọi duy nhất có khả năng lọc phía máy chủ. Phương thức này hỗ trợ phạm vi thời gian/slot, lọc tài khoản token và phân trang.

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

### Sử dụng `sendSmartTransaction` cho các lần gửi thông thường

Phương thức này tự động mô phỏng, ước tính đơn vị tính toán, truy xuất phí ưu tiên và xác nhận. Không tạo thủ công các chỉ thị ComputeBudget — SDK sẽ tự động thêm chúng.

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

### Sử dụng Helius Sender để có độ trễ cực thấp

Đối với các giao dịch nhạy cảm về thời gian (kinh doanh chênh lệch giá, sniping, thanh lý), hãy sử dụng `sendTransactionWithSender`. Phương thức này định tuyến qua cơ sở hạ tầng đa khu vực của Helius và 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,
});
```

### Sử dụng `getAssetBatch` cho nhiều tài sản

Khi truy xuất nhiều tài sản, hãy xử lý chúng theo lô. Không gọi `getAsset` trong vòng lặp.

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

### Sử dụng webhook hoặc WebSocket thay vì thăm dò

Không thăm dò `getTransactionsForAddress` trong vòng lặp. Sử dụng webhook cho thông báo giữa các máy chủ hoặc WebSocket để truyền dữ liệu theo thời gian thực ở phía máy khách.

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

## Phân trang

SDK sử dụng các chiến lược phân trang khác nhau tùy theo phương thức.

### Dựa trên token/con trỏ (các phương thức 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);
```

### Dựa trên trang (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++;
}
```

## Bộ lọc `tokenAccounts`

Khi truy vấn `getTransactionsForAddress`, bộ lọc `tokenAccounts` kiểm soát việc có bao gồm hoạt động của tài khoản token hay không:

| Giá trị            | Hành vi                                             | Sử dụng khi                                                                                         |
| ------------------ | --------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| bỏ qua / `"none"`  | Chỉ các giao dịch liên quan trực tiếp đến địa chỉ   | Bạn chỉ quan tâm đến việc chuyển SOL và các lệnh gọi chương trình                                   |
| `"balanceChanged"` | Cũng bao gồm các giao dịch token làm thay đổi số dư | **Được đề xuất cho hầu hết tác nhân** — hiển thị hoạt động gửi/nhận token mà không có dữ liệu nhiễu |
| `"all"`            | Bao gồm tất cả giao dịch của tài khoản token        | Bạn cần toàn bộ hoạt động token (có thể trả về nhiều kết quả)                                       |

## `changedSinceSlot` — Truy xuất tài khoản tăng dần

`changedSinceSlot` chỉ trả về các tài khoản được sửa đổi sau một slot nhất định. Hữu ích cho quy trình đồng bộ hóa hoặc lập chỉ mục. Được hỗ trợ bởi `getProgramAccountsV2`, `getTokenAccountsByOwnerV2`, `getAccountInfo`, `getMultipleAccounts`, `getProgramAccounts` và `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 },
]);
```

## Các lỗi thường gặp

1. **`transactionDetails: "full"` không phải là giá trị mặc định** — Theo mặc định, `getTransactionsForAddress` chỉ trả về chữ ký. Đặt `transactionDetails: "full"` để nhận đầy đủ dữ liệu giao dịch.

2. **Không thêm các chỉ thị ComputeBudget khi sử dụng `sendSmartTransaction`** — SDK sẽ tự động thêm chúng. Việc tự thêm sẽ tạo ra các chỉ thị trùng lặp và khiến giao dịch thất bại.

3. **Phí ưu tiên được tính bằng microlamport trên mỗi đơn vị tính toán** — Không phải lamport. Các giá trị từ `getPriorityFeeEstimate` đã ở đúng đơn vị dành cho `SetComputeUnitPrice`.

4. **Phân trang DAS được đánh số từ 1** — `page: 1` là trang đầu tiên, không phải `page: 0`.

5. **`blockTime` là số giây Unix, không phải mili giây** — Sử dụng `Math.floor(Date.now() / 1000)` khi lọc theo `blockTime`.

6. **`getAsset` ẩn các token có thể thay thế theo mặc định** — Truyền `options: { showFungible: true }` để bao gồm chúng.

7. **Các luồng WebSocket cần được dọn dẹp** — Luôn sử dụng tín hiệu AbortController và gọi `helius.ws.close()` khi hoàn tất để tránh rò rỉ kết nối.

8. **Đặt `maxSupportedTransactionVersion: 1` khi truy xuất giao dịch.** Nếu không, `getTransaction`, `getBlock` và `getTransactionsForAddress` với `transactionDetails: "full"` sẽ thất bại với lỗi `-32015` đối với giao dịch v1. Trên giao dịch v1, phí ưu tiên là `message.transactionConfig.priorityFee`, tức tổng số tính bằng lamport; không có chỉ thị ComputeBudget nào để quét. Xem [Hỗ trợ giao dịch v1](/docs/vi/rpc/transaction-v1).

## Xử lý lỗi và thử lại

SDK đưa ra các đối tượng `Error` gốc với mã trạng thái HTTP được nhúng trong chuỗi thông báo (ví dụ: `"API error (429): ..."`). Đối tượng lỗi không có thuộc tính `.status`, vì vậy việc phát hiện trạng thái yêu cầu phân tích thông báo.

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

| Trạng thái | Ý nghĩa                              | Hành động                                       |
| ---------- | ------------------------------------ | ----------------------------------------------- |
| 401        | API key không hợp lệ hoặc bị thiếu   | Kiểm tra API key                                |
| 429        | Bị giới hạn tốc độ hoặc hết tín dụng | Chờ lâu hơn rồi thử lại                         |
| 5xx        | Lỗi máy chủ                          | Thử lại với thời gian chờ tăng theo cấp số nhân |
