Current State Queries
Real-time blockchain data retrieval methods for accessing current account states, balances, and program data
Current State Queries
Real-time data methods allow you to query the current state of the X1 Blockchain. These methods are optimized for retrieving up-to-date information about accounts, balances, program data, and token holdings.
Overview
Current state queries fetch data from the most recent confirmed or finalized state of the blockchain. Unlike historical queries, these methods are designed for:
- Real-time applications - Wallets, dashboards, and live monitoring tools
- Transaction preparation - Getting account states before building transactions
- Balance checks - Verifying sufficient funds or token balances
- Program state reads - Accessing current data from on-chain programs
When to Use Current State Methods
Use these methods when you need:
- Latest account information - Current balances, data, and ownership
- Live data for UI - Displaying real-time information to users
- Pre-transaction validation - Checking states before submitting transactions
- Token account queries - Finding and reading SPL token accounts
Don't use these methods for:
- Historical analysis or auditing (use Historical Data Methods)
- Tracking past transactions (use
getSignaturesForAddress) - Analytics over time periods (use archived block data)
Core Methods
getAccountInfo
Retrieves all information about a specific account including balance, owner, data, and executable status.
const { Connection, PublicKey } = require('@solana/web3.js');
const connection = new Connection(
'https://nexus.fortiblox.com/rpc',
{
commitment: 'confirmed',
httpHeaders: {
'X-API-Key': process.env.FORTIBLOX_API_KEY
}
}
);
async function getAccountInfo(address) {
const publicKey = new PublicKey(address);
const accountInfo = await connection.getAccountInfo(publicKey);
if (!accountInfo) {
console.log('Account does not exist');
return null;
}
console.log('Account Info:', {
lamports: accountInfo.lamports,
owner: accountInfo.owner.toString(),
executable: accountInfo.executable,
rentEpoch: accountInfo.rentEpoch,
dataLength: accountInfo.data.length
});
return accountInfo;
}
// Example usage
getAccountInfo('9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g');from solana.rpc.api import Client
from solana.publickey import PublicKey
import os
# Initialize connection
client = Client(
"https://nexus.fortiblox.com/rpc",
extra_headers={"X-API-Key": os.environ['FORTIBLOX_API_KEY']}
)
def get_account_info(address):
"""Get account information for a given address"""
pubkey = PublicKey(address)
response = client.get_account_info(
pubkey,
commitment="confirmed"
)
if not response.value:
print("Account does not exist")
return None
account = response.value
print(f"Account Info:")
print(f" Balance: {account.lamports / 1e9} SOL")
print(f" Owner: {account.owner}")
print(f" Executable: {account.executable}")
print(f" Data Length: {len(account.data)}")
return account
# Example usage
get_account_info('9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g')curl -X POST https://nexus.fortiblox.com/rpc \
-H "X-API-Key: $FORTIBLOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getAccountInfo",
"params": [
"9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g",
{
"encoding": "base64",
"commitment": "confirmed"
}
]
}'Use Cases:
- Reading program-derived account (PDA) data
- Verifying account ownership before operations
- Checking if an account is executable (program)
- Retrieving custom data stored in accounts
Performance Tips:
- Use
dataSliceto fetch only the portion of data you need - Choose
confirmedcommitment for faster responses - Cache results for accounts that don't change frequently
getBalance
Returns the balance of an account in lamports (1 SOL = 1,000,000,000 lamports).
async function getBalance(address) {
const publicKey = new PublicKey(address);
const balance = await connection.getBalance(publicKey);
// Convert lamports to SOL
const solBalance = balance / 1e9;
console.log(`Balance: ${balance} lamports (${solBalance} SOL)`);
return balance;
}
// Check if account has sufficient balance
async function hasSufficientBalance(address, requiredLamports) {
const balance = await getBalance(address);
return balance >= requiredLamports;
}
// Example: Check if user can afford transaction
const canAfford = await hasSufficientBalance(
'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg',
5000 // 5000 lamports for fee
);def get_balance(address):
"""Get SOL balance for an address"""
pubkey = PublicKey(address)
response = client.get_balance(
pubkey,
commitment="confirmed"
)
lamports = response.value
sol_balance = lamports / 1e9
print(f"Balance: {lamports} lamports ({sol_balance} SOL)")
return lamports
def has_sufficient_balance(address, required_lamports):
"""Check if account has sufficient balance"""
balance = get_balance(address)
return balance >= required_lamports
# Example usage
can_afford = has_sufficient_balance(
'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg',
5000
)curl -X POST https://nexus.fortiblox.com/rpc \
-H "X-API-Key: $FORTIBLOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getBalance",
"params": [
"vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg"
]
}'Use Cases:
- Wallet balance display
- Pre-transaction validation
- Monitoring account funding
- Payment verification
Performance Tips:
- Extremely lightweight (1 credit)
- Use
getMultipleAccountsfor checking multiple balances - Cache balances for non-critical displays
getProgramAccounts
Retrieves all accounts owned by a specific program with optional filtering.
async function getProgramAccounts(programId) {
const publicKey = new PublicKey(programId);
// Get all accounts owned by program
const accounts = await connection.getProgramAccounts(publicKey, {
commitment: 'confirmed',
encoding: 'base64'
});
console.log(`Found ${accounts.length} accounts`);
accounts.forEach(({ pubkey, account }) => {
console.log(`Account: ${pubkey.toString()}`);
console.log(` Balance: ${account.lamports} lamports`);
console.log(` Data size: ${account.data.length} bytes`);
});
return accounts;
}
// With filters - find token accounts with specific balance
async function getTokenAccountsWithMinBalance(tokenProgramId, minBalance) {
const accounts = await connection.getProgramAccounts(
new PublicKey(tokenProgramId),
{
commitment: 'confirmed',
filters: [
// Filter by data size (165 bytes for token accounts)
{ dataSize: 165 },
// Filter by token amount (bytes 64-72)
{
memcmp: {
offset: 64,
bytes: minBalance.toString()
}
}
]
}
);
return accounts;
}
// Example: Get all token accounts
const TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
getProgramAccounts(TOKEN_PROGRAM_ID);from solana.rpc.types import MemcmpOpts
def get_program_accounts(program_id):
"""Get all accounts owned by a program"""
pubkey = PublicKey(program_id)
response = client.get_program_accounts(
pubkey,
commitment="confirmed"
)
accounts = response.value
print(f"Found {len(accounts)} accounts")
for account in accounts:
print(f"Account: {account.pubkey}")
print(f" Balance: {account.account.lamports} lamports")
print(f" Data size: {len(account.account.data)} bytes")
return accounts
def get_token_accounts_with_filters(token_program_id):
"""Get token accounts with filtering"""
pubkey = PublicKey(token_program_id)
response = client.get_program_accounts(
pubkey,
commitment="confirmed",
encoding="base64",
filters=[
# Filter by data size
{"dataSize": 165}
]
)
return response.value
# Example usage
TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
get_program_accounts(TOKEN_PROGRAM_ID)# Get all program accounts
curl -X POST https://nexus.fortiblox.com/rpc \
-H "X-API-Key: $FORTIBLOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getProgramAccounts",
"params": [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{
"encoding": "base64",
"commitment": "confirmed",
"filters": [
{"dataSize": 165}
]
}
]
}'Use Cases:
- Finding all token accounts for a mint
- Discovering user-owned program accounts
- Scanning for specific account patterns
- Building account indexes
Performance Tips:
- Heavy method: 5 credits - Use sparingly
- Always use filters to reduce data transfer
- Consider caching results and updating incrementally
- Use
dataSliceto fetch only needed data portions
Performance Warning: getProgramAccounts can be expensive for programs with many accounts. Always use filters and consider pagination strategies.
getTokenAccountsByOwner
Retrieves all SPL token accounts owned by a specific address.
async function getTokenAccountsByOwner(ownerAddress) {
const publicKey = new PublicKey(ownerAddress);
const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
// Get all token accounts
const response = await connection.getTokenAccountsByOwner(
publicKey,
{ programId: TOKEN_PROGRAM_ID },
{ commitment: 'confirmed' }
);
console.log(`Found ${response.value.length} token accounts`);
response.value.forEach(({ pubkey, account }) => {
const data = account.data;
console.log(`Token Account: ${pubkey.toString()}`);
// Parse token account data for mint, amount, etc.
});
return response.value;
}
// Get token accounts for specific mint
async function getTokenAccountsForMint(ownerAddress, mintAddress) {
const owner = new PublicKey(ownerAddress);
const mint = new PublicKey(mintAddress);
const response = await connection.getTokenAccountsByOwner(
owner,
{ mint },
{ commitment: 'confirmed' }
);
console.log(`Found ${response.value.length} accounts for mint`);
return response.value;
}
// Example: Get all USDC accounts for a user
const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
getTokenAccountsForMint(
'9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g',
USDC_MINT
);def get_token_accounts_by_owner(owner_address):
"""Get all token accounts for an owner"""
owner = PublicKey(owner_address)
token_program = PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')
response = client.get_token_accounts_by_owner(
owner,
{"programId": token_program},
commitment="confirmed"
)
accounts = response.value
print(f"Found {len(accounts)} token accounts")
for account in accounts:
print(f"Token Account: {account.pubkey}")
return accounts
def get_token_accounts_for_mint(owner_address, mint_address):
"""Get token accounts for specific mint"""
owner = PublicKey(owner_address)
mint = PublicKey(mint_address)
response = client.get_token_accounts_by_owner(
owner,
{"mint": mint},
commitment="confirmed"
)
return response.value
# Example usage
USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
get_token_accounts_for_mint(
'9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g',
USDC_MINT
)# Get all token accounts by owner
curl -X POST https://nexus.fortiblox.com/rpc \
-H "X-API-Key: $FORTIBLOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getTokenAccountsByOwner",
"params": [
"9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g",
{
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
"encoding": "jsonParsed",
"commitment": "confirmed"
}
]
}'
# Get token accounts for specific mint
curl -X POST https://nexus.fortiblox.com/rpc \
-H "X-API-Key: $FORTIBLOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getTokenAccountsByOwner",
"params": [
"9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g",
{
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
},
{
"encoding": "jsonParsed"
}
]
}'Use Cases:
- Displaying user token holdings in wallets
- Finding token accounts before transfers
- Checking token balances
- Building portfolio views
Performance Tips:
- Heavy method: 5 credits - Cache results when possible
- Use
jsonParsedencoding for easy data access - Filter by mint to reduce response size
- Batch multiple owner queries if needed
getMultipleAccounts
Efficiently retrieves information for multiple accounts in a single request.
async function getMultipleAccounts(addresses) {
const publicKeys = addresses.map(addr => new PublicKey(addr));
const accounts = await connection.getMultipleAccountsInfo(publicKeys);
accounts.forEach((account, index) => {
if (!account) {
console.log(`Account ${addresses[index]}: Does not exist`);
return;
}
console.log(`Account ${addresses[index]}:`);
console.log(` Balance: ${account.lamports} lamports`);
console.log(` Owner: ${account.owner.toString()}`);
});
return accounts;
}
// Batch balance checks
async function getBatchBalances(addresses) {
const accounts = await getMultipleAccounts(addresses);
return accounts.map((account, index) => ({
address: addresses[index],
balance: account ? account.lamports : 0,
exists: account !== null
}));
}
// Example: Check multiple wallet balances
const wallets = [
'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg',
'9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g',
'AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc'
];
getBatchBalances(wallets);def get_multiple_accounts(addresses):
"""Get information for multiple accounts"""
pubkeys = [PublicKey(addr) for addr in addresses]
response = client.get_multiple_accounts(
pubkeys,
commitment="confirmed"
)
accounts = response.value
for i, account in enumerate(accounts):
if not account:
print(f"Account {addresses[i]}: Does not exist")
continue
print(f"Account {addresses[i]}:")
print(f" Balance: {account.lamports} lamports")
print(f" Owner: {account.owner}")
return accounts
def get_batch_balances(addresses):
"""Get balances for multiple addresses"""
accounts = get_multiple_accounts(addresses)
return [
{
"address": addresses[i],
"balance": account.lamports if account else 0,
"exists": account is not None
}
for i, account in enumerate(accounts)
]
# Example usage
wallets = [
'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg',
'9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g',
'AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc'
]
get_batch_balances(wallets)curl -X POST https://nexus.fortiblox.com/rpc \
-H "X-API-Key: $FORTIBLOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getMultipleAccounts",
"params": [
[
"vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
"9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g",
"AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc"
],
{
"encoding": "base64",
"commitment": "confirmed"
}
]
}'Use Cases:
- Checking multiple wallet balances at once
- Fetching related account data together
- Portfolio value calculations
- Batch validation before transactions
Performance Tips:
- More efficient than individual
getAccountInfocalls - Maximum 100 accounts per request
- Returns results in same order as input
- Credits: 3 (much cheaper than 100 individual calls)
Commitment Levels Explained
Commitment levels determine how confirmed the data is. Choose based on your speed vs. safety requirements:
processed (Fastest, Least Safe)
- Speed: Immediate
- Confirmation: Node has received and processed in a valid block
- Risk: May be rolled back (not guaranteed to be final)
- Use for: Real-time UI updates, non-critical displays
const connection = new Connection(url, 'processed');confirmed (Balanced)
- Speed: ~400ms typical
- Confirmation: Supermajority of validators have voted
- Risk: Very unlikely to be rolled back
- Use for: Most applications, transaction preparation
const connection = new Connection(url, 'confirmed'); // Defaultfinalized (Slowest, Safest)
- Speed: ~13 seconds typical
- Confirmation: 32+ confirmed blocks (cannot be rolled back)
- Risk: Zero (permanent)
- Use for: Financial transactions, critical operations
const connection = new Connection(url, 'finalized');Recommendation: Use confirmed for most operations. Only use finalized for critical operations where you absolutely cannot tolerate rollbacks.
Performance Optimization
1. Use Appropriate Data Slicing
Fetch only the data you need:
// ❌ BAD - Fetches entire 10MB account
const account = await connection.getAccountInfo(publicKey);
// ✅ GOOD - Fetches only 100 bytes at offset 0
const account = await connection.getAccountInfo(publicKey, {
dataSlice: { offset: 0, length: 100 }
});2. Batch Related Requests
// ❌ BAD - 3 separate requests
const balance1 = await connection.getBalance(pubkey1);
const balance2 = await connection.getBalance(pubkey2);
const balance3 = await connection.getBalance(pubkey3);
// ✅ GOOD - 1 batched request
const accounts = await connection.getMultipleAccountsInfo([
pubkey1, pubkey2, pubkey3
]);3. Implement Smart Caching
class AccountCache {
constructor(ttl = 60000) {
this.cache = new Map();
this.ttl = ttl;
}
async getAccountInfo(connection, publicKey) {
const key = publicKey.toString();
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
const data = await connection.getAccountInfo(publicKey);
this.cache.set(key, { data, timestamp: Date.now() });
return data;
}
}
const cache = new AccountCache(60000); // 1 minute TTL
const account = await cache.getAccountInfo(connection, publicKey);4. Use Filters Effectively
// ❌ BAD - Fetches all accounts, filters client-side
const allAccounts = await connection.getProgramAccounts(programId);
const filtered = allAccounts.filter(a => a.account.data.length === 165);
// ✅ GOOD - Filters server-side
const filtered = await connection.getProgramAccounts(programId, {
filters: [{ dataSize: 165 }]
});Common Pitfalls
1. Not Handling Null Accounts
// ❌ BAD - Will crash if account doesn't exist
const account = await connection.getAccountInfo(publicKey);
const balance = account.lamports;
// ✅ GOOD - Handles non-existent accounts
const account = await connection.getAccountInfo(publicKey);
if (!account) {
console.log('Account does not exist');
return;
}
const balance = account.lamports;2. Excessive getProgramAccounts Calls
// ❌ BAD - Expensive, called frequently
setInterval(async () => {
const accounts = await connection.getProgramAccounts(programId);
}, 1000);
// ✅ GOOD - Cache and update incrementally
let accountsCache = [];
setInterval(async () => {
// Only fetch changes or use WebSocket subscriptions
accountsCache = await fetchAccountChanges(accountsCache);
}, 5000);3. Ignoring Commitment Levels
// ❌ BAD - May see inconsistent data
const balance1 = await connection.getBalance(pubkey, 'processed');
const balance2 = await connection.getBalance(pubkey, 'finalized');
// ✅ GOOD - Use consistent commitment
const commitment = 'confirmed';
const balance1 = await connection.getBalance(pubkey, commitment);
const balance2 = await connection.getBalance(pubkey, commitment);Real-World Use Cases
Wallet Balance Display
async function getWalletPortfolio(ownerAddress) {
const owner = new PublicKey(ownerAddress);
// Get SOL balance
const solBalance = await connection.getBalance(owner);
// Get all token accounts
const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
const tokenAccounts = await connection.getTokenAccountsByOwner(
owner,
{ programId: TOKEN_PROGRAM_ID },
{ encoding: 'jsonParsed' }
);
// Parse token balances
const tokens = tokenAccounts.value.map(({ account }) => {
const parsed = account.data.parsed;
return {
mint: parsed.info.mint,
amount: parsed.info.tokenAmount.uiAmount,
decimals: parsed.info.tokenAmount.decimals
};
});
return {
sol: solBalance / 1e9,
tokens
};
}Pre-Transaction Validation
async function validateTransfer(from, to, amount) {
// Check sender has sufficient balance
const balance = await connection.getBalance(from);
const fee = 5000; // Estimated fee in lamports
if (balance < amount + fee) {
throw new Error(`Insufficient balance. Has ${balance}, needs ${amount + fee}`);
}
// Verify recipient account exists (optional)
const toAccount = await connection.getAccountInfo(to);
if (!toAccount) {
console.log('Recipient account does not exist (will be created)');
}
return true;
}NFT Metadata Lookup
async function getNFTMetadata(nftMintAddress) {
const mint = new PublicKey(nftMintAddress);
// Get token accounts holding this NFT
const largestAccounts = await connection.getTokenLargestAccounts(mint);
if (largestAccounts.value.length === 0) {
return null;
}
// Get metadata PDA
const metadataPDA = await getMetadataPDA(mint);
const metadata = await connection.getAccountInfo(metadataPDA);
if (!metadata) {
return null;
}
// Parse metadata (simplified)
return parseMetadata(metadata.data);
}