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()
          }
        };
      }
    }