Parameters

config
object
Configuration object containing:
commitment
string
Commitment level (processed, confirmed, finalized)
votePubkey
string
Public key of a specific vote account to query (base-58 encoded)
keepUnstakedDelinquents
boolean
Whether to include unstaked delinquent vote accounts
delinquentSlotDistance
number
Maximum slot distance to consider a vote account delinquent

Response

result
object
Object containing:
current
array
Array of current vote account objects containing:
votePubkey
string
Public key of the vote account (base-58 encoded)
nodePubkey
string
Public key of the validator (base-58 encoded)
activatedStake
number
Amount of activated stake in lamports
epochVoteAccount
boolean
Whether the account voted in the current epoch
epochCredits
array
Array of epoch credit objects containing:
epoch
number
Epoch number
credits
number
Number of credits earned
previousCredits
number
Number of credits earned in previous epoch
lastVote
number
Slot of the last vote
rootSlot
number
Slot of the root
delinquent
array
Array of delinquent vote account objects with the same structure as current

Code Examples

Basic Request

curl https://rpc.orbitflare.com -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://rpc.orbitflare.com');

// 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

  1. Returns the current vote accounts
  2. The response includes both current and delinquent vote accounts
  3. The response is immediate as it reads from the current state
  4. The accounts can change with stake changes and voting
  5. The vote accounts must be valid

Best Practices

  1. Use appropriate commitment level based on your needs
  2. Cache results when appropriate to reduce RPC load
  3. Monitor for changes in vote accounts
  4. Consider using websocket subscription for real-time updates
  5. Handle network errors and retry when appropriate

Common Errors

CodeMessageSolution
-32601Method not foundVerify you’re connected to a Solana RPC node
-32602Invalid paramsCheck configuration parameters
-32007Vote account not foundVerify the vote account exists

Use Cases

  1. 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
          }
        };
      }
    }
    
  2. 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
            });
          }
        });
      }
    }
    
  3. 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()
          }
        };
      }
    }