跳转到主要内容

参数

mint
string
必填
代币铸造的公钥(base-58 编码)
config
object
包含以下内容的配置对象:
limit
number
要返回的最大账户数量(默认:20)
commitment
string
Commitment 级别(processed、confirmed、finalized)

响应

result
object
包含以下内容的对象:
context
object
slot
number
处理请求时的 slot
value
array
代币账户对象数组,包含:
address
string
代币账户的公钥(base-58 编码)
amount
string
代币的原始数量(字符串格式)
decimals
number
代币铸造配置的小数位数
uiAmount
number
考虑小数位数后的代币数量(浮点数)
uiAmountString
string
考虑小数位数后的代币数量(字符串)

代码示例

基本请求

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": "getTokenLargestAccounts",
  "params": [
    "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    {
      "limit": 10
    }
  ]
}'

使用 web3.js

import { Connection, PublicKey } from '@solana/web3.js';

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

// Get largest token accounts
const mint = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
const accounts = await connection.getTokenLargestAccounts(mint, { limit: 10 });
console.log('Largest token accounts:', accounts);

// Get largest token accounts with analysis
async function getTokenLargestAccountsWithAnalysis(
  mint: PublicKey,
  config: { limit?: number; commitment?: string }
) {
  const accounts = await connection.getTokenLargestAccounts(mint, config);
  
  return {
    accounts,
    analysis: {
      totalAccounts: accounts.value.length,
      totalSupply: accounts.value.reduce((sum, acc) => {
        const amount = BigInt(acc.amount);
        return sum + amount;
      }, BigInt(0)),
      distribution: accounts.value.reduce((acc, account, index) => {
        const amount = BigInt(account.amount);
        const percentage = Number((amount * BigInt(100)) / BigInt(accounts.value[0].amount));
        acc[account.address] = {
          amount: account.amount,
          percentage,
          rank: index + 1
        };
        return acc;
      }, {} as Record<string, {
        amount: string;
        percentage: number;
        rank: number;
      }>),
      metadata: {
        timestamp: Date.now(),
        commitment: config.commitment
      }
    }
  };
}

注意事项

  1. 返回给定铸造的最大代币账户
  2. 账户按余额降序排序
  3. 响应是即时的,因为它从当前状态读取
  4. 账户可能随代币转账和其他操作而变化
  5. 铸造必须是有效的代币铸造

最佳实践

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

常见错误

错误码消息解决方案
-32601Method not found验证是否连接到 Solana RPC 节点
-32602Invalid params检查铸造公钥和配置
-32007Mint not found验证铸造是否存在
-32008Invalid limit确保限制是正数

