Accounts
client.accounts is the resource namespace for everything account-related: creation, lookup, listing, import / export, and address management. All ID fields accept an AccountRef — a hex string, bech32 string, AccountId, Account, or AccountHeader — so you rarely need to convert between them.
Account type and auth scheme values
Account creation uses two small enums:
| Kind | Accepted values | Meaning |
|---|---|---|
AccountType.FungibleFaucet | 0 | Mintable token source |
AccountType.NonFungibleFaucet | 1 | Non-fungible token source |
AccountType.RegularAccountImmutableCode | 2 | Immutable wallet or contract |
AccountType.RegularAccountUpdatableCode | 3 | Mutable wallet or contract (default) |
auth field | "falcon" | "ecdsa" | Signing scheme — Falcon is the default |
storage field | "public" | "private" | "network" | Visibility and persistence mode |
All snippets below use these names. The SDK also ships friendly aliases (AccountType.MutableWallet, AccountType.ImmutableContract, etc.) but prefer the canonical names above when writing TypeScript — the aliases currently fail strict type-checking in some builds.
Create
Wallet
import { MidenClient, AccountType } from "@miden-sdk/miden-sdk";
const client = await MidenClient.createTestnet();
// Default: mutable wallet, private storage, Falcon auth
const wallet = await client.accounts.create();
// With explicit options
const wallet2 = await client.accounts.create({
type: AccountType.RegularAccountImmutableCode, // immutable wallet
storage: "public",
auth: "ecdsa",
seed: "my-seed", // hashed to 32 bytes via SHA-256
});
console.log(wallet.id().toString()); // hex
console.log(wallet.nonce().toString());
console.log(wallet.isPublic());
console.log(wallet.isPrivate());
console.log(wallet.isFaucet());
console.log(wallet.isRegularAccount());
Faucet
import { MidenClient, AccountType } from "@miden-sdk/miden-sdk";
const client = await MidenClient.createTestnet();
const faucet = await client.accounts.create({
type: AccountType.FungibleFaucet,
symbol: "TEST",
decimals: 8,
maxSupply: 10_000_000n, // number | bigint
});
const faucet2 = await client.accounts.create({
type: AccountType.FungibleFaucet,
symbol: "DAG",
decimals: 8,
maxSupply: 10_000_000n,
storage: "public",
auth: "falcon",
});
Contract
Contract accounts hold custom MASM code. Compile the code into an AccountComponent with client.compile.component(), then create the account:
import {
MidenClient,
AccountType,
AuthSecretKey,
StorageSlot,
} from "@miden-sdk/miden-sdk";
const counterCode = `
use miden::protocol::active_account
use miden::protocol::native_account
use miden::core::word
use miden::core::sys
const COUNTER_SLOT = word("miden::tutorials::counter")
pub proc get_count
push.COUNTER_SLOT[0..2] exec.active_account::get_item
exec.sys::truncate_stack
end
pub proc increment_count
push.COUNTER_SLOT[0..2] exec.active_account::get_item
add.1
push.COUNTER_SLOT[0..2] exec.native_account::set_item
exec.sys::truncate_stack
end
`;
const client = await MidenClient.createTestnet();
const component = await client.compile.component({
code: counterCode,
slots: [StorageSlot.emptyValue("miden::tutorials::counter")],
});
const seed = crypto.getRandomValues(new Uint8Array(32));
const auth = AuthSecretKey.rpoFalconWithRNG(seed);
const contract = await client.accounts.create({
type: AccountType.RegularAccountImmutableCode, // immutable contract
seed,
auth,
components: [component],
});
console.log("Contract:", contract.id().toString());
console.log("Is public:", contract.isPublic()); // contracts default to public
Contract defaults:
- Storage — defaults to
"public"(so other accounts can read state for FPI). Passstorage: "private"to override. - Auth — must be a concrete
AuthSecretKeyinstance, not a scheme string. The caller retains the key; the client uses it to sign transactions that touch the contract. - Seed — required, 32 bytes. Determines the account ID.
Pre-built via AccountBuilder
When you need full control — e.g. an external signer that provides an auth commitment instead of a secret key — build the account manually and hand it to insert():
import {
MidenClient,
AccountBuilder,
AccountComponent,
AccountStorageMode,
AccountType,
} from "@miden-sdk/miden-sdk";
const client = await MidenClient.createTestnet();
const commitment = /* externalSigner.getPublicKeyCommitment() */ (undefined as any);
const seed = new Uint8Array(32); // deterministic seed from your derivation path
const account = new AccountBuilder(seed)
.withAuthComponent(
AccountComponent.createAuthComponentFromCommitment(commitment, 1),
)
.accountType(AccountType.RegularAccountImmutableCode)
.storageMode(AccountStorageMode.public())
.withBasicWalletComponent()
.build().account;
await client.accounts.insert({ account });
accounts.insert() is local-only: it persists the account to the store without any network call. Use it when you already have a valid Account object and just need to track it.
Retrieve
get
const account = await client.accounts.get("0x1234...");
if (!account) {
console.log("Not found locally");
return;
}
console.log(account.id().toString());
console.log(account.nonce().toString());
console.log(account.isPublic());
console.log(account.isFaucet());
get only consults the local store. It returns null if the account isn't tracked.
getOrImport
// Returns the local copy if present; otherwise fetches from the network and stores it.
const account = await client.accounts.getOrImport(
"mtst1arjemrxne8lj5qz4mg9c8mtyxg954483",
);
console.log("Nonce:", account.nonce().toString());
Use getOrImport for accounts you didn't create — a faucet or contract deployed by another party, for example. Once imported, subsequent calls return the local copy without hitting the network.
get vs getOrImport:
getfor local-only reads. Cheap, no network.getOrImportwhen the account may need to be pulled from chain.
list
const accounts = await client.accounts.list();
for (const header of accounts) {
console.log(header.id().toString(), header.nonce().toString());
}
Returns AccountHeader[] — a lightweight summary suitable for listing UIs. Call get() if you need the full Account.
getDetails
const details = await client.accounts.getDetails("0x1234...");
console.log(details.account.id().toString());
console.log(details.vault); // AssetVault
console.log(details.storage); // AccountStorage
console.log(details.code); // AccountCode | null
console.log(details.keys); // Word[] (public-key commitments)
One round-trip returns the full account plus its vault, storage, code, and key commitments.
getBalance
const balance: bigint = await client.accounts.getBalance(
"0xACCOUNT...",
"0xFAUCET...",
);
console.log(`Balance: ${balance}`);
Address management
await client.accounts.addAddress("0xACCOUNT...", "mtst1address...");
await client.accounts.removeAddress("0xACCOUNT...", "mtst1address...");
Associates one or more bech32 addresses with an account. Useful when your UI lets users alias accounts by a human-readable string.
Import
client.accounts.import() accepts a discriminated union:
// 1. By reference — fetches a public account from the network.
await client.accounts.import("0x1234..."); // hex
await client.accounts.import("mtst1arjemrxne8lj5qz4mg9c8mtyxg954483"); // bech32
// 2. From a previously exported file.
await client.accounts.import({ file: accountFile });
// 3. From a seed — PUBLIC ACCOUNTS ONLY.
await client.accounts.import({
seed: initSeed, // Uint8Array
type: AccountType.RegularAccountUpdatableCode, // mutable wallet
auth: "falcon",
});
Import-by-seed works only for accounts originally created with storage: "public". Private account state is never published on-chain, so it can't be reconstructed from a seed alone. For private accounts, use the file export / import workflow below.
If you aren't sure whether the account is already in your local store, prefer getOrImport() — it skips the network call when the account is already known.
Export
const accountFile = await client.accounts.export("0x1234...");
// Persist accountFile to disk, send it to another device, etc.
AccountFile includes the full account state, code, seed (if new), and tracked secret keys. Treat it as sensitive.
Error behaviour
get()returnsnullwhen the account is not in the local store.getDetails(),getBalance(), andexport()throw"Account not found: 0x..."when the account is missing.import({ seed, ... })on a private account throws at resolve time — private state isn't recoverable from a seed.
Next
- Transactions — spend, mint, consume, swap.
- Compile — turn MASM into
AccountComponents for contract accounts. - Sync and store — refresh account state from the network.