Skip to content

feat: add multicall suuport for the CLI #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
* [BREAKING] Added genesis commitment header to `TonicRpcClient` requests (#1045).
* Added authentication arguments support to `TransactionRequest` ([#1121](https://github.com/0xMiden/miden-client/pull/1121)).
* Added bindings for retrieving storage `AccountDelta` in the web client ([#1098](https://github.com/0xMiden/miden-client/pull/1098)).

* Added `multicall` support for the CLI ([#1141](https://github.com/0xMiden/miden-client/pull/1141))

## 0.10.1 (2025-07-26)

* Avoid passing unneeded nodes to `PartialMmr::from_parts` (#1081).
Expand Down
7 changes: 5 additions & 2 deletions bin/miden-cli/src/commands/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use miden_objects::PrettyPrint;
use crate::config::CliConfig;
use crate::errors::CliError;
use crate::utils::{load_config_file, load_faucet_details_map, parse_account_id, update_config};
use crate::{CLIENT_BINARY_NAME, create_dynamic_table};
use crate::{client_binary_name, create_dynamic_table};

// ACCOUNT COMMAND
// ================================================================================================
Expand Down Expand Up @@ -319,7 +319,10 @@ pub(crate) fn maybe_set_default_account(

let account_id = account_id.to_bech32(current_config.rpc.endpoint.0.to_network_id()?);
println!("Setting account {account_id} as the default account ID.");
println!("You can unset it with `{CLIENT_BINARY_NAME} account --default none`.");
println!(
"You can unset it with `{} account --default none`.",
client_binary_name().display()
);
current_config.default_account_id = Some(account_id);

Ok(())
Expand Down
8 changes: 5 additions & 3 deletions bin/miden-cli/src/commands/new_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use tracing::debug;
use crate::commands::account::maybe_set_default_account;
use crate::errors::CliError;
use crate::utils::load_config_file;
use crate::{CLIENT_BINARY_NAME, CliKeyStore};
use crate::{CliKeyStore, client_binary_name};

// CLI TYPES
// ================================================================================================
Expand Down Expand Up @@ -130,7 +130,8 @@ impl NewWalletCmd {

println!("Successfully created new wallet.");
println!(
"To view account details execute {CLIENT_BINARY_NAME} account -s {account_address}",
"To view account details execute {} account -s {account_address}",
client_binary_name().display()
);

maybe_set_default_account(&mut current_config, new_account.id())?;
Expand Down Expand Up @@ -193,7 +194,8 @@ impl NewAccountCmd {

println!("Successfully created new account.");
println!(
"To view account details execute {CLIENT_BINARY_NAME} account -s {account_address}"
"To view account details execute {} account -s {account_address}",
client_binary_name().display()
);

Ok(())
Expand Down
7 changes: 4 additions & 3 deletions bin/miden-cli/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use miden_objects::{AccountError, AccountIdError, AssetError, NetworkIdError};
use miette::Diagnostic;
use thiserror::Error;

use crate::CLIENT_BINARY_NAME;

use crate::client_binary_name;
type SourceError = Box<dyn Error + Send + Sync>;

#[derive(Debug, Diagnostic, Error)]
Expand All @@ -32,7 +31,9 @@ pub enum CliError {
#[diagnostic(
code(cli::config_error),
help(
"Check if the configuration file exists and is well-formed. If it does not exist, run `{CLIENT_BINARY_NAME} init` command to create it."
"Check if the configuration file exists and is well-formed. If it does not exist, run `{} init` command to create it.",
client_binary_name().display()

)
)]
Config(#[source] SourceError, String),
Expand Down
72 changes: 68 additions & 4 deletions bin/miden-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::env;
use std::ffi::OsString;
use std::sync::Arc;

use clap::Parser;
use clap::{Parser, Subcommand};
use comfy_table::{Attribute, Cell, ContentArrangement, Table, presets};
use errors::CliError;
use miden_client::account::AccountHeader;
Expand Down Expand Up @@ -38,7 +39,24 @@ mod utils;
const CLIENT_CONFIG_FILE_NAME: &str = "miden-client.toml";

/// Client binary name.
pub const CLIENT_BINARY_NAME: &str = "miden-client";
///
/// If, for whatever reason, we fail to obtain the client's executable name,
/// then we simply display the standard "miden-client".
pub fn client_binary_name() -> OsString {
std::env::current_exe()
.inspect_err(|e| {
eprintln!(
"WARNING: Couldn't obtain the path of the current executable because of {e}.\
Defaulting to miden-client."
);
})
.and_then(|executable_path| {
executable_path.file_name().map(std::ffi::OsStr::to_os_string).ok_or(
std::io::Error::other("Couldn't obtain the file name of the current executable"),
)
})
.unwrap_or(OsString::from("miden-client"))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If, for whatever reason, current_exe fails to return the executable's name, I went with returning a default. Mainly because the error case scenario is a bit far fetched, for instance, deleting the executable file during execution (for more details, see: https://doc.rust-lang.org/std/env/fn.current_exe.html#errors).

Worst case scenario, the displayed message is invalid, but we do get a diagnostic thanks to inspect_err.

}

/// Number of blocks that must elapse after a transaction’s reference block before it is marked
/// stale and discarded.
Expand All @@ -52,14 +70,55 @@ const TX_GRACEFUL_BLOCK_DELTA: u32 = 20;
version,
rename_all = "kebab-case"
)]
pub struct Cli {
#[command(multicall(true))]
pub struct MidenClientCli {
#[command(subcommand)]
action: Command,
behavior: Behavior,
}

impl From<MidenClientCli> for Cli {
fn from(value: MidenClientCli) -> Self {
match value.behavior {
Behavior::MidenClient { cli } => cli,
Behavior::External(args) => Cli::parse_from(args).set_external(),
}
}
}

#[derive(Debug, Subcommand)]
#[command(rename_all = "kebab-case")]
enum Behavior {
/// The Miden Client CLI.
MidenClient {
#[command(flatten)]
cli: Cli,
},

/// Used when the Miden Client CLI is called under a different name, like
/// when it is called from [Midenup](https://github.com/0xMiden/midenup).
/// Vec<OsString> holds the "raw" arguments passed to the command line,
/// analogous to `argv`.
#[command(external_subcommand)]
External(Vec<OsString>),
}

#[derive(Parser, Debug)]
#[command(name = "miden-client")]
pub struct Cli {
/// Activates the executor's debug mode, which enables debug output for scripts
/// that were compiled and executed with this mode.
#[arg(short, long, default_value_t = false)]
debug: bool,

#[command(subcommand)]
action: Command,

/// Indicates whether the client's CLI is being called directly, or
/// externally under an alias (like in the case of
/// [Midenup](https://github.com/0xMiden/midenup).
#[arg(skip)]
#[allow(unused)]
external: bool,
}

/// CLI actions.
Expand Down Expand Up @@ -150,6 +209,11 @@ impl Cli {
Command::ConsumeNotes(consume_notes) => consume_notes.execute(client).await,
}
}

fn set_external(mut self) -> Self {
self.external = true;
self
}
}

pub fn create_dynamic_table(headers: &[&str]) -> Table {
Expand Down
11 changes: 7 additions & 4 deletions bin/miden-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use miden_client_cli::Cli;
use clap::FromArgMatches;
use miden_client_cli::{Cli, MidenClientCli};

extern crate std;

#[tokio::main]
async fn main() -> miette::Result<()> {
use clap::Parser;

tracing_subscriber::fmt::init();

// read command-line args
let cli = Cli::parse();
let input = <MidenClientCli as clap::CommandFactory>::command();
let matches = input.get_matches();
let parsed = MidenClientCli::from_arg_matches(&matches).unwrap_or_else(|err| err.exit());
let cli: Cli = parsed.into();

// execute cli action
Ok(cli.execute().await?)
Expand Down
Loading