用例

  1. 代币分布分析
    interface TokenDistributionAnalysis {
      mint: string;
      accounts: Array<{
        address: string;
        amount: string;
        percentage: number;
        rank: number;
      }>;
      metrics: {
        totalAccounts: number;
        totalSupply: string;
        concentration: number;
        top10Percentage: number;
      };
      metadata: {
        timestamp: number;
        commitment?: string;
      };
    }
    
    class TokenDistributionAnalyzer {
      private calculateGiniCoefficient(amounts: bigint[]): number {
        const n = amounts.length;
        const mean = amounts.reduce((sum, x) => sum + x, BigInt(0)) / BigInt(n);
        let numerator = BigInt(0);
        let denominator = BigInt(0);
        
        for (let i = 0; i < n; i++) {
          for (let j = 0; j < n; j++) {
            numerator += (amounts[i] - amounts[j]).abs();
          }
          denominator += amounts[i];
        }
        
        return Number(numerator) / (2 * n * Number(denominator));
      }
      
      async analyzeTokenDistribution(
        mint: PublicKey,
        config: { limit?: number; commitment?: string }
      ): Promise<TokenDistributionAnalysis> {
        const accounts = await connection.getTokenLargestAccounts(mint, config);
        const amounts = accounts.value.map(acc => BigInt(acc.amount));
        const totalSupply = amounts.reduce((sum, x) => sum + x, BigInt(0));
        const top10Supply = amounts.slice(0, 10).reduce((sum, x) => sum + x, BigInt(0));
        
        return {
          mint: mint.toBase58(),
          accounts: accounts.value.map((account, index) => ({
            address: account.address,
            amount: account.amount,
            percentage: Number((BigInt(account.amount) * BigInt(100)) / totalSupply),
            rank: index + 1
          })),
          metrics: {
            totalAccounts: accounts.value.length,
            totalSupply: totalSupply.toString(),
            concentration: this.calculateGiniCoefficient(amounts),
            top10Percentage: Number((top10Supply * BigInt(100)) / totalSupply)
          },
          metadata: {
            timestamp: Date.now(),
            commitment: config.commitment
          }
        };
      }
    }
    
  2. 代币持有者监控
    interface TokenHolderChange {
      mint: string;
      changes: Array<{
        type: 'added' | 'removed' | 'modified';
        address: string;
        previousAmount?: string;
        currentAmount?: string;
        previousRank?: number;
        currentRank?: number;
      }>;
      metadata: {
        timestamp: number;
      };
    }
    
    class TokenHolderMonitor {
      private previousHolders: Map<string, {
        amount: string;
        rank: number;
      }> = new Map();
      
      async monitorTokenHolders(
        mint: PublicKey,
        config: { limit?: number; commitment?: string }
      ): Promise<TokenHolderChange | null> {
        const accounts = await connection.getTokenLargestAccounts(mint, config);
        const currentHolders = new Map(
          accounts.value.map((account, index) => [
            account.address,
            {
              amount: account.amount,
              rank: index + 1
            }
          ])
        );
        
        const changes: Array<{
          type: 'added' | 'removed' | 'modified';
          address: string;
          previousAmount?: string;
          currentAmount?: string;
          previousRank?: number;
          currentRank?: number;
        }> = [];
        
        this.previousHolders.forEach((data, address) => {
          if (!currentHolders.has(address)) {
            changes.push({
              type: 'removed',
              address,
              previousAmount: data.amount,
              previousRank: data.rank
            });
          } else {
            const current = currentHolders.get(address)!;
            if (current.amount !== data.amount || current.rank !== data.rank) {
              changes.push({
                type: 'modified',
                address,
                previousAmount: data.amount,
                currentAmount: current.amount,
                previousRank: data.rank,
                currentRank: current.rank
              });
            }
          }
        });
        
        currentHolders.forEach((data, address) => {
          if (!this.previousHolders.has(address)) {
            changes.push({
              type: 'added',
              address,
              currentAmount: data.amount,
              currentRank: data.rank
            });
          }
        });
        
        this.previousHolders = currentHolders;
        
        if (changes.length > 0) {
          return {
            mint: mint.toBase58(),
            changes,
            metadata: {
              timestamp: Date.now()
            }
          };
        }
        
        return null;
      }
    }
    
  3. 代币供应规划
    interface TokenSupplyPlan {
      mint: string;
      currentHolders: Array<{
        address: string;
        amount: string;
        rank: number;
      }>;
      recommendations: Array<{
        type: 'diversify' | 'consolidate' | 'rebalance';
        addresses: string[];
        reason: string;
      }>;
      metadata: {
        timestamp: number;
      };
    }
    
    class TokenSupplyPlanner {
      private readonly maxConcentration = 0.5;
      private readonly minHolders = 100;
      
      async planTokenSupply(
        mint: PublicKey,
        config: { limit?: number; commitment?: string }
      ): Promise<TokenSupplyPlan> {
        const accounts = await connection.getTokenLargestAccounts(mint, config);
        const amounts = accounts.value.map(acc => BigInt(acc.amount));
        const totalSupply = amounts.reduce((sum, x) => sum + x, BigInt(0));
        
        const recommendations: Array<{
          type: 'diversify' | 'consolidate' | 'rebalance';
          addresses: string[];
          reason: string;
        }> = [];
        
        const top10Supply = amounts.slice(0, 10).reduce((sum, x) => sum + x, BigInt(0));
        const concentration = Number((top10Supply * BigInt(100)) / totalSupply) / 100;
        
        if (concentration > this.maxConcentration) {
          recommendations.push({
            type: 'diversify',
            addresses: accounts.value.slice(0, 10).map(acc => acc.address),
            reason: `Top 10 holders control ${(concentration * 100).toFixed(2)}% of supply`
          });
        }
        
        if (accounts.value.length < this.minHolders) {
          recommendations.push({
            type: 'diversify',
            addresses: accounts.value.map(acc => acc.address),
            reason: `Only ${accounts.value.length} holders, below minimum of ${this.minHolders}`
          });
        }
        
        return {
          mint: mint.toBase58(),
          currentHolders: accounts.value.map((account, index) => ({
            address: account.address,
            amount: account.amount,
            rank: index + 1
          })),
          recommendations,
          metadata: {
            timestamp: Date.now()
          }
        };
      }
    }