Parameters
Public key of the delegate (base-58 encoded)
Configuration object containing:Public key of the token program (base-58 encoded)
Commitment level (processed, confirmed, finalized)
Encoding for account data (base58, base64, jsonParsed)
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)
Number of lamports in the account
Public key of the account owner (base-58 encoded)
Whether the account is executable
Epoch at which the account will next owe rent
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
Public key of the token’s mint (base-58 encoded)
Public key of the token account owner (base-58 encoded)
Public key of the delegate (base-58 encoded)
Type of account (account)
Program that owns the account (spl-token)
Number of bytes allocated to the account
Code Examples
Basic Request
curl https://rpc.orbitflare.com -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getTokenAccountsByDelegate",
"params": [
"4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj",
{
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
]
}'
Using web3.js
import { Connection, PublicKey } from '@solana/web3.js';
const connection = new Connection('https://rpc.orbitflare.com');
// Get token accounts by delegate
const delegate = new PublicKey('4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj');
const programId = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
const accounts = await connection.getTokenAccountsByDelegate(delegate, { programId });
console.log('Token accounts:', accounts);
// Get token accounts by delegate with analysis
async function getTokenAccountsByDelegateWithAnalysis(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
) {
const accounts = await connection.getTokenAccountsByDelegate(delegate, 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
}
}
};
}
Notes
- Returns all token accounts where the given public key is a delegate
- The delegate has the authority to transfer tokens from these accounts
- The response is immediate as it reads from the current state
- The accounts can change with token transfers and other operations
- The delegate must be a valid public key
Best Practices
- Use appropriate commitment level based on your needs
- Cache results when appropriate to reduce RPC load
- Monitor for changes in delegated 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 delegate public key and configuration |
| -32007 | Delegate not found | Verify the delegate exists |
| -32008 | Invalid program ID | Verify the program ID is correct |
Use Cases
-
Delegate Account Analysis
interface DelegateAccountAnalysis {
delegate: string;
accounts: Array<{
pubkey: string;
mint: string;
balance: string;
owner: string;
}>;
metrics: {
totalAccounts: number;
totalBalance: string;
byMint: Record<string, string>;
byOwner: Record<string, number>;
};
metadata: {
timestamp: number;
commitment?: string;
};
}
class DelegateAccountAnalyzer {
async analyzeDelegateAccounts(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
): Promise<DelegateAccountAnalysis> {
const accounts = await connection.getTokenAccountsByDelegate(delegate, config);
const byMint: Record<string, bigint> = {};
const byOwner: Record<string, number> = {};
let totalBalance = BigInt(0);
accounts.value.forEach(account => {
const mint = account.account.data.parsed.info.mint;
const owner = account.account.data.parsed.info.owner;
const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
byMint[mint] = (byMint[mint] || BigInt(0)) + amount;
byOwner[owner] = (byOwner[owner] || 0) + 1;
totalBalance += amount;
});
return {
delegate: delegate.toBase58(),
accounts: accounts.value.map(account => ({
pubkey: account.pubkey,
mint: account.account.data.parsed.info.mint,
balance: account.account.data.parsed.info.tokenAmount.amount,
owner: account.account.data.parsed.info.owner
})),
metrics: {
totalAccounts: accounts.value.length,
totalBalance: totalBalance.toString(),
byMint: Object.fromEntries(
Object.entries(byMint).map(([mint, amount]) => [mint, amount.toString()])
),
byOwner
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment
}
};
}
}
-
Delegate Account Monitoring
interface DelegateAccountChange {
delegate: string;
changes: Array<{
type: 'added' | 'removed' | 'modified';
account: string;
previousBalance?: string;
currentBalance?: string;
}>;
metadata: {
timestamp: number;
};
}
class DelegateAccountMonitor {
private previousAccounts: Map<string, string> = new Map();
async monitorDelegateAccounts(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
): Promise<DelegateAccountChange | null> {
const accounts = await connection.getTokenAccountsByDelegate(delegate, config);
const currentAccounts = new Map(
accounts.value.map(account => [
account.pubkey,
account.account.data.parsed.info.tokenAmount.amount
])
);
const changes: Array<{
type: 'added' | 'removed' | 'modified';
account: string;
previousBalance?: string;
currentBalance?: string;
}> = [];
// Check for removed or modified accounts
this.previousAccounts.forEach((balance, account) => {
if (!currentAccounts.has(account)) {
changes.push({
type: 'removed',
account,
previousBalance: balance
});
} else if (currentAccounts.get(account) !== balance) {
changes.push({
type: 'modified',
account,
previousBalance: balance,
currentBalance: currentAccounts.get(account)
});
}
});
// Check for added accounts
currentAccounts.forEach((balance, account) => {
if (!this.previousAccounts.has(account)) {
changes.push({
type: 'added',
account,
currentBalance: balance
});
}
});
this.previousAccounts = currentAccounts;
if (changes.length > 0) {
return {
delegate: delegate.toBase58(),
changes,
metadata: {
timestamp: Date.now()
}
};
}
return null;
}
}
-
Delegate Account Planning
interface DelegateAccountPlan {
delegate: string;
currentAccounts: Array<{
pubkey: string;
mint: string;
balance: string;
}>;
recommendations: Array<{
type: 'consolidate' | 'diversify' | 'rebalance';
accounts: string[];
reason: string;
}>;
metadata: {
timestamp: number;
};
}
class DelegateAccountPlanner {
private readonly minBalancePerAccount = BigInt(1000000); // 1 token
private readonly maxAccountsPerMint = 5;
async planDelegateAccounts(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
): Promise<DelegateAccountPlan> {
const accounts = await connection.getTokenAccountsByDelegate(delegate, 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';
accounts: string[];
reason: string;
}> = [];
Object.entries(byMint).forEach(([mint, mintAccounts]) => {
// Check for accounts with low balances
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}`
});
}
// Check for too many accounts per 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}`
});
}
});
return {
delegate: delegate.toBase58(),
currentAccounts: accounts.value.map(account => ({
pubkey: account.pubkey,
mint: account.account.data.parsed.info.mint,
balance: account.account.data.parsed.info.tokenAmount.amount
})),
recommendations,
metadata: {
timestamp: Date.now()
}
};
}
}