Parameters
object
Response
object
Object containing:
array
Array of current vote account objects containing:
string
Public key of the vote account (base-58 encoded)
string
Public key of the validator (base-58 encoded)
number
Amount of activated stake in lamports
boolean
Whether the account voted in the current epoch
array
number
Slot of the last vote
number
Slot of the root
array
Array of delinquent vote account objects with the same structure as current
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": "getVoteAccounts"
}'
Using web3.js
import { Connection } from '@solana/web3.js';
const connection = new Connection('https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY');
// Get vote accounts
const voteAccounts = await connection.getVoteAccounts();
console.log('Vote accounts:', voteAccounts);
// Get vote accounts with analysis
async function getVoteAccountsWithAnalysis(
config: {
commitment?: string;
votePubkey?: string;
keepUnstakedDelinquents?: boolean;
delinquentSlotDistance?: number;
}
) {
const voteAccounts = await connection.getVoteAccounts(config);
return {
voteAccounts,
analysis: {
current: {
count: voteAccounts.current.length,
totalStake: voteAccounts.current.reduce((sum, acc) => sum + acc.activatedStake, 0),
averageStake: voteAccounts.current.reduce((sum, acc) => sum + acc.activatedStake, 0) / voteAccounts.current.length,
activeVoters: voteAccounts.current.filter(acc => acc.epochVoteAccount).length
},
delinquent: {
count: voteAccounts.delinquent.length,
totalStake: voteAccounts.delinquent.reduce((sum, acc) => sum + acc.activatedStake, 0),
averageStake: voteAccounts.delinquent.reduce((sum, acc) => sum + acc.activatedStake, 0) / voteAccounts.delinquent.length,
activeVoters: voteAccounts.delinquent.filter(acc => acc.epochVoteAccount).length
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment
}
}
};
}
Notes
- Returns the current vote accounts
- The response includes both current and delinquent vote accounts
- The response is immediate as it reads from the current state
- The accounts can change with stake changes and voting
- The vote accounts must be valid
Best Practices
- Use appropriate commitment level based on your needs
- Cache results when appropriate to reduce RPC load
- Monitor for changes in vote 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 configuration parameters |
| -32007 | Vote account not found | Verify the vote account exists |
Use Cases
-
Vote Account Analysis
interface VoteAccountAnalysis { accounts: { current: Array<{ votePubkey: string; nodePubkey: string; activatedStake: number; epochVoteAccount: boolean; lastVote: number; rootSlot?: number; }>; delinquent: Array<{ votePubkey: string; nodePubkey: string; activatedStake: number; epochVoteAccount: boolean; lastVote: number; rootSlot?: number; }>; }; metrics: { current: { count: number; totalStake: number; averageStake: number; activeVoters: number; participationRate: number; }; delinquent: { count: number; totalStake: number; averageStake: number; activeVoters: number; participationRate: number; }; }; metadata: { timestamp: number; commitment?: string; }; } class VoteAccountAnalyzer { async analyzeVoteAccounts( config: { commitment?: string; votePubkey?: string; keepUnstakedDelinquents?: boolean; delinquentSlotDistance?: number; } ): Promise<VoteAccountAnalysis> { const voteAccounts = await connection.getVoteAccounts(config); return { accounts: { current: voteAccounts.current.map(acc => ({ votePubkey: acc.votePubkey, nodePubkey: acc.nodePubkey, activatedStake: acc.activatedStake, epochVoteAccount: acc.epochVoteAccount, lastVote: acc.lastVote, rootSlot: acc.rootSlot })), delinquent: voteAccounts.delinquent.map(acc => ({ votePubkey: acc.votePubkey, nodePubkey: acc.nodePubkey, activatedStake: acc.activatedStake, epochVoteAccount: acc.epochVoteAccount, lastVote: acc.lastVote, rootSlot: acc.rootSlot })) }, metrics: { current: { count: voteAccounts.current.length, totalStake: voteAccounts.current.reduce((sum, acc) => sum + acc.activatedStake, 0), averageStake: voteAccounts.current.reduce((sum, acc) => sum + acc.activatedStake, 0) / voteAccounts.current.length, activeVoters: voteAccounts.current.filter(acc => acc.epochVoteAccount).length, participationRate: voteAccounts.current.filter(acc => acc.epochVoteAccount).length / voteAccounts.current.length }, delinquent: { count: voteAccounts.delinquent.length, totalStake: voteAccounts.delinquent.reduce((sum, acc) => sum + acc.activatedStake, 0), averageStake: voteAccounts.delinquent.reduce((sum, acc) => sum + acc.activatedStake, 0) / voteAccounts.delinquent.length, activeVoters: voteAccounts.delinquent.filter(acc => acc.epochVoteAccount).length, participationRate: voteAccounts.delinquent.filter(acc => acc.epochVoteAccount).length / voteAccounts.delinquent.length } }, metadata: { timestamp: Date.now(), commitment: config.commitment } }; } } -
Vote Account Monitoring
interface VoteAccountChange { changes: { current: Array<{ type: 'added' | 'removed' | 'modified'; votePubkey: string; previousStake?: number; currentStake?: number; previousVote?: boolean; currentVote?: boolean; }>; delinquent: Array<{ type: 'added' | 'removed' | 'modified'; votePubkey: string; previousStake?: number; currentStake?: number; previousVote?: boolean; currentVote?: boolean; }>; }; metadata: { timestamp: number; }; } class VoteAccountMonitor { private previousAccounts: { current: Map<string, { stake: number; vote: boolean; }>; delinquent: Map<string, { stake: number; vote: boolean; }>; } = { current: new Map(), delinquent: new Map() }; async monitorVoteAccounts( config: { commitment?: string; votePubkey?: string; keepUnstakedDelinquents?: boolean; delinquentSlotDistance?: number; } ): Promise<VoteAccountChange | null> { const voteAccounts = await connection.getVoteAccounts(config); const changes: { current: Array<{ type: 'added' | 'removed' | 'modified'; votePubkey: string; previousStake?: number; currentStake?: number; previousVote?: boolean; currentVote?: boolean; }>; delinquent: Array<{ type: 'added' | 'removed' | 'modified'; votePubkey: string; previousStake?: number; currentStake?: number; previousVote?: boolean; currentVote?: boolean; }>; } = { current: [], delinquent: [] }; // Check current accounts this.checkAccountChanges( voteAccounts.current, this.previousAccounts.current, changes.current ); // Check delinquent accounts this.checkAccountChanges( voteAccounts.delinquent, this.previousAccounts.delinquent, changes.delinquent ); // Update previous accounts this.previousAccounts.current = new Map( voteAccounts.current.map(acc => [ acc.votePubkey, { stake: acc.activatedStake, vote: acc.epochVoteAccount } ]) ); this.previousAccounts.delinquent = new Map( voteAccounts.delinquent.map(acc => [ acc.votePubkey, { stake: acc.activatedStake, vote: acc.epochVoteAccount } ]) ); if (changes.current.length > 0 || changes.delinquent.length > 0) { return { changes, metadata: { timestamp: Date.now() } }; } return null; } private checkAccountChanges( currentAccounts: Array<{ votePubkey: string; activatedStake: number; epochVoteAccount: boolean; }>, previousAccounts: Map<string, { stake: number; vote: boolean; }>, changes: Array<{ type: 'added' | 'removed' | 'modified'; votePubkey: string; previousStake?: number; currentStake?: number; previousVote?: boolean; currentVote?: boolean; }> ) { // Check for removed or modified accounts previousAccounts.forEach((data, votePubkey) => { const current = currentAccounts.find(acc => acc.votePubkey === votePubkey); if (!current) { changes.push({ type: 'removed', votePubkey, previousStake: data.stake, previousVote: data.vote }); } else if ( current.activatedStake !== data.stake || current.epochVoteAccount !== data.vote ) { changes.push({ type: 'modified', votePubkey, previousStake: data.stake, currentStake: current.activatedStake, previousVote: data.vote, currentVote: current.epochVoteAccount }); } }); // Check for added accounts currentAccounts.forEach(account => { if (!previousAccounts.has(account.votePubkey)) { changes.push({ type: 'added', votePubkey: account.votePubkey, currentStake: account.activatedStake, currentVote: account.epochVoteAccount }); } }); } } -
Vote Account Planning
interface VoteAccountPlan { accounts: { current: Array<{ votePubkey: string; nodePubkey: string; activatedStake: number; epochVoteAccount: boolean; }>; delinquent: Array<{ votePubkey: string; nodePubkey: string; activatedStake: number; epochVoteAccount: boolean; }>; }; recommendations: Array<{ type: 'stake' | 'unstake' | 'monitor'; votePubkey: string; reason: string; }>; metadata: { timestamp: number; }; } class VoteAccountPlanner { private readonly minStake = 1000000000; // 1 SOL private readonly maxDelinquentVotes = 3; async planVoteAccounts( config: { commitment?: string; votePubkey?: string; keepUnstakedDelinquents?: boolean; delinquentSlotDistance?: number; } ): Promise<VoteAccountPlan> { const voteAccounts = await connection.getVoteAccounts(config); const recommendations: Array<{ type: 'stake' | 'unstake' | 'monitor'; votePubkey: string; reason: string; }> = []; // Check current accounts voteAccounts.current.forEach(account => { if (account.activatedStake < this.minStake) { recommendations.push({ type: 'stake', votePubkey: account.votePubkey, reason: `Account has low stake (${account.activatedStake})` }); } if (!account.epochVoteAccount) { recommendations.push({ type: 'monitor', votePubkey: account.votePubkey, reason: 'Account not voting in current epoch' }); } }); // Check delinquent accounts voteAccounts.delinquent.forEach(account => { if (account.activatedStake > 0) { recommendations.push({ type: 'unstake', votePubkey: account.votePubkey, reason: 'Account is delinquent with stake' }); } }); return { accounts: { current: voteAccounts.current.map(acc => ({ votePubkey: acc.votePubkey, nodePubkey: acc.nodePubkey, activatedStake: acc.activatedStake, epochVoteAccount: acc.epochVoteAccount })), delinquent: voteAccounts.delinquent.map(acc => ({ votePubkey: acc.votePubkey, nodePubkey: acc.nodePubkey, activatedStake: acc.activatedStake, epochVoteAccount: acc.epochVoteAccount })) }, recommendations, metadata: { timestamp: Date.now() } }; } }