Parameters
string
required
Public key of the token mint (base-58 encoded)
object
Response
object
Object containing:
array
Array of token account objects containing:
string
Public key of the token account (base-58 encoded)
string
Raw amount of tokens as a string
number
Number of decimals configured for token’s mint
number
Token amount as a float, accounting for decimals
string
Token amount as a string, accounting for decimals
Code Examples
Basic Request
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
}
]
}'
Using 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
}
}
};
}
Notes
- Returns the largest token accounts for a given mint
- Accounts are sorted by balance in descending order
- The response is immediate as it reads from the current state
- The accounts can change with token transfers and other operations
- The mint must be a valid token mint
Best Practices
- Use appropriate commitment level based on your needs
- Cache results when appropriate to reduce RPC load
- Monitor for changes in largest accounts
- Consider using websocket subscription for real-time updates
- Handle network errors and retry when appropriate
Common Errors
| Code | Message | Solution |
|---|---|---|
| -32601 | Method not found | Verify you’re connected to a Solana RPC node |
| -32602 | Invalid params | Check mint public key and configuration |
| -32007 | Mint not found | Verify the mint exists |
| -32008 | Invalid limit | Ensure limit is a positive number |
Use Cases
-
Token Distribution Analysis
interface TokenDistributionAnalysis { mint: string; accounts: Array<{ address: string; amount: string; percentage: number; rank: number; }>; metrics: { totalAccounts: number; totalSupply: string; concentration: number; // Gini coefficient 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 } }; } } -
Token Holder Monitoring
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; }> = []; // Check for removed or modified holders 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 }); } } }); // Check for added holders 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; } } -
Token Supply Planning
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; // Maximum allowed concentration private readonly minHolders = 100; // Minimum number of holders 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; }> = []; // Check for concentration 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` }); } // Check for minimum holders 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() } }; } }