Parameters
Public key of the token mint (base-58 encoded)
Configuration object containing:Maximum number of accounts to return (default: 20)
Commitment level (processed, confirmed, finalized)
Response
Object containing:The slot the request was processed at
Array of token account objects containing:Public key of the token account (base-58 encoded)
Raw amount of tokens as a string
Number of decimals configured for token’s mint
Token amount as a float, accounting for decimals
Token amount as a string, accounting for decimals
Code Examples
Basic Request
curl https://rpc.orbitflare.com -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://rpc.orbitflare.com');
// 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()
}
};
}
}