Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Accounts / Smart Contracts

An Account represents the primary entity of the protocol. Capable of holding assets, storing data, and executing custom code. Each Account is a specialized smart contract providing a programmable interface for interacting with its state and assets.

What is the purpose of an account?

In Miden's hybrid UTXO- and account-based model, accounts enable the creation of expressive smart contracts via a Turing-complete language.

Account composition

An Account is composed of several core parts, illustrated below:

Account diagram

These parts are:

  1. ID
  2. Code
  3. Storage
  4. Vault
  5. Nonce

ID

note

An immutable and unique identifier for the Account.

A 120-bit long number represents the Account ID. This identifier is designed to contain the metadata of an account. The metadata includes the account type, account storage mode and the version of the Account. This metadata is included in the ID to ensure it can be determined without needing the full account state.

The ID is generated by hashing a randomly generated seed together with commitments to the initial code and storage of the Account. This process requires a small amount of Proof-of-Work (9 bits) that can be done even by low-powered devices. The resulting 256-bit hash is shortened to 120 bits.

An Account ID can be encoded in different formats:

  1. Bech32 (user-facing):
    • Example: mm1qzqge9n53l5dpyqav7y0d2j0ggl3dc9m
    • Benefits:
      • Built-in error detection via checksum algorithm
      • Human-readable prefix indicates network type
      • Less prone to transcription errors
    • Structure:
      • Human-readable prefix that determines the network:
        • mm (indicates Miden Mainnet)
        • mtst (indicates Miden Testnet)
        • mdev (indicates Miden Devnet)
      • Separator: 1
      • Data part with integrated checksum

Info

  • We strongly recommend encoding account IDs using Bech32 for all user-facing applications.
  1. Hexadecimal (debugging):
    • Example: 0x808c96748fe8d0901d6788f6aa4f42
    • Frequenty used encoding for blockchain addresses

Code

note

A collection of functions defining the Account’s programmable interface.

Every Miden Account is essentially a smart contract. The Code component defines the account’s functions, which can be invoked through both Note scripts and transaction scripts. Key characteristics include:

  • Mutable access: Only the Account’s own functions can modify its storage and vault. All state changes—such as updating storage slots, incrementing the nonce, or transferring assets—must occur through these functions.
  • Function commitment: Each function can be called by its MAST root. The root represents the underlying code tree as a 32-byte commitment. This ensures integrity, i.e., the caller calls what he expects.
  • Note creation: Account functions can generate new notes.

Storage

note

A flexible, arbitrary data store within the Account.

The storage is divided into a maximum of 255 indexed storage slots. Each slot can either store a 32-byte value or serve as a pointer to a key-value store with large amounts capacity.

  • StorageSlot::Value: Contains 32 bytes of arbitrary data.
  • StorageSlot::Map: Contains a StorageMap, a key-value store where both keys and values are 32 bytes. The slot's value is a commitment to the entire map.

StorageMap

A StorageMap is a key-value store implemented as a sparse Merkle tree (SMT) of depth 64. This allows an account to store a much larger amount of data than would be possible using only the account's storage slots. The root of the underlying SMT is stored in a single account storage slot, and each map entry is a leaf in the tree. When retrieving an entry (e.g., via account::get_map_item), its inclusion is proven using a Merkle proof.

Key properties of StorageMap:

  • Efficient, scalable storage: The SMT structure enables efficient storage and proof of inclusion for a large number of entries, while only storing the root in the account's storage slot.
  • Partial presence: Not all entries of the map need to be present at transaction execution time to access or modify the map. It is sufficient if only the accessed or modified items are present in the advice provider.
  • Key hashing: Since map keys are user-chosen and may not be uniformly distributed, keys are hashed before being inserted into the SMT. This ensures a more balanced tree and mitigates efficiency issues due to key clustering. The original keys are retained in a separate map, allowing for introspection (e.g., querying the set of stored original keys for debugging or explorer scenarios). This introduces some redundancy, but enables useful features such as listing all stored keys.

This design allows for flexible, scalable, and privacy-preserving storage within accounts, supporting both large datasets and efficient proof generation.

Vault

note

A collection of assets stored by the Account.

Large amounts of fungible and non-fungible assets can be stored in the account's vault.

Nonce

note

A counter incremented with each state update to the Account.

The nonce enforces ordering and prevents replay attacks. It must strictly increase with every Account state update. The increment must be less than but always greater than the previous nonce, ensuring a well-defined sequence of state changes.

If a smart contract function should be callable by other users, it must increment the account's nonce. Otherwise, only the contract owner—i.e., the party possessing the contract's key—can execute the function.

Account lifecycle

Throughout its lifetime, an Account progresses through various phases:

  • Creation and Deployment: Initialization of the Account on the network.
  • Active Operation: Continuous state updates via Account functions that modify the storage, nonce, and vault.
  • Termination or Deactivation: Optional, depending on the contract’s design and governance model.

Account creation

For an Account to be recognized by the network, it must exist in the account database maintained by Miden node(s).

However, a user can locally create a new Account ID before it’s recognized network-wide. The typical process might be:

  1. Alice generates a new Account ID locally (according to the desired Account type) using the Miden client.
  2. The Miden client checks with a Miden node to ensure the ID does not already exist.
  3. Alice shares the new ID with Bob (for example, to receive assets).
  4. Bob executes a transaction, creating a note containing assets for Alice.
  5. Alice consumes Bob’s note in her own transaction to claim the asset.
  6. Depending on the Account’s storage mode and transaction type, the operator receives the new Account ID and, if all conditions are met, includes it in the Account database.

Additional information

Account type

There are two main categories of accounts in Miden: basic accounts and faucets.

  • Basic Accounts: Basic Accounts may be either mutable or immutable:

    • Mutable: Code can be changed after deployment.
    • Immutable: Code cannot be changed once deployed.
  • Faucets: Faucets are always immutable and can be specialized by the type of assets they issue:

    • Fungible Faucet: Can issue fungible assets.
    • Non-fungible Faucet: Can issue non-fungible assets.

Type and mutability are encoded in the two most significant bits of the account's ID.

Account storage mode

Users can choose whether their accounts are stored publicly or privately. The preference is encoded in the third and forth most significant bits of the account's ID:

  • Public Accounts: The account’s state is stored on-chain, similar to how accounts are stored in public blockchains like Ethereum.

  • Network Accounts: The account’s state is stored on-chain, just like public accounts. Additionally, the network will monitor this account for any public notes targeted at it and attempt to create network transactions against the account, which consume the notes. Contracts that rely on a shared, publicly accessible state (e.g., a DEX) should be network accounts.

  • Private Accounts: Only a commitment (hash) to the account’s state is stored on-chain. This mode is suitable for users who prioritize privacy or plan to store a large amount of data in their Account. To interact with a private Account, a user must have knowledge of its interface.

The storage mode is chosen during Account creation, it cannot be changed later.

Network Accounts

Users can choose whether their Account is a network account or not. The network will monitor this account for any public notes targeted at it and attempt to create network transactions against the account, which consume the notes. Because the network must be able to execute transactions against such an account, the storage mode of such accounts must be Public.