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

# getTransfersByAddress 概览与教程

> 通过 mint、时间、金额和交易对方过滤条件，查询 Solana 地址的人类可读的代币和原生 SOL 转账对象。

## 概述

[`getTransfersByAddress`](/zh/api-reference/rpc/http/gettransfersbyaddress) 是一个 Helius 独有的 RPC 方法，用于返回钱包地址的解析、可读的代币和本地 SOL 转账对象。它不属于标准 Solana RPC。

它专注于转账活动，因此返回简明的转账记录而非完整的交易数据载荷。每条记录都经过标准化处理，包含解析的所有者和代币账户、发行、原始金额、小数、UI 金额、指令位置和确认状态，从而无需重新实现 Solana 代币解析即可对余额变动进行调和。

此方法需要 [开发者计划](/zh/billing/plans) 或更高版本，每次请求需耗费 10 个积分。

<CardGroup cols={2}>
  <Card title="解析的转账对象" icon="arrow-right-arrow-left">
    返回包含解析账户、金额、小数和转账类型的人类可读转账记录。
  </Card>

  <Card title="调和就绪" icon="scale-balanced">
    模型化 SOL、WSOL、Token-2022 费用、发行、销毁和账户所有者变更，以便准确调和余额。
  </Card>

  <Card title="发行、时间和金额过滤器" icon="filter">
    可以通过发行地址、区块时间范围或原始金额范围来缩小转账历史。
  </Card>

  <Card title="交易对手过滤器" icon="users">
    通过 `with` 和 `direction` 按发送者或接收者过滤转账。
  </Card>
</CardGroup>

## 何时使用

在需要以下情况时使用 `getTransfersByAddress`：

* 支付或转账监控的钱包转账历史
* 投资组合活动和代币流动分析
* 可以信赖的账本和会计对账余额
* 特定交易对手的转账报告（谁发送或接收了什么）
* 标准化的 SOL/WSOL、Token-2022 费用、发行和燃烧处理，不需要编写解析器

