//! Fetching and iterating over storage entries. use subxt::dynamic::Value; use subxt::utils::AccountId32; use subxt::{Error, OnlineClient, PolkadotConfig}; #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")] mod polkadot {} #[tokio::main] async fn main() -> Result<(), Error> { let config = PolkadotConfig::new(); let api = OnlineClient::new(config).await?; let at_block = api.at_current_block().await?; // Here we use a statically generated address to fetch the storage entry, which // gives us type information for future actions on it. let account_balances = at_block .storage() .entry(polkadot::storage().system().account())?; // We can see the default value for this entry at this block, if one exists. if let Some(default_value) = account_balances.default_value() { let default_balance_info = default_value.decode_as::()?; println!("Default balance info: {default_balance_info}"); } // We can fetch a specific account balance by its key, like so (here I just picked a random key // I knew to exist from iterating over storage entries): let account_id = { let hex = "9a4d0faa2ba8c3cc5711852960940793acf55bf195b6eecf88fa78e961d0ce4a"; let bytes: [u8; 32] = hex::decode(hex).unwrap().try_into().unwrap(); AccountId32::from(bytes) }; let entry = account_balances.fetch((account_id,)).await?; // We can decode the value into our generic `Value` type, which can // represent any SCALE-encoded value, like so: let _balance_info = entry.decode_as::()?; // Or we can decode into a known shape. Any type implementing DecodeAsType can // be used here to extract fields you're interested in, or we can use the generated // type which already implements this: type AccountInfo = polkadot::system::storage::account::Output; let balance_info = entry.decode_as::()?; println!( "Single balance info from {account_id} => free: {} reserved: {} frozen: {} flags: {:?}", balance_info.data.free, balance_info.data.reserved, balance_info.data.frozen, balance_info.data.flags, ); // Or we can iterate over all of the account balances and print them out. Here we provide an // empty tuple, indicating that we want to iterate over everything and not only things under a certain key // (in the case of account balances, there is only one key anyway, but other storage entries may map from // several keys to a value, and for those we can choose which depth we iterate at by providing as many keys // as we want and leaving the rest). let mut all_balances = account_balances.iter(()).await?; while let Some(entry) = all_balances.next().await { let entry = entry?; let key = entry.key()?; // Because we provided a statically typed Address when we originally obtained this // storage entry (ie `polkadot::storage().system().account()`), we can statically // decode the key into its well typed constituent parts: let key_parts = key.decode()?; println!("Account ID: {}", key_parts.0); // Alternately, if we don't have type information available (or just want to decode // into some different type), we can do something like this instead: let account_id = key .part(0) .unwrap() .decode_as::()? .expect("We expect this key to decode into a 32 byte AccountId"); // Decode these values into our generic scale_value::Value type. Less efficient than // defining a static type as above, but easier for the sake of the example. let balance_info = entry.value().decode_as::()?; println!(" {account_id} => {balance_info}"); } Ok(()) }