Skip to content

Commit 2263b97

Browse files
feat: add multicall support for the CLI
Signed-off-by: Tomas Fabrizio Orsi <tomas.orsi@lambdaclass.com>
1 parent ed19fca commit 2263b97

File tree

6 files changed

+89
-17
lines changed

6 files changed

+89
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
* [BREAKING] Added genesis commitment header to `TonicRpcClient` requests (#1045).
2727
* Added authentication arguments support to `TransactionRequest` ([#1121](https://github.com/0xMiden/miden-client/pull/1121)).
2828
* Added bindings for retrieving storage `AccountDelta` in the web client ([#1098](https://github.com/0xMiden/miden-client/pull/1098)).
29-
29+
* Added `multicall` support for the CLI (#TBD)
30+
3031
## 0.10.1 (2025-07-26)
3132

3233
* Avoid passing unneeded nodes to `PartialMmr::from_parts` (#1081).

bin/miden-cli/src/commands/account.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use miden_objects::PrettyPrint;
99
use crate::config::CliConfig;
1010
use crate::errors::CliError;
1111
use crate::utils::{load_config_file, load_faucet_details_map, parse_account_id, update_config};
12-
use crate::{CLIENT_BINARY_NAME, create_dynamic_table};
12+
use crate::{client_binary_name, create_dynamic_table};
1313

1414
// ACCOUNT COMMAND
1515
// ================================================================================================
@@ -319,7 +319,10 @@ pub(crate) fn maybe_set_default_account(
319319

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

325328
Ok(())

bin/miden-cli/src/commands/new_account.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use tracing::debug;
2525
use crate::commands::account::maybe_set_default_account;
2626
use crate::errors::CliError;
2727
use crate::utils::load_config_file;
28-
use crate::{CLIENT_BINARY_NAME, CliKeyStore};
28+
use crate::{CliKeyStore, client_binary_name};
2929

3030
// CLI TYPES
3131
// ================================================================================================
@@ -130,7 +130,8 @@ impl NewWalletCmd {
130130

131131
println!("Successfully created new wallet.");
132132
println!(
133-
"To view account details execute {CLIENT_BINARY_NAME} account -s {account_address}",
133+
"To view account details execute {} account -s {account_address}",
134+
client_binary_name().display()
134135
);
135136

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

194195
println!("Successfully created new account.");
195196
println!(
196-
"To view account details execute {CLIENT_BINARY_NAME} account -s {account_address}"
197+
"To view account details execute {} account -s {account_address}",
198+
client_binary_name().display()
197199
);
198200

199201
Ok(())

bin/miden-cli/src/errors.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ use miden_objects::{AccountError, AccountIdError, AssetError, NetworkIdError};
77
use miette::Diagnostic;
88
use thiserror::Error;
99

10-
use crate::CLIENT_BINARY_NAME;
11-
10+
use crate::client_binary_name;
1211
type SourceError = Box<dyn Error + Send + Sync>;
1312

1413
#[derive(Debug, Diagnostic, Error)]
@@ -32,7 +31,9 @@ pub enum CliError {
3231
#[diagnostic(
3332
code(cli::config_error),
3433
help(
35-
"Check if the configuration file exists and is well-formed. If it does not exist, run `{CLIENT_BINARY_NAME} init` command to create it."
34+
"Check if the configuration file exists and is well-formed. If it does not exist, run `{} init` command to create it.",
35+
client_binary_name().display()
36+
3637
)
3738
)]
3839
Config(#[source] SourceError, String),

bin/miden-cli/src/lib.rs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::env;
2+
use std::ffi::OsString;
23
use std::sync::Arc;
34

4-
use clap::Parser;
5+
use clap::{Parser, Subcommand};
56
use comfy_table::{Attribute, Cell, ContentArrangement, Table, presets};
67
use errors::CliError;
78
use miden_client::account::AccountHeader;
@@ -38,7 +39,24 @@ mod utils;
3839
const CLIENT_CONFIG_FILE_NAME: &str = "miden-client.toml";
3940

4041
/// Client binary name.
41-
pub const CLIENT_BINARY_NAME: &str = "miden-client";
42+
/// Note: If, for whatever reason, we fail to obtain the client's executable
43+
/// name, then we simply display the standard "miden-client".
44+
pub fn client_binary_name() -> OsString {
45+
std::env::current_exe()
46+
.map(|executable| {
47+
executable
48+
.file_name()
49+
.expect("ERROR: failed to obtain the executable's file name")
50+
.to_os_string()
51+
})
52+
.inspect_err(|e| {
53+
eprintln!(
54+
"WARNING: Couldn't obtain the name of the current executable because of {e}.\
55+
Defaulting to miden-client."
56+
);
57+
})
58+
.unwrap_or(OsString::from("miden-client"))
59+
}
4260

4361
/// Number of blocks that must elapse after a transaction’s reference block before it is marked
4462
/// stale and discarded.
@@ -52,14 +70,53 @@ const TX_GRACEFUL_BLOCK_DELTA: u32 = 20;
5270
version,
5371
rename_all = "kebab-case"
5472
)]
55-
pub struct Cli {
73+
#[command(multicall(true))]
74+
pub struct MidenClientCli {
5675
#[command(subcommand)]
57-
action: Command,
76+
behavior: Behavior,
77+
}
78+
79+
impl From<MidenClientCli> for Cli {
80+
fn from(value: MidenClientCli) -> Self {
81+
match value.behavior {
82+
Behavior::MidenClient { cli } => cli,
83+
Behavior::External(args) => Cli::parse_from(args).set_external(),
84+
}
85+
}
86+
}
5887

88+
#[derive(Debug, Subcommand)]
89+
#[command(rename_all = "kebab-case")]
90+
enum Behavior {
91+
/// The Miden toolchain installer
92+
MidenClient {
93+
#[command(flatten)]
94+
cli: Cli,
95+
},
96+
97+
/// Used when the Miden Client CLI is called under a different name, like it
98+
/// is the case in [Midenup](https://github.com/0xMiden/midenup).
99+
#[command(external_subcommand)]
100+
External(Vec<OsString>),
101+
}
102+
103+
#[derive(Parser, Debug)]
104+
#[command(name = "miden-client")]
105+
pub struct Cli {
59106
/// Activates the executor's debug mode, which enables debug output for scripts
60107
/// that were compiled and executed with this mode.
61108
#[arg(short, long, default_value_t = false)]
62109
debug: bool,
110+
111+
#[command(subcommand)]
112+
action: Command,
113+
114+
/// Indicates whether the client's CLI is being called directly, or
115+
/// externally under an alias (like in the case of
116+
/// [Midenup](https://github.com/0xMiden/midenup).
117+
#[arg(skip)]
118+
#[allow(unused)]
119+
external: bool,
63120
}
64121

65122
/// CLI actions.
@@ -150,6 +207,11 @@ impl Cli {
150207
Command::ConsumeNotes(consume_notes) => consume_notes.execute(client).await,
151208
}
152209
}
210+
211+
fn set_external(mut self) -> Self {
212+
self.external = true;
213+
self
214+
}
153215
}
154216

155217
pub fn create_dynamic_table(headers: &[&str]) -> Table {

bin/miden-cli/src/main.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
use miden_client_cli::Cli;
1+
use clap::FromArgMatches;
2+
use miden_client_cli::{Cli, MidenClientCli};
23

34
extern crate std;
45

56
#[tokio::main]
67
async fn main() -> miette::Result<()> {
7-
use clap::Parser;
8-
98
tracing_subscriber::fmt::init();
9+
1010
// read command-line args
11-
let cli = Cli::parse();
11+
let input = <MidenClientCli as clap::CommandFactory>::command();
12+
let matches = input.get_matches();
13+
let parsed = MidenClientCli::from_arg_matches(&matches).unwrap_or_else(|err| err.exit());
14+
let cli: Cli = parsed.into();
1215

1316
// execute cli action
1417
Ok(cli.execute().await?)

0 commit comments

Comments
 (0)