> ## 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ách truy xuất lịch sử giao dịch của ví Solana

> Lấy toàn bộ lịch sử giao dịch của bất kỳ ví Solana nào cùng các thay đổi số dư trong từng giao dịch — dành cho trình theo dõi danh mục đầu tư, kế toán và phân tích.

<Note>
  Wallet API đang ở giai đoạn Beta. Các điểm cuối và định dạng phản hồi có thể thay đổi.
</Note>

## Tổng quan

Điểm cuối Lịch sử giao dịch truy xuất toàn bộ lịch sử giao dịch của ví Solana bằng Enhanced Transactions API. Điểm cuối này trả về các giao dịch đã phân tích cú pháp, dễ đọc cùng với những thay đổi số dư trong từng giao dịch, theo thứ tự thời gian đảo ngược (mới nhất trước).

Điểm cuối trả về tối đa 100 giao dịch cho mỗi yêu cầu, vì vậy bạn phải phân trang theo cách thủ công. Sử dụng tham số `before` với `pagination.nextCursor` để truy xuất trang tiếp theo và đọc `pagination.hasMore` để biết khi nào còn kết quả khác. Mỗi yêu cầu là một lệnh gọi API và có chi phí 100 tín dụng.

Tham số `tokenAccounts` kiểm soát việc có bao gồm các giao dịch liên quan đến tài khoản token thuộc sở hữu của ví hay không:

* `balanceChanged` (khuyến nghị): bao gồm các giao dịch làm thay đổi số dư tài khoản token và lọc thư rác.
* `none`: chỉ gồm các tương tác trực tiếp với ví.
* `all`: tất cả giao dịch của tài khoản token, bao gồm cả thư rác.