当需要完整交易数据、仅限签名的历史或非转账活动时，使用 [`getTransactionsForAddress`](/zh/rpc/gettransactionsforaddress)。一种常见模式是通过此处的转账记录分页，然后使用批量 [`getTransaction`](/zh/api-reference/rpc/http/gettransaction) 调用获取基础完整交易（参见[获取转账行的完整交易](#fetch-full-transactions-for-transfer-rows)）。

## 精确性和对账

`getTransfersByAddress` 为需要可靠的分类账、支付跟踪、投资组合活动和余额对账的应用构建。API 返回的是规范化的转账对象，而不是返回原始交易有效负载并将每个极端案例留给你的解析器处理。

响应明确地建模了通常使 Solana 历史难以对账的转账案例：

* 标准 SPL 代币和原生 SOL 转账。
* Token-2022 转账附带扣留费用，表现为普通的 `transfer` 行，具有单独的费用字段。
* 铸造和销毁，表现为具有 `null` 发送者或接收者的转账。
* SOL 的包装和展开行为，默认模式设计为避免嘈杂的生命周期行。
* 通过 SetAuthority 更改代币账户所有者。
* Token-2022 扣留费用的提取。
* 中介账户流动，返回为基础转账记录而不是被合并为猜测的净移动。

对于支持的可见转账事件，这使您可以在不重新实现 Solana 代币解析逻辑的情况下对余额进行对账。已知的排除项，例如仅从余额变化推断的隐藏 SOL 流动，在[限制](#limitations)中指出。

## 快速开始

```javascript theme={"system"}
const response = await fetch("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "1",
    method: "getTransfersByAddress",
    params: ["86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"]
  })
});

const data = await response.json();
console.log(data.result.data);
```

## 请求参数

传递钱包所有者地址，而不是关联的代币账户 (ATA)。API 会查找由该钱包拥有的代币账户的转账活动。

<ParamField body="address" type="string" required>
  Base58 编码的所有者钱包地址，用于查询转账。传递钱包所有者地址，而不是关联的代币账户 (ATA)。
</ParamField>

<ParamField body="config" type="object">
  可选的配置对象，用于过滤、分页、承诺、排序和 SOL/WSOL 行为。
</ParamField>

<ParamField body="with" type="string">
  通过对手地址进行过滤。仅返回与该地址有关的转账。
</ParamField>

<ParamField body="direction" type="string" default="any">
  按相对于`address`的转账方向进行筛选。

  * `in`：由`address`接收的转账
  * `out`：由`address`发出的转账
  * `any`：传入和传出的转账
</ParamField>

<ParamField body="mint" type="string">
  按令牌mint地址筛选。使用`So11111111111111111111111111111111111111111`表示本机SOL，`So11111111111111111111111111111111111111112`表示WSOL。
</ParamField>

<ParamField body="solMode" type="string" default="merged">
  控制本机SOL和WSOL的表示方式。

  * `merged`：WSOL被视为本机SOL。包装和打开周期行被排除，WSOL铸造值被重写为本机SOL铸造。
  * `separate`：WSOL保留为不同的铸造，并包括包装和打开周期行。
</ParamField>

<ParamField body="filters" type="object">
  额度、区块时间和插槽的其他筛选器。
</ParamField>

<ParamField body="limit" type="number" default="100">
  返回的最大转账数。范围：1到100。
</ParamField>

<ParamField body="paginationToken" type="string">
  用于分页的上一个响应的光标。
</ParamField>

<ParamField body="commitment" type="string" default="finalized">
  数据承诺级别。

  * `finalized`
  * `confirmed`
</ParamField>

<ParamField body="minContextSlot" type="number">
  请求可评估的最小插槽
</ParamField>

<ParamField body="sortOrder" type="string" default="desc">
  结果排序。

  * `desc`：最新最先
  * `asc`：最旧最先
</ParamField>

## 响应

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "data": [
      {
        "signature": "5GEX7Q3X5Q8yJGbKYoR7mtzQmG8tpoEwzjPgqVmn3y5xg3yKwqXcDdN5YVcc9V6vA4TuH5iM6FHRVhTxvz4AX2zG",
        "slot": 315073428,
        "blockTime": 1736159420,
        "type": "transfer",
        "fromUserAccount": "7hPhaUpydpvm8wtiS3k4LPZKUmivQRs7YQmpE1hFshHx",
        "toUserAccount": "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
        "fromTokenAccount": "HcvK3EJ74iM9g11cUgsaPvLSrhCvCwcrWxBNd87LsC1x",
        "toTokenAccount": "CBcYniR9G9CN3zGMnwNE4SWbqkYWvCFVreEob9xHnQCY",
        "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "amount": "2500000",
        "decimals": 6,
        "uiAmount": "2.5",
        "confirmationStatus": "finalized",
        "transactionIdx": 35,
        "instructionIdx": 1,
        "innerInstructionIdx": 0
      }
    ],
    "paginationToken": "315073428:35:1:0:splTransfer"
  }
}
```

### 响应字段详情

* `fromUserAccount`和`toUserAccount`始终存在。当一方不存在时，值为`null`。
* `fromTokenAccount`和`toTokenAccount`仅在标记账户端点对行有意义时包含。对于本机SOL转账，它们完全被省略。
* 铸造转账是单方面的：`fromUserAccount`为`null`，它们只能作为接收者的传入转账返回。
* 燃烧转账是单方面的：`toUserAccount`为`null`，它们只能作为燃烧所有者的传出转账返回。

## 过滤器

使用比较过滤器进行数值范围查询。所有比较字段都是可选的且可以组合使用。

```json theme={"system"}
{
  "gt": 1000000,
  "gte": 1000000,
  "lt": 1000000000,
  "lte": 1000000000
}
```

| 过滤器         | 类型                 | 描述              |
| ----------- | ------------------ | --------------- |
| `amount`    | `ComparisonFilter` | 原始转账金额，不是UI金额。  |
| `blockTime` | `ComparisonFilter` | 区块时间戳，单位为Unix秒。 |
| `slot`      | `ComparisonFilter` | 槽号。             |

## 转账类型

`type`字段标识每一行代表的转账行为。

| 类型                    | 描述                                                     | `fromUserAccount` | `toUserAccount`   |
| --------------------- | ------------------------------------------------------ | ----------------- | ----------------- |
| `transfer`            | 两个钱包之间的标准代币或SOL转账。                                     | 发送者               | 接收者               |
| `mint`                | 新代币铸造到某个钱包。                                            | `null`            | 接收者               |
| `burn`                | 代币被永久销毁。                                               | 发送者               | `null`            |
| `wrap`                | 将SOL包装成WSOL。默认在`solMode: "merged"`中排除。                 | `null`            | 拥有者               |
| `unwrap`              | WSOL解包装回本地SOL，或从关闭代币账户中恢复租金。默认在`solMode: "merged"`中排除。 | 拥有者               | `null`或lamport目的地 |
| `changeOwner`         | 使用SetAuthority更改代币账户所有权。                               | 原所有者              | 新所有者              |
| `withdrawWithheldFee` | 从铸币或账户中收取的Token-2022扣留费用。                              | `null`            | 费用接收者             |

### 转账类型和指令

| 转账类型                  | 涵盖的指令                                                                                                                                                                                                                   | 默认可见性                  |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `transfer`            | `SystemProgram::Transfer`, `SystemProgram::TransferWithSeed`, `SystemProgram::WithdrawNonceAccount`, `SystemProgram::CreateAccount`, `SystemProgram::CreateAccountWithSeed`, `SystemProgram::CreateAccountAllowPrefund` | 始终                     |
| `transfer`            | `Token::Transfer`, `Token::TransferChecked`, `Token-2022::Transfer`, `Token-2022::TransferChecked`                                                                                                                      | 始终                     |
| `transfer`            | `Token-2022::TransferCheckedWithFee`, with `feeAmount` and `feeUiAmount` fields                                                                                                                                         | 始终                     |
| `mint`                | `Token::MintTo`, `Token::MintToChecked`                                                                                                                                                                                 | 始终                     |
| `burn`                | `Token::Burn`, `Token::BurnChecked`                                                                                                                                                                                     | 始终                     |
| `wrap`                | `Token::SyncNative`, `Token::InitializeAccount`, `Token::InitializeAccount2`, `Token::InitializeAccount3`用于WSOL生命周期处理时                                                                                                  | 仅`solMode: "separate"` |
| `unwrap`              | `Token::CloseAccount`在余额大于零的WSOL上                                                                                                                                                                                       | 仅`solMode: "separate"` |
| `unwrap`              | `Token::CloseAccount`非WSOL代币账户的租金恢复，或零代币余额的WSOL账户                                                                                                                                                                       | 仅`solMode: "separate"` |
| `changeOwner`         | `Token::SetAuthority(AccountOwner)`                                                                                                                                                                                     | 始终                     |
| `withdrawWithheldFee` | `Token-2022::WithdrawWithheldTokensFromMint`, `Token-2022::WithdrawWithheldTokensFromAccounts`                                                                                                                          | 始终                     |

## SOL 和 wSOL 行为

SOL 在 Solana 上以两种形式存在，这两种形式通常在用户实际活动中同时出现：

* **原生 SOL** 是链的原生资产。它以 lamports 形式直接存在于钱包或账户中。一个 SOL 是 1,000,000,000 lamports。
* **封装 SOL （WSOL，通常写作 wSOL）** 是 SOL 的 SPL 代币表示。它使用 WSOL 铸币 `So11111111111111111111111111111111111111112` 并像 USDC 或任何其他 SPL 代币一样存在于一个代币账户中。

当需要 SOL 像 SPL 代币一样运作时，用户和应用程序通常会封装 SOL，通常用于 DeFi、交换、基于代币账户的会计或仅接受 SPL 代币的程序接口。封装通常使用原生 SOL 为一个代币账户提供资金，并将其同步为 WSOL。拆封则会关闭 WSOL 代币账户，并将 SOL 返回到一个 lamport 目的地。

这种生命周期可能会造成混乱的历史记录，如果你试图回答一个简单的问题，比如“有多少 SOL 在这个钱包和另一个人之间移动了？”封装或拆封通常会在同一所有者控制的账户之间移动 SOL。如果这些生命周期行被默认显示为普通转账，应用程序可能会重复计算活动或将内部记账显示为外部支付。

默认情况下，`getTransfersByAddress` 使用 `solMode: "merged"`。在这种模式下：

* 当通过 `So11111111111111111111111111111111111111111` 查询时，原生 SOL 和 WSOL 被视为一个 SOL 资产。
* WSOL 转账行被归一化为原生 SOL 铸币，以便 SOL 计账记录更易于调整。
* 封装和拆封的生命周期行被排除，因为它们通常代表同一所有者控制的账户之间的移动，而不是对其他用户的支付。
* SOL 和 WSOL 在不同所有者之间的转账仍然被表示为转账。
* 从 `CloseAccount` 恢复的租金在返回关闭账户生命周期行时被表示为一个原生 SOL `unwrap` 行。

在需要 WSOL 作为独立 SPL 代币铸币时或想检查包装和解包生命周期记录时使用 `solMode: "separate"`。在这种模式下，WSOL 保持铸币 `So11111111111111111111111111111111111111112`，并且包装/解包记录与 `type: "wrap"` 或 `type: "unwrap"` 一起返回。

对于 `solMode: "separate"` 中的 WSOL 账户关闭，WSOL 铸币的 `unwrap` 记录表示剩余的 WSOL 代币余额以 SOL 形式返回。从已关闭代币账户中退还的租金以单独的本机 SOL `unwrap` 行返回。

## Token-2022 转账费用

Token-2022 `TransferCheckedWithFee` 指令表示为一个传输记录，带有 `type: "transfer"`。目的地金额在 `amount` 返回；扣留的费用详细信息在 `feeAmount` 和 `feeUiAmount` 中返回。

对于带有费用的转账，来源被扣款 `amount + feeAmount`，而目的地被记入 `amount`。

```json theme={"system"}
{
  "signature": "WcvF2eFxArpqRJySzDuiP6Xw8BMprWytMpYCxk2ExBt5C1WyxWzDWcCWXW8iKQVYR9AtdQxPE1uu1SMEZvbbhdr",
  "slot": 409259683,
  "blockTime": 1774635210,
  "type": "transfer",
  "fromUserAccount": "5aZZ4duJUKiMsJN9vRsoAn4SDX7agvKu7Q3QdFWRfWze",
  "toUserAccount": "FESSvM1cVUchc13XQY8e41oeYxMnyqQNYVZwoznfJsTo",
  "fromTokenAccount": "3VUYGjYktCzNhDVymNb3Z1iHewtfPFRvdA53qSWuxdXy",
  "toTokenAccount": "51cEFBA1virMuPqHXvNGs8FKKTMqeEVKzugv1hqPU2Zc",
  "mint": "CKfatsPMUf8SkiURsDXs7eK6GWb4Jsd6UDbs7twMCWxo",
  "amount": "48650000",
  "decimals": 5,
  "uiAmount": "486.5",
  "feeAmount": "13450000",
  "feeUiAmount": "134.5",
  "confirmationStatus": "finalized",
  "transactionIdx": 1315,
  "instructionIdx": 4,
  "innerInstructionIdx": 0
}
```

## 例子

### 通过 USDC 进行过滤

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
    }
  ]
}
```

