getTokenAccountsByOwner RPC 方法用于检索由特定公钥拥有的所有 SPL Token 账户。对于需要显示用户代币持有或与其各种代币账户交互的钱包和应用程序来说,这是一个基本方法。 您必须通过特定代币 mintprogramId(例如,SPL Token Program 或 Token-2022 Program)来过滤查询。 对于拥有大量代币组合的钱包,考虑使用 getTokenAccountsByOwnerV2,它提供基于游标的分页支持,每个请求最多可配置 10,000 个账户。

常见用例

  • 显示用户投资组合: 获取给定用户钱包地址的所有代币账户(以及余额),以显示其完整的代币投资组合。
  • 应用逻辑: 在发起转账或其他交互之前,识别用户特定代币的账户。
  • 验证: 检查某个所有者拥有的特定类型代币的账户。
  • 索引代币持有者: 虽然对于全局索引效率较低,但可以用于查找已知所有者集合的账户。

请求参数

  1. ownerPubkey(字符串,必需):要检索其代币账户的账户所有者的 base-58 编码公钥。
  2. filter(对象,必需):一个 JSON 对象,必须指定 mintprogramId
    • mint(字符串):特定代币铸造的 base-58 编码公钥。如果提供,将仅返回由 ownerPubkey 拥有的此铸造的代币账户。
    • programId(字符串):管理账户的 Token Program 的 base-58 编码公钥。常见值有:
      • SPL Token Program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
      • Token-2022 Program: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
  3. options (object, optional): 一个可选的配置对象,可以包括:
    • commitment (string, optional): 指定承诺级别
    • encoding (string, optional): 账户数据的编码。强烈推荐使用"jsonParsed"。其他选项:"base64", "base64+zstd"。默认使用"base64"
    • dataSlice (object, optional): 用于检索账户数据的特定切片 (offset: usize, length: usize)。仅适用于base58, base64, 或base64+zstd编码。
    • minContextSlot (u64, optional): 查询的最小槽位。

响应结构

JSON-RPC 响应中的result.value字段是一个对象数组。每个对象对应一个由ownerPubkey拥有并匹配filter的SPL Token账户。 value数组中的每个对象包含:
  • pubkey (string): Token账户本身的base-58编码公钥。
  • account (object): Token账户的详细信息:
    • lamports (u64): 免租金的Lamport余额。
    • owner (string): 拥有程序(例如,Token Program公钥)。
    • data: 账户数据。如果使用"jsonParsed"编码,这将包含:
      • program (string): 例如,"spl-token"
      • parsed: 一个包含结构化信息的对象:
        • info: 详细信息如:
          • mint (string): Token的铸造地址。
          • owner (string): Token账户的所有者(应与请求中的ownerPubkey匹配)。
          • tokenAmount (object): Token的余额 (amount, decimals, uiAmount, uiAmountString)。
          • state (string): Token账户的状态(例如,"initialized")。
          • isNative (boolean): 如果账户持有包装的SOL。
          • delegate (string, optional): 如果设置了委托,则为委托地址。
          • delegatedAmount (object, optional): 如果设置了委托,则为委托金额。
        • type (string): 例如,"account"
    • executable (boolean): 账户是否可执行。
    • rentEpoch (u64): 下一个纪元租金到期。
    • space (u64, if not jsonParsed): 原始账户数据的字节长度。
示例响应(使用 jsonParsed 编码,过滤条件为 programId):
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 183459000
    },
    "value": [
      {
        "pubkey": "AssociatedTokenAccountPubkey1...",
        "account": {
          "data": {
            "program": "spl-token",
            "parsed": {
              "info": {
                "isNative": false,
                "mint": "SomeTokenMintPubkey...",
                "owner": "OwnerPubkeyProvidedInRequest...",
                "state": "initialized",
                "tokenAmount": {
                  "amount": "1000000000", // 1 token if decimals is 9
                  "decimals": 9,
                  "uiAmount": 1.0,
                  "uiAmountString": "1.0"
                }
              },
              "type": "account"
            },
            "space": 165
          },
          "executable": false,
          "lamports": 2039280,
          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
          "rentEpoch": 380
        }
      },
      {
        "pubkey": "AnotherAssociatedTokenAccountPubkey...",
        "account": {
          // ... similar structure for another token owned by the same owner
        }
      }
    ]
  },
  "id": 1
}

代码示例

# Replace <OWNER_PUBKEY> and <TOKEN_MINT_PUBKEY> or <TOKEN_PROGRAM_ID>

# Example filtering by programId (SPL Token Program)
curl -X POST -H "Content-Type: application/json" -d \
  '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByOwner",
    "params": [
      "<OWNER_PUBKEY>",
      { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
      { "encoding": "jsonParsed" }
    ]
  }' \
  <YOUR_RPC_URL>

# Example filtering by a specific mint
curl -X POST -H "Content-Type: application/json" -d \
  '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByOwner",
    "params": [
      "<OWNER_PUBKEY>",
      { "mint": "<SPECIFIC_TOKEN_MINT_PUBKEY>" },
      { "encoding": "jsonParsed", "commitment": "confirmed" }
    ]
  }' \
  <YOUR_RPC_URL>

开发者提示

  • 过滤要求:必须在过滤器中提供 mintprogramId。没有这些主要过滤器之一,无法查询所有代币类型的所有者的所有代币账户。
  • 关联代币账户: 此方法将返回由公钥拥有的所有代币账户,包括标准的关联代币账户(ATAs)和他们可能拥有的任何其他 SPL 代币账户(例如,来自旧钱包实现或自定义设置)。
  • 编码: 强烈推荐为 encoding 选项使用 "jsonParsed"。它将二进制账户数据解码为更易用的 JSON 结构。
  • 性能: 如果一个所有者拥有非常多的代币账户(特别是仅通过 programId 过滤时),响应可能会很大。在这种情况下,使用 getTokenAccountsByOwnerV2,它提供内置的分页支持。
  • Token-2022(代币扩展): 如果您使用的是通过 Token-2022 程序创建的代币(支持转账费用、利息等扩展),请确保使用正确的 programIdTokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
本指南提供了对 getTokenAccountsByOwner RPC 方法的深入理解,使您能够高效地检索任何 Solana 地址的代币账户信息。

大型代币组合的分页

对于持有大量代币的钱包,使用 getTokenAccountsByOwnerV2,它提供:
  • 基于游标的分页:设置 limit(1-10,000)并使用 paginationKey 导航结果
  • 增量更新:使用 changedSinceSlot 仅获取自特定槽位以来修改的代币账户
  • 更好的性能:防止超时并实现实时组合跟踪
  • 分页行为:分页结束仅在没有返回代币账户时指示。由于过滤,返回的账户可能少于限制 - 继续分页直到 paginationKey 为 null
// Example: Paginated query for all token accounts
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: "getTokenAccountsByOwnerV2",
    params: [
      "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
      { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
      {
        encoding: "jsonParsed",
        limit: 1000
      }
    ]
  })
});

const data = await response.json();
console.log(`Found ${data.result.value.length} token accounts`);
if (data.result.paginationKey) {
  console.log("More results available, use paginationKey for next page");
  // Continue pagination even if fewer than limit accounts were returned
} else {
  console.log("End of pagination - no more token accounts available");
}