<Warning>
  Bộ lọc `tokenAccounts` dựa vào trường `owner` trong siêu dữ liệu số dư token. Trường này chưa có trước slot 111.491.819 (khoảng tháng 12 năm 2022). Các giao dịch liên quan đến tài khoản token hoạt động trước slot này có thể bị thiếu. Xem [hướng dẫn getTransactionsForAddress](/docs/vi/rpc/gettransactionsforaddress#hạn-chế-và-trường-hợp-biên) để biết giải pháp thay thế.
</Warning>

## Khi nào nên sử dụng

Sử dụng Transaction History API khi cần:

* **Hiển thị bảng tin giao dịch**: cho người dùng xem toàn bộ lịch sử giao dịch của họ.
* **Tính PnL**: theo dõi lãi và lỗ trên tất cả giao dịch.
* **Thuế và kế toán**: tạo báo cáo giao dịch đầy đủ để khai thuế.
* **Phân tích danh mục đầu tư**: phân tích mô hình và hoạt động giao dịch.
* **Nhật ký kiểm toán**: duy trì hồ sơ đầy đủ về hoạt động của ví.
* **Tái dựng số dư**: tái dựng số dư hiện tại từ dữ liệu lịch sử.

## Bắt đầu nhanh

### Truy vấn lịch sử cơ bản

Lấy các giao dịch gần đây nhất cùng những thay đổi số dư:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"}
    const getTransactionHistory = async (address) => {
      const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY`;

      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const data = await response.json();

      console.log(`Found ${data.data.length} transactions`);

      // Display recent transactions
      data.data.forEach(tx => {
        const date = new Date(tx.timestamp * 1000).toLocaleString();
        const status = tx.error ? 'Failed' : 'Success';

        console.log(`\n${status} - ${date}`);
        console.log(`Signature: ${tx.signature.slice(0, 20)}...`);
        console.log(`Fee: ${tx.fee} SOL`);

        // Show balance changes
        tx.balanceChanges.forEach(change => {
          const sign = change.amount > 0 ? '+' : '';
          console.log(`  ${sign}${change.amount} ${change.mint === 'SOL' ? 'SOL' : change.mint.slice(0, 8)}...`);
        });
      });

      return data;
    };

    getTransactionHistory("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"system"}
    import requests
    from datetime import datetime

    def get_transaction_history(address: str):
        url = f"https://api.helius.xyz/v1/wallet/{address}/history"
        headers = {"X-Api-Key": "YOUR_API_KEY"}

        response = requests.get(url, headers=headers)
        response.raise_for_status()

        data = response.json()

        print(f"Found {len(data['data'])} transactions")

        # Display recent transactions
        for tx in data['data']:
            date = datetime.fromtimestamp(tx['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
            status = 'Failed' if tx.get('error') else 'Success'

            print(f"\n{status} - {date}")
            print(f"Signature: {tx['signature'][:20]}...")
            print(f"Fee: {tx['fee']} SOL")

            # Show balance changes
            for change in tx['balanceChanges']:
                sign = '+' if change['amount'] > 0 else ''
                mint_display = 'SOL' if change['mint'] == 'SOL' else change['mint'][:8] + '...'
                print(f"  {sign}{change['amount']} {mint_display}")

        return data

    get_transaction_history("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY")
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"system"}
    curl "https://api.helius.xyz/v1/wallet/86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY/history?api-key=YOUR_API_KEY"
    ```
  </Tab>
</Tabs>

### Phân trang để lấy toàn bộ lịch sử

Truy xuất tất cả giao dịch bằng cách phân trang với tham số `before`:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"}
    const getAllTransactionHistory = async (address) => {
      let allTransactions = [];
      let before = null;

      do {
        const url = before
          ? `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&before=${before}`
          : `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY`;

        const response = await fetch(url);
        const data = await response.json();

        allTransactions = allTransactions.concat(data.data);
        before = data.pagination.hasMore ? data.pagination.nextCursor : null;

        console.log(`Fetched ${allTransactions.length} transactions so far...`);

      } while (before);

      console.log(`\nTotal transactions: ${allTransactions.length}`);
      return allTransactions;
    };

    getAllTransactionHistory("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"system"}
    def get_all_transaction_history(address: str):
        all_transactions = []
        before = None

        while True:
            url = f"https://api.helius.xyz/v1/wallet/{address}/history"
            params = {"api-key": "YOUR_API_KEY"}

            if before:
                params["before"] = before

            response = requests.get(url, params=params, headers={"X-Api-Key": "YOUR_API_KEY"})
            response.raise_for_status()

            data = response.json()
            all_transactions.extend(data['data'])

            print(f"Fetched {len(all_transactions)} transactions so far...")

            if not data['pagination']['hasMore']:
                break

            before = data['pagination']['nextCursor']

        print(f"\nTotal transactions: {len(all_transactions)}")
        return all_transactions

    get_all_transaction_history("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY")
    ```
  </Tab>
</Tabs>

## Tham số truy vấn

| Tham số         | Kiểu      | Mặc định       | Mô tả                                                                                              |
| --------------- | --------- | -------------- | -------------------------------------------------------------------------------------------------- |
| `limit`         | số nguyên | 100            | Số lượng giao dịch tối đa trong mỗi yêu cầu (1-100)                                                |
| `before`        | chuỗi     | -              | Truy xuất các giao dịch trước chữ ký này (sử dụng `pagination.nextCursor` từ phản hồi trước)       |
| `after`         | chuỗi     | -              | Truy xuất các giao dịch sau chữ ký này (để phân trang theo thứ tự tăng dần)                        |
| `type`          | chuỗi     | -              | Lọc theo loại giao dịch (ví dụ: SWAP, TRANSFER, NFT\_SALE, TOKEN\_MINT)                            |
| `tokenAccounts` | chuỗi     | balanceChanged | Lọc các giao dịch liên quan đến tài khoản token: `none`, `balanceChanged` (khuyến nghị) hoặc `all` |

### Các loại giao dịch khả dụng

Tham số `type` hỗ trợ lọc theo các loại giao dịch sau:

`SWAP`, `TRANSFER`, `NFT_SALE`, `NFT_BID`, `NFT_LISTING`, `NFT_MINT`, `NFT_CANCEL_LISTING`, `TOKEN_MINT`, `BURN`, `COMPRESSED_NFT_MINT`, `COMPRESSED_NFT_TRANSFER`, `COMPRESSED_NFT_BURN`, `CREATE_STORE`, `WHITELIST_CREATOR`, `ADD_TO_WHITELIST`, `REMOVE_FROM_WHITELIST`, `AUCTION_MANAGER_CLAIM_BID`, `EMPTY_PAYMENT_ACCOUNT`, `UPDATE_PRIMARY_SALE_METADATA`, `ADD_TOKEN_TO_VAULT`, `ACTIVATE_VAULT`, `INIT_VAULT`, `INIT_BANK`, `INIT_STAKE`, `MERGE_STAKE`, `SPLIT_STAKE`, `CREATE_AUCTION_MANAGER`, `START_AUCTION`, `CREATE_AUCTION_MANAGER_V2`, `UPDATE_EXTERNAL_PRICE_ACCOUNT`, `EXECUTE_TRANSACTION`

### Ví dụ về bộ lọc

<Tabs>
  <Tab title="Filter by Type">
    ```javascript theme={"system"}
    // Get only SWAP transactions
    const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&type=SWAP`;
    ```
  </Tab>

  <Tab title="Token Accounts Filter">
    ```javascript theme={"system"}
    // Exclude spam by only including transactions that changed token balances
    const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&tokenAccounts=balanceChanged`;

    // Only show direct wallet interactions
    const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&tokenAccounts=none`;
    ```
  </Tab>

  <Tab title="Combined Filters">
    ```javascript theme={"system"}
    // Get only NFT sales that changed balances
    const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&type=NFT_SALE&tokenAccounts=balanceChanged`;
    ```
  </Tab>
</Tabs>

## Định dạng phản hồi

```json theme={"system"}
{
  "data": [
    {
      "signature": "5wHu1qwD7Jsj3xqWjdSEJmYr3Q5f5RjXqjqQJ7jqEj7jqEj7jqEj7jqEj7jqEj7jqE",
      "timestamp": 1704067200,
      "slot": 250000000,
      "fee": 0.000005,
      "feePayer": "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
      "error": null,
      "balanceChanges": [
        {
          "mint": "So11111111111111111111111111111111111111111",
          "amount": -0.05,
          "decimals": 9
        },
        {
          "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "amount": 50.0,
          "decimals": 6
        }
      ]
    }
  ],
  "pagination": {
    "hasMore": true,
    "nextCursor": "5wHu1qwD7Jsj3xqWjdSEJmYr3Q5f5RjXqjqQJ7jqEj7jqEj7jqEj7jqEj7jqEj7jqE"
  }
}
```

### Ghi chú về trường

* **`timestamp`**: số giây Unix. Có thể là `null` đối với các giao dịch rất gần đây chưa được xử lý hoàn toàn.
* **`error`**: `null` đối với giao dịch thành công; một giá trị lỗi đối với giao dịch thất bại. Giao dịch thất bại vẫn phát sinh phí.
* **`balanceChanges`**: lượng tài sản nắm giữ trong ví đã thay đổi như thế nào trong giao dịch — `amount` dương là số token đã nhận, còn `amount` âm là số token đã gửi hoặc chi tiêu.
* **`mint`** (trong `balanceChanges`): địa chỉ đúc token hoặc `"SOL"` đối với SOL gốc.
* **`amount`** (trong `balanceChanges`): **dễ đọc**, đã được chia cho `decimals` — `-0.05` có nghĩa là −0,05 SOL, không phải −0,05 lamport. Điểm cuối này không bao gồm trường `amountRaw` thô.

#### Ví dụ về thay đổi số dư

```javascript theme={"system"}
// Swap: Sold 0.05 SOL, received 5 USDC
{
  "balanceChanges": [
    { "mint": "SOL", "amount": -0.05, "decimals": 9 },
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": 5.0, "decimals": 6 }
  ]
}

// Simple transfer: Sent 10 USDC
{
  "balanceChanges": [
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": -10.0, "decimals": 6 }
  ]
}
```

## Trường hợp sử dụng

### Tính tổng khối lượng giao dịch

Cộng tất cả các khoản chuyển để tính khối lượng giao dịch:

```javascript theme={"system"}
const calculateTradingVolume = async (address, tokenMint) => {
  const transactions = await getAllTransactionHistory(address);

  let totalVolume = 0;

  transactions.forEach(tx => {
    tx.balanceChanges.forEach(change => {
      if (change.mint === tokenMint) {
        totalVolume += Math.abs(change.amount);
      }
    });
  });

  console.log(`Total ${tokenMint} volume: ${totalVolume}`);
  return totalVolume;
};

// Example: Calculate total USDC volume
calculateTradingVolume(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC
);
```

### Tạo báo cáo thuế

Tạo báo cáo giao dịch để khai thuế:

```javascript theme={"system"}
const generateTaxReport = async (address, year) => {
  const transactions = await getAllTransactionHistory(address);

  const startDate = new Date(`${year}-01-01`).getTime() / 1000;
  // Set to end of December 31st (23:59:59.999) to include all transactions from that day
  const endDate = new Date(`${year}-12-31T23:59:59.999Z`).getTime() / 1000;

  const taxableTransactions = transactions
    .filter(tx => tx.timestamp >= startDate && tx.timestamp <= endDate)
    .map(tx => ({
      date: new Date(tx.timestamp * 1000).toISOString(),
      signature: tx.signature,
      fee: tx.fee,
      balanceChanges: tx.balanceChanges,
      explorerUrl: `https://orbmarkets.io/tx/${tx.signature}`
    }));

  console.log(`Found ${taxableTransactions.length} transactions in ${year}`);

  // Export as JSON
  const report = {
    address,
    year,
    transactionCount: taxableTransactions.length,
    transactions: taxableTransactions
  };

  console.log(JSON.stringify(report, null, 2));
  return report;
};

generateTaxReport("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY", 2024);
```

### Theo dõi giao dịch thất bại

Tìm tất cả giao dịch thất bại để xác định lỗi:

```javascript theme={"system"}
const getFailedTransactions = async (address) => {
  const data = await getTransactionHistory(address);

  const failed = data.data.filter(tx => tx.error !== null);

  console.log(`Found ${failed.length} failed transactions`);

  failed.forEach(tx => {
    const date = new Date(tx.timestamp * 1000).toLocaleString();
    console.log(`\n${date}`);
    console.log(`Signature: ${tx.signature}`);
    console.log(`Error: ${tx.error}`);
    console.log(`Fee Paid: ${tx.fee} SOL`);
  });

  return failed;
};
```

### Tái dựng số dư trong quá khứ

Tính số dư tại một thời điểm cụ thể:

```javascript theme={"system"}
const getHistoricalBalance = async (address, targetTimestamp) => {
  const transactions = await getAllTransactionHistory(address);

  // Filter to transactions before target date
  const relevantTxs = transactions.filter(tx => tx.timestamp <= targetTimestamp);

  // Sum all balance changes
  const balances = {};

  relevantTxs.forEach(tx => {
    tx.balanceChanges.forEach(change => {
      if (!balances[change.mint]) {
        balances[change.mint] = 0;
      }
      balances[change.mint] += change.amount;
    });
  });

  console.log(`Historical balances as of ${new Date(targetTimestamp * 1000).toLocaleString()}:`);
  Object.entries(balances).forEach(([mint, balance]) => {
    console.log(`${mint}: ${balance}`);
  });

  return balances;
};

// Example: Get balances on Jan 1, 2024
getHistoricalBalance(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  new Date("2024-01-01").getTime() / 1000
);
```

Để lấy số dư chính xác của một token tại một thời điểm, điểm cuối [Số dư trong quá khứ](/docs/vi/wallet-api/balance-at) đọc trực tiếp số dư sau giao dịch trên chuỗi thay vì cộng các thay đổi ở phía máy khách.

### Phân tích phí giao dịch

Tính tổng phí đã trả:

```javascript theme={"system"}
const analyzeFees = async (address) => {
  const transactions = await getAllTransactionHistory(address);

  const totalFees = transactions.reduce((sum, tx) => sum + tx.fee, 0);
  const avgFee = totalFees / transactions.length;

  const successfulTxs = transactions.filter(tx => !tx.error);
  const failedTxs = transactions.filter(tx => tx.error);

  const wastedFees = failedTxs.reduce((sum, tx) => sum + tx.fee, 0);

  console.log(`Total Transactions: ${transactions.length}`);
  console.log(`Successful: ${successfulTxs.length}`);
  console.log(`Failed: ${failedTxs.length}`);
  console.log(`Total Fees Paid: ${totalFees.toFixed(6)} SOL`);
  console.log(`Average Fee: ${avgFee.toFixed(6)} SOL`);
  console.log(`Wasted on Failed Txs: ${wastedFees.toFixed(6)} SOL`);

  return {
    totalFees,
    avgFee,
    wastedFees,
    successRate: (successfulTxs.length / transactions.length) * 100
  };
};
```

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

* **Sử dụng phân trang để lấy toàn bộ lịch sử.** Một số ví có hàng trăm nghìn giao dịch; luôn phân trang khi truy xuất tất cả giao dịch.
* **Lưu dữ liệu lịch sử vào bộ nhớ đệm.** Các giao dịch trong quá khứ không bao giờ thay đổi. Hãy lưu chúng vào bộ nhớ đệm cục bộ và chỉ truy xuất giao dịch mới.
* **Xử lý giao dịch thất bại.** Kiểm tra trường `error` để phân biệt giao dịch thành công với giao dịch thất bại. Giao dịch thất bại vẫn phát sinh phí.
* **Sử dụng dấu thời gian để lọc theo ngày.** Dấu thời gian được tính bằng giây Unix. Chuyển đổi sang ngày giờ địa phương để hiển thị và lọc.

## Lỗi thường gặp

| Mã lỗi | Mô tả                             | Giải pháp                                            |
| ------ | --------------------------------- | ---------------------------------------------------- |
| 400    | Định dạng địa chỉ ví không hợp lệ | Xác minh địa chỉ là một địa chỉ Solana base58 hợp lệ |
| 401    | Thiếu hoặc khóa API không hợp lệ  | Kiểm tra để đảm bảo khóa API có trong yêu cầu        |
| 429    | Vượt quá giới hạn tốc độ          | Giảm tần suất yêu cầu hoặc nâng cấp gói dịch vụ      |

## Bước tiếp theo

<CardGroup cols={3}>
  <Card title="Token Transfers" icon="arrow-right-arrow-left" href="/docs/vi/wallet-api/transfers">
    Chế độ xem chỉ gồm các giao dịch chuyển với thông tin người gửi/người nhận — đơn giản hơn toàn bộ lịch sử.
  </Card>

  <Card title="Wallet API Overview" icon="wallet" href="/docs/vi/wallet-api/overview">
    Tất cả các điểm cuối của Wallet API và quy ước dùng chung.
  </Card>

  <Card title="API Reference" icon="code" href="/docs/vi/api-reference/wallet-api/history">
    Lược đồ yêu cầu và phản hồi cho lịch sử giao dịch.
  </Card>
</CardGroup>