### 来自发送者的传入转账

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "with": "7hPhaUpydpvm8wtiS3k4LPZKUmivQRs7YQmpE1hFshHx",
      "direction": "in"
    }
  ]
}
```

### 金额和时间范围

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "mint": "So11111111111111111111111111111111111111112",
      "filters": {
        "amount": {
          "gte": 1000000000,
          "lt": 10000000000
        },
        "blockTime": {
          "gte": 1735718400,
          "lt": 1738396800
        }
      }
    }
  ]
}
```

### 分页请求

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "limit": 50,
      "paginationToken": "315069220:308:2:1:splTransfer"
    }
  ]
}
```

### 获取转账行的完整交易

`getTransfersByAddress` 返回已解析的转账行，而不是完整的交易负载。如果需要每次转账的完整交易，首先通过传输分页，根据 `signature` 去重，然后使用批量 [`getTransaction`](/zh/api-reference/rpc/http/gettransaction) 调用获取完整交易。

`getTransfersByAddress` 不能跨多个所有者地址进行批量操作。一次查询一个所有者地址，然后按签名批量处理结果的 `getTransaction` 请求。单个交易可以发出多个转账行，因此在获取交易之前始终去重签名。

```javascript theme={"system"}
const API_KEY = "YOUR_API_KEY";
const RPC_URL = `https://mainnet.helius-rpc.com/?api-key=${API_KEY}`;
const OWNER_ADDRESS = "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY";

