Skip to main content
Version: Next (unstable)

Query hooks

Query hooks read from the local store (and trigger a fetch when the cache is cold). Every query hook shares { isLoading, error, refetch } alongside hook-specific data fields. Refetching is automatic after successful syncs, so most components don't need to call refetch() manually.

useAccounts​

Lists every account header tracked by the client. Since protocol 0.15, an account ID/header no longer identifies whether the account is a wallet or faucet; inspect the full account's components when you need that distinction.

import { useAccounts } from "@miden-sdk/react";

function AccountList() {
const { accounts, isLoading, error } = useAccounts();

if (isLoading) return <p>Loading…</p>;
if (error) return <p>{error.message}</p>;

return (
<>
<h3>Accounts ({accounts.length})</h3>
{accounts.map((account) => (
<div key={account.id().toString()}>{account.id().toString()}</div>
))}
</>
);
}

Return type (AccountsResult):

{
accounts: AccountHeader[]; // every tracked account
wallets: AccountHeader[]; // deprecated alias that mirrors accounts
faucets: AccountHeader[]; // deprecated; always empty
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
}

useAccount(id)​

Full details for a single account, including per-asset balances decorated with symbol + decimals when metadata is available.

import { useAccount } from "@miden-sdk/react";

function AccountDetails({ id, usdcFaucetId }: {
id: string;
usdcFaucetId: string; // canonical hex faucet ID, as returned by AccountId.toString()
}) {
const { account, assets, getBalance, isLoading, error } = useAccount(id);

if (isLoading) return <p>Loading…</p>;
if (error) return <p>{error.message}</p>;
if (!account) return <p>Not found</p>;

return (
<>
<p>Account: {account.bech32id()}</p>
<p>Nonce: {account.nonce().toString()}</p>
<p>USDC balance: {getBalance(usdcFaucetId).toString()}</p>

<ul>
{assets.map((a) => (
<li key={a.assetId}>
{a.amount.toString()} {a.symbol ?? a.assetId}
</li>
))}
</ul>
</>
);
}

Return type (AccountResult):

{
account: Account | null;
assets: AssetBalance[]; // { assetId, amount, symbol?, decimals? }
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
getBalance: (assetId: string) => bigint;
}

getBalance(assetId) returns the raw balance in base units, or 0n when no matching asset is found. Pass the canonical hex faucet ID used in assets[].assetId (as returned by AccountId.toString()); this helper compares strings directly and does not normalize bech32 IDs.

useNotes(filter?)​

Lists input notes (received) and consumable notes (ready to claim) with optional filtering. consumableNotes and consumableNoteSummaries exclude notes locked until a later block; sync again after they unlock.

import { useNotes } from "@miden-sdk/react";

function NotesInbox({ account }: { account: string }) {
const { notes, consumableNotes, noteSummaries, refetch } = useNotes({
status: "committed",
accountId: account,
});

return (
<>
<button onClick={refetch}>Refresh</button>
<h3>Tracked input notes, all accounts ({notes.length})</h3>
{noteSummaries.map((s) => (
<div key={s.id}>
{s.assets.map((a) => `${a.amount} ${a.symbol ?? a.assetId}`).join(", ")}
</div>
))}

<h3>Consumable by this account ({consumableNotes.length})</h3>
</>
);
}

Filter options (NotesFilter):

FieldValuesDescription
status"all" | "consumed" | "committed" | "expected" | "processing"Lifecycle filter for notes and noteSummaries; does not filter the consumable lists
accountIdAccountRefRestricts consumableNotes and consumableNoteSummaries to this account; does not filter notes or noteSummaries
senderstringSender ID (hex or bech32, normalized internally); filters only noteSummaries and consumableNoteSummaries
excludeIdsstring[]Excludes IDs only from noteSummaries and consumableNoteSummaries; raw records remain unchanged

Return type (NotesResult):

{
notes: InputNoteRecord[]; // raw SDK records
consumableNotes: ConsumableNoteRecord[];
noteSummaries: NoteSummary[]; // pre-computed { id, assets[], sender? }
consumableNoteSummaries: NoteSummary[];
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
}

