> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# getTokenAccountsByOwner

> 返回给定所有者的所有代币账户

## 参数

<ResponseField name="owner" type="string" required>
  所有者的公钥（base-58 编码）
</ResponseField>

<ResponseField name="config" type="object" required>
  包含以下内容的配置对象：

  <ResponseField name="programId" type="string" required>
    代币程序的公钥（base-58 编码）
  </ResponseField>

  <ResponseField name="commitment" type="string" optional>
    Commitment 级别（processed、confirmed、finalized）
  </ResponseField>

  <ResponseField name="encoding" type="string" optional>
    账户数据的编码格式（base58、base64、jsonParsed）
  </ResponseField>

  <ResponseField name="dataSlice" type="object" optional>
    <ResponseField name="offset" type="number">
      账户数据的偏移量
    </ResponseField>

    <ResponseField name="length" type="number">
      要返回的数据长度
    </ResponseField>
  </ResponseField>
</ResponseField>

## 响应

<ResponseField name="result" type="object">
  包含以下内容的对象：

  <ResponseField name="context" type="object">
    <ResponseField name="slot" type="number">
      处理请求时的 slot
    </ResponseField>
  </ResponseField>

  <ResponseField name="value" type="array">
    代币账户对象数组，包含：

    <ResponseField name="pubkey" type="string">
      代币账户的公钥（base-58 编码）
    </ResponseField>

    <ResponseField name="account" type="object">
      <ResponseField name="lamports" type="number">
        账户中的 lamports 数量
      </ResponseField>

      <ResponseField name="owner" type="string">
        账户所有者的公钥（base-58 编码）
      </ResponseField>

      <ResponseField name="executable" type="boolean">
        账户是否可执行
      </ResponseField>

      <ResponseField name="rentEpoch" type="number">
        账户下次需要支付租金的 epoch
      </ResponseField>

      <ResponseField name="data" type="object">
        <ResponseField name="parsed" type="object">
          <ResponseField name="info" type="object">
            <ResponseField name="tokenAmount" type="object">
              <ResponseField name="amount" type="string">
                代币的原始数量（字符串格式）
              </ResponseField>

              <ResponseField name="decimals" type="number">
                代币铸造配置的小数位数
              </ResponseField>

              <ResponseField name="uiAmount" type="number" optional>
                考虑小数位数后的代币数量（浮点数）
              </ResponseField>

              <ResponseField name="uiAmountString" type="string" optional>
                考虑小数位数后的代币数量（字符串）
              </ResponseField>
            </ResponseField>

            <ResponseField name="mint" type="string">
              代币铸造的公钥（base-58 编码）
            </ResponseField>

            <ResponseField name="owner" type="string">
              代币账户所有者的公钥（base-58 编码）
            </ResponseField>

            <ResponseField name="delegate" type="string" optional>
              代理人的公钥（base-58 编码）
            </ResponseField>
          </ResponseField>

          <ResponseField name="type" type="string">
            账户类型（account）
          </ResponseField>
        </ResponseField>

        <ResponseField name="program" type="string">
          拥有该账户的程序（spl-token）
        </ResponseField>

        <ResponseField name="space" type="number">
          分配给账户的字节数
        </ResponseField>
      </ResponseField>
    </ResponseField>
  </ResponseField>
</ResponseField>

## 代码示例

### 基本请求

```bash theme={null}
curl https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getTokenAccountsByOwner",
  "params": [
    "4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj",
    {
      "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
    }
  ]
}'
```

### 使用 web3.js

```typescript theme={null}
import { Connection, PublicKey } from '@solana/web3.js';

const connection = new Connection('https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY');

// Get token accounts by owner
const owner = new PublicKey('4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj');
const programId = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
const accounts = await connection.getTokenAccountsByOwner(owner, { programId });
console.log('Token accounts:', accounts);

// Get token accounts by owner with analysis
async function getTokenAccountsByOwnerWithAnalysis(
  owner: PublicKey,
  config: { programId: PublicKey; commitment?: string }
) {
  const accounts = await connection.getTokenAccountsByOwner(owner, config);
  
  return {
    accounts,
    analysis: {
      totalAccounts: accounts.value.length,
      totalBalance: accounts.value.reduce((sum, acc) => {
        const amount = BigInt(acc.account.data.parsed.info.tokenAmount.amount);
        return sum + amount;
      }, BigInt(0)),
      byMint: accounts.value.reduce((acc, account) => {
        const mint = account.account.data.parsed.info.mint;
        const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
        acc[mint] = (acc[mint] || BigInt(0)) + amount;
        return acc;
      }, {} as Record<string, bigint>),
      metadata: {
        timestamp: Date.now(),
        commitment: config.commitment
      }
    }
  };
}
```