async function rpc(method, params) {
  const response = await fetch(RPC_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: "1",
      method,
      params
    })
  });

  const body = await response.json();
  if (body.error) {
    throw new Error(body.error.message);
  }
  return body.result;
}

async function getAllTransfers(address) {
  const transfers = [];
  let paginationToken;

  do {
    const result = await rpc("getTransfersByAddress", [
      address,
      {
        limit: 100,
        ...(paginationToken ? { paginationToken } : {})
      }
    ]);

    transfers.push(...result.data);
    paginationToken = result.paginationToken;
  } while (paginationToken);

  return transfers;
}

async function getTransactionsInBatches(signatures, batchSize = 100) {
  const transactions = [];

  for (let i = 0; i < signatures.length; i += batchSize) {
    const batch = signatures.slice(i, i + batchSize).map((signature, index) => ({
      jsonrpc: "2.0",
      id: `${i + index}`,
      method: "getTransaction",
      params: [
        signature,
        {
          encoding: "jsonParsed",
          maxSupportedTransactionVersion: 0
        }
      ]
    }));

    const response = await fetch(RPC_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(batch)
    });

    const results = await response.json();
    for (const item of results) {
      if (item.error) {
        throw new Error(item.error.message);
      }
      transactions.push(item.result);
    }
  }

  return transactions;
}