noteSummaries is the pragmatic choice for UIs — it pre-extracts asset info and runs metadata resolution.

useNoteStream(options?)​

Temporal note tracking with first-seen timestamps and per-stream filtering. Useful for notification UIs that want to highlight new arrivals.

import { useState } from "react";
import { useNoteStream } from "@miden-sdk/react";

function NewNotesToast() {
const [since] = useState(() => Date.now());
const { notes, latest, markHandled, markAllHandled } = useNoteStream({
status: "committed", // default "committed"
since, // fixed at mount; drop notes seen earlier
amountFilter: (amount) => amount > 0n,
});

return (
<>
{latest && <p>New: {latest.id}</p>}
{notes.map((n) => (
<div key={n.id}>
{n.id} at {new Date(n.firstSeenAt).toISOString()}
<button onClick={() => markHandled(n.id)}>dismiss</button>
</div>
))}
<button onClick={markAllHandled}>Dismiss all</button>
</>
);
}

UseNoteStreamOptions fields: status, sender, since (numeric timestamp), excludeIds (Set<string> or string[]), and amountFilter for predicate-based filtering. The stream also exposes snapshot() for passing state across unmount / remount boundaries.

useTransactionHistory(options?)​

Transaction records, with optional filters for specific IDs or a custom TransactionFilter.

import { useTransactionHistory } from "@miden-sdk/react";

function HistoryTable() {
const { records, isLoading } = useTransactionHistory();
if (isLoading) return <p>Loading…</p>;

return (
<table>
<tbody>
{records.map((tx) => (
<tr key={tx.id().toHex()}>
<td>{tx.id().toHex()}</td>
<td>{tx.blockNum().toString()}</td>
</tr>
))}
</tbody>
</table>
);
}

Options:

FieldDescription
idSingle transaction ID lookup
idsList of transaction IDs
filterCustom TransactionFilter (overrides id / ids)
refreshOnSyncRe-fetch after every auto-sync (default true)

Result (TransactionHistoryResult):

{
records: TransactionRecord[];
record: TransactionRecord | null; // convenience when a single id was provided
status: TransactionStatus | null; // convenience when a single id was provided
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
}

In 0.17.0, TransactionFilter supports all(), ids(...), and uncommitted(), but no account filter. Filter the returned records locally using record.accountId().toString() and a canonical hex account ID:

const accountRecords = records.filter(
(record) => record.accountId().toString() === accountIdHex,
);

useSyncState​

Sync heights and manual-trigger controls.

import { useSyncState } from "@miden-sdk/react";

function SyncBadge() {
const { syncHeight, isSyncing, lastSyncTime, sync } = useSyncState();

return (
<button onClick={() => sync()} disabled={isSyncing}>
Block {syncHeight ?? "—"} {isSyncing && "(syncing…)"}
</button>
);
}

Manual sync() composes with the auto-sync loop (configured via autoSyncInterval on MidenProvider) — call it when you want to force an immediate refresh.

useAssetMetadata(assetIds?)​

Symbol + decimals lookup for a batch of asset IDs. The argument is an optional string[]; pass an empty array (or nothing) to read the global cache without triggering new fetches.

import { useAssetMetadata } from "@miden-sdk/react";

function TokenChip({ assetId }: { assetId: string }) {
const { assetMetadata } = useAssetMetadata([assetId]);
const meta = assetMetadata.get(assetId);
return <span>{meta?.symbol ?? assetId}</span>;
}

function TokenLegend({ ids }: { ids: string[] }) {
const { assetMetadata } = useAssetMetadata(ids);
return (
<>
{ids.map((id) => {
const m = assetMetadata.get(id);
return <span key={id}>{m?.symbol ?? id}</span>;
})}
</>
);
}

assetMetadata is a Map<string, AssetMetadata> keyed by asset ID. The hook dedupes and caches across components, so siblings that ask for overlapping IDs share cost.

Next​

  • Mutation hooks — create wallets, faucets, send tokens, consume notes.
  • Advanced — custom scripts, note import/export, session accounts.
  • Recipes — end-to-end patterns.