Fetch an account#
Account reads keep three steps apart: the transport fetches bytes, the result tells you whether the account exists, and a codec you pick decodes the data. This page fetches raw account bytes with Client::fetch_encoded_account, handles accounts that do not exist, and decodes a sysvar and a System nonce account.
The examples assume the client from the Quick start. Account data can be larger than the default 8192-byte response budget, so build the client with a larger Limits:
use solana_kit_client::{Client, Limits};
use solana_kit_native::{HttpConfig, NativeHttp};
let transport = NativeHttp::new("https://api.devnet.solana.com", HttpConfig::default())?;
let client = Client::new(transport, Limits { bytes: 64 * 1024, depth: 32 });Fetch one account#
use solana_kit_client::methods::{Contextual, ReadConfig};
use solana_kit_core::{Address, accounts::MaybeAccount};
let address: Address = "SysvarRent111111111111111111111111111111111".parse()?;
let Contextual { context, value } = client
.fetch_encoded_account(address, ReadConfig::default())
.await?;
match value {
MaybeAccount::Present(account) => {
println!(
"slot {}: owner {}, {} lamports, {} bytes",
context.slot,
account.owner,
account.lamports,
account.data.len()
);
}
MaybeAccount::Missing(address) => println!("no account at {address}"),
}fetch_encoded_account asks for the whole account in base64 and returns Contextual<MaybeEncodedAccount>. MaybeEncodedAccount is short for MaybeAccount<Vec<u8>>:
MaybeAccount::Present(Account<Vec<u8>>)holdsaddress,owner,lamports,executable,space,rent_epochand the rawdata.MaybeAccount::Missing(Address)means the node reported no account. A missing account is a normal result, not an error.
To treat a missing account as an error, call .require(). It returns Result<Account<T>, AccountError>, and the error still holds the missing address.
ReadConfig sets commitment and min_context_slot. ReadConfig::default() sends neither, so the node uses its defaults.
Fetch several accounts#
fetch_encoded_accounts returns results in the order you asked, keeping duplicates and missing entries:
use solana_kit_client::methods::{Commitment, ReadConfig};
let config = ReadConfig {
commitment: Some(Commitment::Confirmed),
..ReadConfig::default()
};
let accounts = client
.fetch_encoded_accounts(vec![address, Address::from_bytes([9; 32])], config)
.await?;
for account in &accounts.value {
println!("{} exists: {}", account.address(), account.exists());
}If the node returns a different number of entries than you requested, the call fails.
Decode account data#
An encoded account decodes with any solana_kit_core::codecs::Decoder. Account::decode(decoder, expected_owner, limits) checks three things before it decodes: the owner matches, the data length matches the reported space, and no bytes are left over. The result is an Account<T> that keeps all the metadata.
The limits argument is solana_kit_core::codecs::Limits, not the client's Limits. It caps the bytes and decoded elements the decoder may consume. The examples import it as DecodeLimits to keep the two apart.
A sysvar#
use solana_kit_client::methods::ReadConfig;
use solana_kit_core::{
codecs::Limits as DecodeLimits,
sysvars::{CLOCK_ADDRESS, Clock, OWNER_ADDRESS, SysvarCodec},
};
let clock = client
.fetch_encoded_account(CLOCK_ADDRESS, ReadConfig::default())
.await?
.value
.require()?
.decode(&SysvarCodec::<Clock>::NEW, OWNER_ADDRESS, DecodeLimits::new(40, 0))?;
println!("epoch {} at slot {}", clock.data.epoch, clock.data.slot);solana_kit_core::sysvars has fixed layouts and addresses for the common sysvars. Variable-length sysvars such as SlotHashes need an element budget in their limits.
A System nonce account#
Program crates provide the decoders for their accounts. solana_kit_system::decode_nonce checks that the System Program owns the account and that it is exactly 80 bytes, then decodes it:
use solana_kit_core::{accounts::MaybeAccount, codecs::Limits as DecodeLimits};
use solana_kit_system::decode_nonce;
let maybe = client
.fetch_encoded_account(nonce_address, ReadConfig::default())
.await?
.value;
if let MaybeAccount::Present(account) = maybe {
let nonce = decode_nonce(account, DecodeLimits::new(80, 0))?;
if let Some(data) = nonce.data.durable_data() {
println!("authority {}, nonce {}", data.authority, data.blockhash);
}
}durable_data() returns the fields only for an initialized nonce of the Current version. Legacy and uninitialized nonce accounts stay distinct, so you never mistake their bytes for a usable nonce.
Parsed JSON reads#
fetch_json_parsed_account and fetch_json_parsed_accounts ask the node for jsonParsed encoding. They return MaybeAccount<AccountData>. AccountData keeps the program's parsed JSON exactly as received, or the binary fallback if the node could not parse the account. Use encoded reads with a codec when you need byte-exact decoding.
For data slices, other encodings, program account scans and token reads, see solana_kit_client::methods::accounts and methods::tokens, described in Accounts and sysvars and RPC.