const transfers = await getAllTransfers(OWNER_ADDRESS);
const signatures = [...new Set(transfers.map((transfer) => transfer.signature))];
const transactions = await getTransactionsInBatches(signatures);

console.log(`Fetched ${transfers.length} transfer rows`);
console.log(`Fetched ${transactions.length} unique transactions`);
```

## 限制

* V1 中不包括失败的交易。
* V1 中不支持仅从余额变化推断的隐藏 SOL 流动。
* `harvestWithheldTokensToMint` 在 V1 中不支持，因为它不指示收集的金额。
* 中间账户流动不减少。如果交易通过中间账户移动资金，将返回基础转账记录。
* 不能跨多个所有者地址批处理。一次查询一个所有者。

## 下一步

<CardGroup cols={2}>
  <Card title="getTransactionsForAddress" icon="clock-rotate-left" href="/zh/rpc/gettransactionsforaddress">
    提供完整的交易历史记录，支持过滤、排序和代币账户。
  </Card>

  <Card title="API 参考" icon="code" href="/zh/api-reference/rpc/http/gettransfersbyaddress">
    getTransfersByAddress 的完整请求和响应模式。
  </Card>

  <Card title="索引指南" icon="layer-group" href="/zh/rpc/how-to-index-solana-data">
    将转移数据回填并同步到您自己的索引中。
  </Card>

  <Card title="历史数据概览" icon="arrow-right-arrow-left" href="/zh/rpc/historical-data">
    比较所有 Solana 历史数据方法。
  </Card>
</CardGroup>
