Announcing Foundry-like tooling for Miden

Monday, September 21, 2026

miden call release banner

In partnership with Miden, Walnut is building Miden Foundry, a set of command-line tools for interacting with, inspecting, testing, and debugging Miden contracts, right from the terminal. The first of those commands miden call is available starting with midenup v1.0.1.

miden call shows developers what a transaction will do before they send it on-chain. It runs a procedure on a Miden account on the developer's own machine and shows the result. Nothing is sent to the network, so developers can run the same call as many times as they want, for free.

In this post, we give a short intro to Miden, explain why developers need these tools, show how miden call works, and share what comes next.

Introduction to Miden and its Unique Transaction Settlement

Miden is a zero-knowledge rollup for building private applications. On Miden, users run transactions on their own devices, and their data stays there unless they choose to make it public.

Every account is a smart contract with its own code, storage, and assets. A call can always read an account’s state, but it can change the state only if the account’s contract allows it. For example, a public counter might let anyone increment it.

Assets never move directly between accounts. They always move through notes: the sender puts the assets in a note, and the receiver accepts them by consuming the note in its own transaction. A note is like a letter: it holds assets and a script that says who can open it. So sending tokens takes two transactions instead of one.

A transaction runs and is proven on the user's device, and only then is it sent to the network. Once it settles, it cannot be reverted. That's where miden call comes in. It allows developers to preview what a transaction will do, without sending it to the chain.

What is Foundry and why Miden needs it

Foundry is a set of command-line tools for building smart contracts on Ethereum, and one of the most popular toolkits among Ethereum developers.

Developers use Foundry to write and run tests, including fuzz tests that try many random inputs. They use it to read data from deployed contracts, simulate a transaction before they send it, and look into past transactions to debug them. Most of this takes a single command.

This helps developers find bugs early, before a contract is live. They can try transactions without deploying anything or paying a fee. When a transaction fails, they can see exactly where and why, instead of sending it again and guessing.

Miden developers need the same tool: as transactions touch accounts, storage, and notes, they can't be reverted once they settle, and today checking what they will do often means writing a Rust script instead of running one command.

Meet miden call

miden call executes a Miden transaction in a dry-run mode. It allows developers to preview the outcome without sending a real transaction to the chain. It works much like cast call on Ethereum.

Example of how it works

Say a developer has a counter contract deployed to an account ${COUNTER} and wants to see the current count:

miden call ${COUNTER}:get-count --package counter-account.masp
Signature: get-count() -> felt

Result: 2
The transaction will have the following effects:

No notes will be consumed.

No notes will be created as a result of this transaction.

Account Storage will not be changed.
Account Vault will not be changed.
New account nonce: 2.

Now call a procedure that changes storage:

miden call ${COUNTER}:increment-count --package counter-account.masp
Signature: increment-count() -> felt

Result: 3
The transaction will have the following effects:

No notes will be consumed.

No notes will be created as a result of this transaction.

Account Storage will not be changed.
Storage map changes:
┌──────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────┐
│ Storage Slot                                 ┆ Map Key                                                            ┆ New Value                                                          │
╞══════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════╡
│ counter_account::counter_contract::count_map ┆ 0x0000000000000000000000000000000000000000000000000100000000000000 ┆ 0x0300000000000000000000000000000000000000000000000000000000000000 │
└──────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────┘
Account Vault will not be changed.
New account nonce: 3.

Nothing was sent to the network. The count on the chain is still the same. The developer only sees what would change if they sent this transaction.

The command takes four parameters: the account to be called, the procedure name, the contract package, and the arguments. Since miden call knows the procedure's types, developers can also pass arguments like an account ID or an asset in a readable form.

For example, a scoreboard contract deployed to the account ${BOARD} has an award procedure that takes a player's account ID and a score. The developer passes the player's account ID ${PLAYER} as it is, and miden call shows the result as a score-update with the previous and the current score:

miden call ${BOARD}:award ${PLAYER} 23 --package scoreboard-account.masp
Signature: award(account-id, felt) -> score-update

Result: score-update { previous: 0, current: 23 }
The transaction will have the following effects:

No notes will be consumed.

No notes will be created as a result of this transaction.

Storage changes:
┌───────────────────────────────────────┬────────────────────────────────────────────────────────────────────┐
│ Storage Slot                          ┆ New Value                                                          │
╞═══════════════════════════════════════╪════════════════════════════════════════════════════════════════════╡
│ scoreboard_account::scoreboard::total ┆ 0x1700000000000000000000000000000000000000000000000000000000000000 │
└───────────────────────────────────────┴────────────────────────────────────────────────────────────────────┘
Storage map changes:
┌────────────────────────────────────────┬────────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────┐
│ Storage Slot                           ┆ Map Key                                                            ┆ New Value                                                          │
╞════════════════════════════════════════╪════════════════════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════╡
│ scoreboard_account::scoreboard::scores ┆ 0x000000000000000000000000000000000013a458b4537752c17daa3b9d3a47ed ┆ 0x1700000000000000000000000000000000000000000000000000000000000000 │
└────────────────────────────────────────┴────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────┘
Account Vault will not be changed.
New account nonce: 2.

miden call works both for the developer's own contracts and for public contracts that someone else deployed. For someone else's contract, miden call reads its state from the network and can only read it: it shows the result, but it cannot change the contract's state. The call runs from one of the developer's own accounts, so they need at least one, which they can create with miden new-wallet.

  • miden account --inspect lists the procedures an account exposes, with their names and signatures. Developers use it to find which procedures they can call.
  • miden exec runs a Miden Assembly (MASM) script against an account, also without submitting anything. Developers use exec for MASM scripts and call for contract procedures.

What’s next

miden call is just the first step in building Foundry-like tooling for Miden. Next, we plan to add:

  • miden send to submit transactions. It runs the same call as miden call, proves it, and submits it to the network, like cast send on Ethereum. Commands that work with notes will also get a --dry-run flag, so developers can preview a note transaction before sending it.
  • Call trace, to see inside a call. With --trace, miden call shows the hierarchy of procedure calls, with the arguments and result of each call. Developers see exactly where a transaction goes wrong, instead of guessing.
  • A local package registry to stop passing file paths. It keeps contract packages in one place on the developer's machine, so developers can refer to a package by name and version, like [email protected] instead of a path to a file.
  • Fuzz testing to find edge cases developers did not think of. Instead of writing one test for one input, developers describe the kind of inputs a contract accepts, such as note inputs or transaction arguments, and the test runs many times with random values. If one of them breaks the contract, they see which input caused it, just like fuzz tests in Foundry.
  • Chain forking, to test against real contracts. Like Anvil's fork mode on Ethereum, it copies the state of the live chain to the developer's machine, so developers can try transactions against contracts that are already deployed. On Miden, this is more challenging because much of the state is private: it lives on users' devices and never reaches the chain. We will cover these challenges in a separate article.

Our goal is to give Miden developers the same fast workflow that Foundry gives Ethereum developers.

Let's talk

Got a project lined up ?

Bring us in for a scoped project with a defined outcome and timeline, or have us embed with your team and build alongside you.