## 注意事项

1. 返回给定公钥拥有的所有代币账户
2. 所有者完全控制这些账户
3. 响应是即时的，因为它从当前状态读取
4. 账户可能随代币转账和其他操作而变化
5. 所有者必须是有效的公钥

## 最佳实践

1. 根据需求使用适当的 commitment 级别
2. 在适当时缓存结果以减少 RPC 负载
3. 监控所属账户的变化
4. 考虑使用 WebSocket 订阅获取实时更新
5. 适当处理网络错误并重试

## 常见错误

| 错误码    | 消息                 | 解决方案                  |
| ------ | ------------------ | --------------------- |
| -32601 | Method not found   | 验证是否连接到 Solana RPC 节点 |
| -32602 | Invalid params     | 检查所有者公钥和配置            |
| -32007 | Owner not found    | 验证所有者是否存在             |
| -32008 | Invalid program ID | 验证程序 ID 是否正确          |

## 用例

1. **所有者账户分析**
   ```typescript theme={null}
   interface OwnerAccountAnalysis {
     owner: string;
     accounts: Array<{
       pubkey: string;
       mint: string;
       balance: string;
       delegate?: string;
     }>;
     metrics: {
       totalAccounts: number;
       totalBalance: string;
       byMint: Record<string, string>;
       delegatedAccounts: number;
     };
     metadata: {
       timestamp: number;
       commitment?: string;
     };
   }

   class OwnerAccountAnalyzer {
     async analyzeOwnerAccounts(
       owner: PublicKey,
       config: { programId: PublicKey; commitment?: string }
     ): Promise<OwnerAccountAnalysis> {
       const accounts = await connection.getTokenAccountsByOwner(owner, config);
       
       const byMint: Record<string, bigint> = {};
       let totalBalance = BigInt(0);
       let delegatedAccounts = 0;
       
       accounts.value.forEach(account => {
         const mint = account.account.data.parsed.info.mint;
         const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
         const delegate = account.account.data.parsed.info.delegate;
         
         byMint[mint] = (byMint[mint] || BigInt(0)) + amount;
         totalBalance += amount;
         if (delegate) {
           delegatedAccounts++;
         }
       });
       
       return {
         owner: owner.toBase58(),
         accounts: accounts.value.map(account => ({
           pubkey: account.pubkey,
           mint: account.account.data.parsed.info.mint,
           balance: account.account.data.parsed.info.tokenAmount.amount,
           delegate: account.account.data.parsed.info.delegate
         })),
         metrics: {
           totalAccounts: accounts.value.length,
           totalBalance: totalBalance.toString(),
           byMint: Object.fromEntries(
             Object.entries(byMint).map(([mint, amount]) => [mint, amount.toString()])
           ),
           delegatedAccounts
         },
         metadata: {
           timestamp: Date.now(),
           commitment: config.commitment
         }
       };
     }
   }
   ```

