Skip to main content
Version: 0.14

Read Storage Values

Let's explore how to interact with public accounts and retrieve their storage data.

Understanding Account Storage​

Miden accounts contain several types of data you can read.

Account Components:

  • Vault: Contains the account's assets (tokens)
  • Storage: Key-value data store with up to 255 slots
  • Code: The account's smart contract logic (MAST root)
  • Nonce: Nonce that increments with each state change to prevent double spend

Storage Visibility:

  • Public accounts: All data is publicly accessible and can be read by anyone
  • Private accounts: Only commitments are public; full data is held privately

Set Up Development Environment​

To run the code examples in this guide, you'll need to set up a development environment. If you haven't already, follow the setup instructions in the Accounts guide.

Reading from a Public Smart Contract​

Let's interact with a counter contract deployed on the Miden testnet. This contract maintains a simple counter value in a named storage map slot.

Reading the Count of a Counter contract​

integration/src/bin/read-count.rs
use miden_client::{
account::{Account, AccountId, StorageSlotName},
builder::ClientBuilder,
keystore::FilesystemKeyStore,
rpc::{Endpoint, GrpcClient},
Felt, Word,
};
use miden_client_sqlite_store::ClientBuilderSqliteExt;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize RPC connection
let endpoint = Endpoint::testnet();
let timeout_ms = 10_000;
let rpc_client = Arc::new(GrpcClient::new(&endpoint, timeout_ms));

// Initialize keystore
let keystore_path = std::path::PathBuf::from("./keystore");
let keystore =
Arc::new(FilesystemKeyStore::new(keystore_path).unwrap());

let store_path = std::path::PathBuf::from("./store.sqlite3");

// Initialize client to connect with the Miden Testnet.
// NOTE: The client is our entry point to the Miden network.
// All interactions with the network go through the client.
let mut client = ClientBuilder::new()
.rpc(rpc_client)
.sqlite_store(store_path)
.authenticator(keystore.clone())
.in_debug_mode(true.into())
.build()
.await?;

client.sync_state().await?;

//------------------------------------------------------------
// READ PUBLIC STATE OF THE COUNTER ACCOUNT
//------------------------------------------------------------

let counter_account_id = AccountId::from_hex("0x224a96d294e10d006aef3d4f1b0876")?;

client.import_account_by_id(counter_account_id).await?;

let counter_account: Account = client
.get_account(counter_account_id)
.await?
.ok_or_else(|| anyhow::anyhow!("Account not found"))?
.try_into()?;

// Read the count from the counter account's named storage map slot
let slot_name = StorageSlotName::new(
"miden::component::miden_counter_account::count_map"
)?;
let count_key = Word::from([Felt::new(0), Felt::new(0), Felt::new(0), Felt::new(1)]);
let count = counter_account
.storage()
.get_map_item(&slot_name, count_key)?;

println!("Count: {:?}", count);

Ok(())
}
src/demo.ts
import { MidenClient, Word } from "@miden-sdk/miden-sdk";

export async function demo() {
// Initialize client to connect with the Miden Testnet.
const client = await MidenClient.createTestnet();

const counterAccountId = "0x224a96d294e10d006aef3d4f1b0876";

// Fetch the counter account (imports it into the local store if needed).
const counter = await client.accounts.getOrImport(counterAccountId);

// Get the count from the counter account by querying its storage map
// using the named storage slot and counter key.
const slotName = "miden::component::miden_counter_account::count_map";
const counterKey = new Word(BigUint64Array.from([0n, 0n, 0n, 1n]));
const count = counter.storage().getMapItem(slotName, counterKey);

// The count value is a WORD (array of 4 u64 values).
// The 4th value is the counter number.
console.log("Count:", Number(count?.toU64s()[3]));
}
Expected output
Count: 1

Reading Account Token Balances​

You can also query the assets (tokens) held by an account:

integration/src/bin/token-balance.rs
use miden_client::{
account::{Account, AccountId},
builder::ClientBuilder,
keystore::FilesystemKeyStore,
rpc::{Endpoint, GrpcClient},
};
use miden_client_sqlite_store::ClientBuilderSqliteExt;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize RPC connection
let endpoint = Endpoint::testnet();
let timeout_ms = 10_000;
let rpc_client = Arc::new(GrpcClient::new(&endpoint, timeout_ms));

// Initialize keystore
let keystore_path = std::path::PathBuf::from("./keystore");
let keystore =
Arc::new(FilesystemKeyStore::new(keystore_path).unwrap());

let store_path = std::path::PathBuf::from("./store.sqlite3");

// Initialize client to connect with the Miden Testnet.
// NOTE: The client is our entry point to the Miden network.
// All interactions with the network go through the client.
let mut client = ClientBuilder::new()
.rpc(rpc_client)
.sqlite_store(store_path)
.authenticator(keystore.clone())
.in_debug_mode(true.into())
.build()
.await?;

client.sync_state().await?;

//------------------------------------------------------------
// READ TOKEN BALANCE OF AN ACCOUNT
//------------------------------------------------------------

let alice_account_id = AccountId::from_hex("0x5b2840a923dedc102ea67e0c1eba3c")?;
let faucet_account_id = AccountId::from_hex("0x29dd1dc628d2842032e751ed1b5da7")?;

client.import_account_by_id(alice_account_id).await?;

let alice_account: Account = client
.get_account(alice_account_id)
.await?
.ok_or_else(|| anyhow::anyhow!("Account not found"))?
.try_into()?;

let balance = alice_account
.vault()
.get_balance(faucet_account_id)?;

println!("Alice's TEST token balance: {:?}", balance);

Ok(())
}
src/demo.ts
import { MidenClient } from "@miden-sdk/miden-sdk";

export async function demo() {
// Initialize client to connect with the Miden Testnet.
const client = await MidenClient.createTestnet();

const aliceId = "0x5b2840a923dedc102ea67e0c1eba3c";
const faucetId = "0x29dd1dc628d2842032e751ed1b5da7";

// Fetch Alice's account (imports it into the local store if needed)
// and query her balance for the faucet's token.
await client.accounts.getOrImport(aliceId);
const balance = await client.accounts.getBalance(aliceId, faucetId);

console.log("Alice's TEST token balance:", Number(balance));
}
Expected output
Alice's TEST token balance: 900