Documentation Index
Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
Use this file to discover all available pages before exploring further.
Parameters
Configuration object containing:Commitment level (processed, confirmed, finalized)
Public key of a specific vote account to query (base-58 encoded)
Whether to include unstaked delinquent vote accounts
Maximum slot distance to consider a vote account delinquent
Response
Object containing:Array of current vote account objects containing:Public key of the vote account (base-58 encoded)
Public key of the validator (base-58 encoded)
Amount of activated stake in lamports
Whether the account voted in the current epoch
Array of epoch credit objects containing:Number of credits earned in previous epoch
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()
}
};
}
}