2. **所有者账户监控**
   ```typescript theme={null}
   interface OwnerAccountChange {
     owner: string;
     changes: Array<{
       type: 'added' | 'removed' | 'modified';
       account: string;
       previousBalance?: string;
       currentBalance?: string;
       previousDelegate?: string;
       currentDelegate?: string;
     }>;
     metadata: {
       timestamp: number;
     };
   }

   class OwnerAccountMonitor {
     private previousAccounts: Map<string, {
       balance: string;
       delegate?: string;
     }> = new Map();
     
     async monitorOwnerAccounts(
       owner: PublicKey,
       config: { programId: PublicKey; commitment?: string }
     ): Promise<OwnerAccountChange | null> {
       const accounts = await connection.getTokenAccountsByOwner(owner, config);
       const currentAccounts = new Map(
         accounts.value.map(account => [
           account.pubkey,
           {
             balance: account.account.data.parsed.info.tokenAmount.amount,
             delegate: account.account.data.parsed.info.delegate
           }
         ])
       );
       
       const changes: Array<{
         type: 'added' | 'removed' | 'modified';
         account: string;
         previousBalance?: string;
         currentBalance?: string;
         previousDelegate?: string;
         currentDelegate?: string;
       }> = [];
       
       this.previousAccounts.forEach((data, account) => {
         if (!currentAccounts.has(account)) {
           changes.push({
             type: 'removed',
             account,
             previousBalance: data.balance,
             previousDelegate: data.delegate
           });
         } else {
           const current = currentAccounts.get(account)!;
           if (current.balance !== data.balance || current.delegate !== data.delegate) {
             changes.push({
               type: 'modified',
               account,
               previousBalance: data.balance,
               currentBalance: current.balance,
               previousDelegate: data.delegate,
               currentDelegate: current.delegate
             });
           }
         }
       });
       
       currentAccounts.forEach((data, account) => {
         if (!this.previousAccounts.has(account)) {
           changes.push({
             type: 'added',
             account,
             currentBalance: data.balance,
             currentDelegate: data.delegate
           });
         }
       });
       
       this.previousAccounts = currentAccounts;
       
       if (changes.length > 0) {
         return {
           owner: owner.toBase58(),
           changes,
           metadata: {
             timestamp: Date.now()
           }
         };
       }
       
       return null;
     }
   }
   ```

3. **所有者账户规划**
   ```typescript theme={null}
   interface OwnerAccountPlan {
     owner: string;
     currentAccounts: Array<{
       pubkey: string;
       mint: string;
       balance: string;
       delegate?: string;
     }>;
     recommendations: Array<{
       type: 'consolidate' | 'diversify' | 'rebalance' | 'delegate';
       accounts: string[];
       reason: string;
     }>;
     metadata: {
       timestamp: number;
     };
   }

   class OwnerAccountPlanner {
     private readonly minBalancePerAccount = BigInt(1000000); // 1 token
     private readonly maxAccountsPerMint = 5;
     
     async planOwnerAccounts(
       owner: PublicKey,
       config: { programId: PublicKey; commitment?: string }
     ): Promise<OwnerAccountPlan> {
       const accounts = await connection.getTokenAccountsByOwner(owner, config);
       
       const byMint = accounts.value.reduce((acc, account) => {
         const mint = account.account.data.parsed.info.mint;
         if (!acc[mint]) {
           acc[mint] = [];
         }
         acc[mint].push(account);
         return acc;
       }, {} as Record<string, typeof accounts.value>);
       
       const recommendations: Array<{
         type: 'consolidate' | 'diversify' | 'rebalance' | 'delegate';
         accounts: string[];
         reason: string;
       }> = [];
       
       Object.entries(byMint).forEach(([mint, mintAccounts]) => {
         const lowBalanceAccounts = mintAccounts.filter(account => 
           BigInt(account.account.data.parsed.info.tokenAmount.amount) < this.minBalancePerAccount
         );
         
         if (lowBalanceAccounts.length > 0) {
           recommendations.push({
             type: 'consolidate',
             accounts: lowBalanceAccounts.map(account => account.pubkey),
             reason: `Accounts with balances below minimum threshold for mint ${mint}`
           });
         }
         
         if (mintAccounts.length > this.maxAccountsPerMint) {
           recommendations.push({
             type: 'consolidate',
             accounts: mintAccounts.map(account => account.pubkey),
             reason: `Too many accounts (${mintAccounts.length}) for mint ${mint}`
           });
         }
         
         const accountsWithoutDelegates = mintAccounts.filter(
           account => !account.account.data.parsed.info.delegate
         );
         
         if (accountsWithoutDelegates.length > 0) {
           recommendations.push({
             type: 'delegate',
             accounts: accountsWithoutDelegates.map(account => account.pubkey),
             reason: `Accounts without delegates for mint ${mint}`
           });
         }
       });
       
       return {
         owner: owner.toBase58(),
         currentAccounts: accounts.value.map(account => ({
           pubkey: account.pubkey,
           mint: account.account.data.parsed.info.mint,
           balance: account.account.data.parsed.info.tokenAmount.amount,
           delegate: account.account.data.parsed.info.delegate
         })),
         recommendations,
         metadata: {
           timestamp: Date.now()
         }
       };
     }
   }
   ```
