Skip to main content

casper_client/
cli.rs

1//! An API suitable for use by a CLI binary.
2//!
3//! It provides functions and types largely based around strings and integers, as would be expected
4//! to be input by a CLI user.  The functions then parse these inputs into the expected Rust types
5//! and pass them through to the equivalent API functions defined in the root of the library.
6//!
7//! # Common Parameters
8//!
9//! Many of the functions have similar parameters.  Descriptions for these common ones follow:
10//!
11//! * `maybe_rpc_id` - The JSON-RPC identifier, applied to the request and returned in the response.
12//!   If it can be parsed as an `i64` it will be used as a JSON integer. If empty, a random `i64`
13//!   will be assigned.  Otherwise the provided string will be used verbatim.
14//! * `node_address` - The hostname or IP and port of the server, e.g. `http://127.0.0.1:7777`.
15//! * `verbosity_level` - When `1`, the JSON-RPC request will be printed to `stdout` with long
16//!   string fields (e.g. hex-formatted raw Wasm bytes) shortened to a string indicating the char
17//!   count of the field.  When `verbosity_level` is greater than `1`, the request will be printed
18//!   to `stdout` with no abbreviation of long fields.  When `verbosity_level` is `0`, the request
19//!   will not be printed to `stdout`.
20//! * `maybe_block_id` - Must be a hex-encoded, 32-byte hash digest or a `u64` representing the
21//!   [`Block`] height or empty.  If empty, the latest `Block` known on the server will be used.
22
23/// Functions for creating Deploys.
24mod arg_handling;
25pub mod deploy;
26mod deploy_builder;
27mod deploy_str_params;
28mod dictionary_item_str_params;
29mod error;
30mod fields_container;
31mod json_args;
32pub mod parse;
33mod payment_str_params;
34mod session_str_params;
35mod simple_args;
36#[cfg(test)]
37mod tests;
38mod transaction;
39mod transaction_builder_params;
40mod transaction_str_params;
41mod transaction_v1_builder;
42
43#[cfg(feature = "std-fs-io")]
44use serde::Serialize;
45
46#[cfg(doc)]
47use casper_types::{account::AccountHash, Key};
48
49use casper_types::{Digest, URef};
50
51use crate::{
52    rpcs::{
53        results::{
54            GetAccountResult, GetAddressableEntityResult, GetAuctionInfoResult, GetBalanceResult,
55            GetBlockResult, GetBlockTransfersResult, GetChainspecResult, GetDeployResult,
56            GetDictionaryItemResult, GetEraInfoResult, GetEraSummaryResult, GetNodeStatusResult,
57            GetPeersResult, GetRewardResult, GetStateRootHashResult, GetTransactionResult,
58            GetValidatorChangesResult, ListRpcsResult, QueryBalanceDetailsResult,
59            QueryBalanceResult, QueryGlobalStateResult,
60        },
61        DictionaryItemIdentifier,
62    },
63    SuccessResponse,
64};
65
66#[cfg(feature = "std-fs-io")]
67use crate::verification_types::VerificationDetails;
68#[cfg(doc)]
69use crate::{Account, Block, Error, StoredValue, Transfer};
70#[cfg(doc)]
71use casper_types::PublicKey;
72#[cfg(feature = "std-fs-io")]
73pub use deploy::{
74    make_deploy, make_transfer, put_deploy, send_deploy_file, sign_deploy_file,
75    speculative_put_deploy, speculative_send_deploy_file, speculative_transfer, transfer,
76};
77pub use deploy_builder::{DeployBuilder, DeployBuilderError};
78pub use deploy_str_params::DeployStrParams;
79pub use dictionary_item_str_params::DictionaryItemStrParams;
80pub use error::{CliError, FromDecStrErr};
81pub(crate) use fields_container::{FieldsContainer, FieldsContainerError};
82pub use json_args::{
83    help as json_args_help, Error as JsonArgsError, ErrorDetails as JsonArgsErrorDetails, JsonArg,
84};
85pub use payment_str_params::PaymentStrParams;
86pub use session_str_params::SessionStrParams;
87pub use simple_args::{help as simple_args_help, insert_arg};
88pub use transaction::{make_transaction, put_transaction};
89#[cfg(feature = "std-fs-io")]
90pub use transaction::{
91    send_transaction_file, sign_transaction_file, speculative_send_transaction_file,
92};
93pub use transaction_builder_params::TransactionBuilderParams;
94pub use transaction_str_params::TransactionStrParams;
95pub use transaction_v1_builder::{TransactionV1Builder, TransactionV1BuilderError};
96
97/// Retrieves a [`casper_types::Deploy`] from the network.
98///
99/// `deploy_hash` must be a hex-encoded, 32-byte hash digest.  For details of the other parameters,
100/// see [the module docs](crate::cli#common-parameters).
101pub async fn get_deploy(
102    maybe_rpc_id: &str,
103    node_address: &str,
104    verbosity_level: u64,
105    deploy_hash: &str,
106    finalized_approvals: bool,
107) -> Result<SuccessResponse<GetDeployResult>, CliError> {
108    let rpc_id = parse::rpc_id(maybe_rpc_id);
109    let verbosity = parse::verbosity(verbosity_level);
110    let deploy_hash = parse::deploy_hash(deploy_hash)?;
111    crate::get_deploy(
112        rpc_id,
113        node_address,
114        verbosity,
115        deploy_hash,
116        finalized_approvals,
117    )
118    .await
119    .map_err(CliError::from)
120}
121
122/// Retrieves a [`casper_types::Transaction`] from the network.
123///
124/// `transaction_hash` must be a hex-encoded, 32-byte hash digest.  For details of the other parameters,
125/// see [the module docs](crate::cli#common-parameters).
126pub async fn get_transaction(
127    maybe_rpc_id: &str,
128    node_address: &str,
129    verbosity_level: u64,
130    transaction_hash: &str,
131    finalized_approvals: bool,
132) -> Result<SuccessResponse<GetTransactionResult>, CliError> {
133    let rpc_id = parse::rpc_id(maybe_rpc_id);
134    let verbosity = parse::verbosity(verbosity_level);
135    let transaction_hash = parse::transaction_hash(transaction_hash)?;
136    crate::get_transaction(
137        rpc_id,
138        node_address,
139        verbosity,
140        transaction_hash,
141        finalized_approvals,
142    )
143    .await
144    .map_err(CliError::from)
145}
146/// Retrieves a [`Block`] from the network.
147///
148/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
149pub async fn get_block(
150    maybe_rpc_id: &str,
151    node_address: &str,
152    verbosity_level: u64,
153    maybe_block_id: &str,
154) -> Result<SuccessResponse<GetBlockResult>, CliError> {
155    let rpc_id = parse::rpc_id(maybe_rpc_id);
156    let verbosity = parse::verbosity(verbosity_level);
157    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
158    crate::get_block(rpc_id, node_address, verbosity, maybe_block_id)
159        .await
160        .map_err(CliError::from)
161}
162
163/// Retrieves all [`Transfer`] items for a [`Block`] from the network.
164///
165/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
166pub async fn get_block_transfers(
167    maybe_rpc_id: &str,
168    node_address: &str,
169    verbosity_level: u64,
170    maybe_block_id: &str,
171) -> Result<SuccessResponse<GetBlockTransfersResult>, CliError> {
172    let rpc_id = parse::rpc_id(maybe_rpc_id);
173    let verbosity = parse::verbosity(verbosity_level);
174    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
175    crate::get_block_transfers(rpc_id, node_address, verbosity, maybe_block_id)
176        .await
177        .map_err(CliError::from)
178}
179
180/// Retrieves a state root hash at a given [`Block`].
181///
182/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
183pub async fn get_state_root_hash(
184    maybe_rpc_id: &str,
185    node_address: &str,
186    verbosity_level: u64,
187    maybe_block_id: &str,
188) -> Result<SuccessResponse<GetStateRootHashResult>, CliError> {
189    let rpc_id = parse::rpc_id(maybe_rpc_id);
190    let verbosity = parse::verbosity(verbosity_level);
191    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
192    crate::get_state_root_hash(rpc_id, node_address, verbosity, maybe_block_id)
193        .await
194        .map_err(CliError::from)
195}
196
197/// Retrieves era information from the network at a given [`Block`].
198///
199/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
200pub async fn get_era_summary(
201    maybe_rpc_id: &str,
202    node_address: &str,
203    verbosity_level: u64,
204    maybe_block_id: &str,
205) -> Result<SuccessResponse<GetEraSummaryResult>, CliError> {
206    let rpc_id = parse::rpc_id(maybe_rpc_id);
207    let verbosity = parse::verbosity(verbosity_level);
208    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
209    crate::get_era_summary(rpc_id, node_address, verbosity, maybe_block_id)
210        .await
211        .map_err(CliError::from)
212}
213
214/// Retrieves a [`StoredValue`] from global state.
215///
216/// `maybe_block_id` or `maybe_state_root_hash` identify the global state root hash to be used for
217/// the query.  Exactly one of these args should be an empty string.
218///
219/// `key` must be a formatted [`PublicKey`] or [`Key`].  `path` is comprised of components starting
220/// from the `key`, separated by `/`s.  It may be empty.
221///
222/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
223pub async fn query_global_state(
224    maybe_rpc_id: &str,
225    node_address: &str,
226    verbosity_level: u64,
227    maybe_block_id: &str,
228    maybe_state_root_hash: &str,
229    key: &str,
230    path: &str,
231) -> Result<SuccessResponse<QueryGlobalStateResult>, CliError> {
232    let rpc_id = parse::rpc_id(maybe_rpc_id);
233    let verbosity = parse::verbosity(verbosity_level);
234    let global_state_identifier =
235        parse::global_state_identifier(maybe_block_id, maybe_state_root_hash)?
236            .ok_or(CliError::FailedToParseStateIdentifier)?;
237    let key = parse::key_for_query(key)?;
238    let path = if path.is_empty() {
239        vec![]
240    } else {
241        path.split('/').map(ToString::to_string).collect()
242    };
243
244    crate::query_global_state(
245        rpc_id,
246        node_address,
247        verbosity,
248        global_state_identifier,
249        key,
250        path,
251    )
252    .await
253    .map_err(CliError::from)
254}
255
256/// Retrieves a purse's balance from global state.
257///
258/// `maybe_block_id` or `maybe_state_root_hash` identify the global state root hash to be used for
259/// the query.  If both are empty, the latest block is used.
260///
261/// `purse_id` can be a properly-formatted public key, account hash, entity address or URef.
262///
263/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
264pub async fn query_balance(
265    maybe_rpc_id: &str,
266    node_address: &str,
267    verbosity_level: u64,
268    maybe_block_id: &str,
269    maybe_state_root_hash: &str,
270    purse_id: &str,
271) -> Result<SuccessResponse<QueryBalanceResult>, CliError> {
272    let rpc_id = parse::rpc_id(maybe_rpc_id);
273    let verbosity = parse::verbosity(verbosity_level);
274    let maybe_global_state_identifier =
275        parse::global_state_identifier(maybe_block_id, maybe_state_root_hash)?;
276    let purse_identifier = parse::purse_identifier(purse_id)?;
277
278    crate::query_balance(
279        rpc_id,
280        node_address,
281        verbosity,
282        maybe_global_state_identifier,
283        purse_identifier,
284    )
285    .await
286    .map_err(CliError::from)
287}
288
289/// Retrieves a purse's balance and hold information from global state.
290///
291/// `maybe_block_id` or `maybe_state_root_hash` identify the global state root hash to be used for
292/// the query.  If both are empty, the latest block is used.
293///
294/// `purse_id` can be a properly-formatted public key, account hash, entity address or URef.
295///
296/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
297pub async fn query_balance_details(
298    maybe_rpc_id: &str,
299    node_address: &str,
300    verbosity_level: u64,
301    maybe_block_id: &str,
302    maybe_state_root_hash: &str,
303    purse_id: &str,
304) -> Result<SuccessResponse<QueryBalanceDetailsResult>, CliError> {
305    let rpc_id = parse::rpc_id(maybe_rpc_id);
306    let verbosity = parse::verbosity(verbosity_level);
307    let maybe_global_state_identifier =
308        parse::global_state_identifier(maybe_block_id, maybe_state_root_hash)?;
309    let purse_identifier = parse::purse_identifier(purse_id)?;
310
311    crate::query_balance_details(
312        rpc_id,
313        node_address,
314        verbosity,
315        maybe_global_state_identifier,
316        purse_identifier,
317    )
318    .await
319    .map_err(CliError::from)
320}
321
322/// Retrieves a [`StoredValue`] from a dictionary at a given state root hash.
323///
324/// `state_root_hash` must be a hex-encoded, 32-byte hash digest.
325///
326/// `dictionary_item_str_params` contains dictionary item identifier options for this query.  See
327/// [`DictionaryItemStrParams`] for more details.
328///
329/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
330pub async fn get_dictionary_item(
331    maybe_rpc_id: &str,
332    node_address: &str,
333    verbosity_level: u64,
334    state_root_hash: &str,
335    dictionary_item_str_params: DictionaryItemStrParams<'_>,
336) -> Result<SuccessResponse<GetDictionaryItemResult>, CliError> {
337    let rpc_id = parse::rpc_id(maybe_rpc_id);
338    let verbosity = parse::verbosity(verbosity_level);
339    let state_root_hash =
340        Digest::from_hex(state_root_hash).map_err(|error| CliError::FailedToParseDigest {
341            context: "state root hash in get_dictionary_item",
342            error,
343        })?;
344    let dictionary_item_identifier =
345        DictionaryItemIdentifier::try_from(dictionary_item_str_params)?;
346
347    crate::get_dictionary_item(
348        rpc_id,
349        node_address,
350        verbosity,
351        state_root_hash,
352        dictionary_item_identifier,
353    )
354    .await
355    .map_err(CliError::from)
356}
357
358/// Retrieves a purse's balance at a given state root hash.
359///
360/// `state_root_hash` must be a hex-encoded, 32-byte hash digest.
361///
362/// `purse` is a URef, formatted as e.g.
363/// ```text
364/// uref-0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20-007
365/// ```
366///
367/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
368pub async fn get_balance(
369    maybe_rpc_id: &str,
370    node_address: &str,
371    verbosity_level: u64,
372    state_root_hash: &str,
373    purse: &str,
374) -> Result<SuccessResponse<GetBalanceResult>, CliError> {
375    let rpc_id = parse::rpc_id(maybe_rpc_id);
376    let verbosity = parse::verbosity(verbosity_level);
377    let state_root_hash =
378        Digest::from_hex(state_root_hash).map_err(|error| CliError::FailedToParseDigest {
379            context: "state root hash in get_balance",
380            error,
381        })?;
382    let purse = URef::from_formatted_str(purse).map_err(|error| CliError::FailedToParseURef {
383        context: "purse in get_balance",
384        error,
385    })?;
386
387    crate::get_balance(rpc_id, node_address, verbosity, state_root_hash, purse)
388        .await
389        .map_err(CliError::from)
390}
391
392/// Retrieves an [`Account`] at a given [`Block`].
393///
394/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
395///
396/// # Parameters
397/// - `maybe_rpc_id`: The optional RPC ID as a string slice.
398/// - `node_address`: The address of the node as a string slice.
399/// - `verbosity_level`: The verbosity level as a 64-bit unsigned integer.
400/// - `maybe_block_id`: The optional block ID as a string slice.
401/// - `account_identifier`: The account identifier as a string slice.
402///
403/// # Returns
404/// The result containing either a successful response with the account details or a `CliError`.
405
406pub async fn get_account(
407    maybe_rpc_id: &str,
408    node_address: &str,
409    verbosity_level: u64,
410    maybe_block_id: &str,
411    account_identifier: &str,
412) -> Result<SuccessResponse<GetAccountResult>, CliError> {
413    let rpc_id = parse::rpc_id(maybe_rpc_id);
414    let verbosity = parse::verbosity(verbosity_level);
415    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
416    let account_identifier = parse::account_identifier(account_identifier)?;
417
418    crate::get_account(
419        rpc_id,
420        node_address,
421        verbosity,
422        maybe_block_id,
423        account_identifier,
424    )
425    .await
426    .map_err(CliError::from)
427}
428
429/// Retrieves an [`crate::rpcs::v2_0_0::get_entity::EntityOrAccount`] at a given [`Block`].
430///
431/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
432///
433/// # Parameters
434/// - `maybe_rpc_id`: The optional RPC ID as a string slice.
435/// - `node_address`: The address of the node as a string slice.
436/// - `verbosity_level`: The verbosity level as a 64-bit unsigned integer.
437/// - `maybe_block_id`: The optional block ID as a string slice.
438/// - `entity_identifier`: The entity identifier as a string slice.
439///
440/// # Returns
441/// The result containing either a successful response with the entity details or a `CliError`.
442pub async fn get_entity(
443    maybe_rpc_id: &str,
444    node_address: &str,
445    verbosity_level: u64,
446    maybe_block_id: &str,
447    entity_identifier: &str,
448) -> Result<SuccessResponse<GetAddressableEntityResult>, CliError> {
449    let rpc_id = parse::rpc_id(maybe_rpc_id);
450    let verbosity = parse::verbosity(verbosity_level);
451    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
452    let entity_identifier = parse::entity_identifier(entity_identifier)?;
453
454    crate::get_entity(
455        rpc_id,
456        node_address,
457        verbosity,
458        maybe_block_id,
459        entity_identifier,
460    )
461    .await
462    .map_err(CliError::from)
463}
464
465/// Retrieves an [`GetRewardResult`] at a given era.
466///
467/// `validator` is the public key as a formatted string associated with the validator.
468///
469/// `maybe_delegator` is the public key as a formatted string associated with the delegator.
470///
471/// For details of other parameters, see [the module docs](crate::cli#common-parameters).
472pub async fn get_reward(
473    maybe_rpc_id: &str,
474    node_address: &str,
475    verbosity_level: u64,
476    maybe_era_id: &str,
477    validator: &str,
478    maybe_delegator: &str,
479) -> Result<SuccessResponse<GetRewardResult>, CliError> {
480    let rpc_id = parse::rpc_id(maybe_rpc_id);
481    let verbosity = parse::verbosity(verbosity_level);
482    let era_identifier = parse::era_identifier(maybe_era_id)?;
483    let validator =
484        parse::public_key(validator)?.ok_or(CliError::FailedToParseValidatorPublicKey)?;
485    let delegator = parse::public_key(maybe_delegator)?;
486
487    crate::get_reward(
488        rpc_id,
489        node_address,
490        verbosity,
491        era_identifier,
492        validator,
493        delegator,
494    )
495    .await
496    .map_err(CliError::from)
497}
498
499/// Retrieves the bids and validators at a given [`Block`].
500///
501/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
502pub async fn get_auction_info(
503    maybe_rpc_id: &str,
504    node_address: &str,
505    verbosity_level: u64,
506    maybe_block_id: &str,
507) -> Result<SuccessResponse<GetAuctionInfoResult>, CliError> {
508    let rpc_id = parse::rpc_id(maybe_rpc_id);
509    let verbosity = parse::verbosity(verbosity_level);
510    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
511    crate::get_auction_info(rpc_id, node_address, verbosity, maybe_block_id)
512        .await
513        .map_err(CliError::from)
514}
515
516/// Retrieves the status changes of the active validators on the network.
517///
518/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
519pub async fn get_validator_changes(
520    maybe_rpc_id: &str,
521    node_address: &str,
522    verbosity_level: u64,
523) -> Result<SuccessResponse<GetValidatorChangesResult>, CliError> {
524    let rpc_id = parse::rpc_id(maybe_rpc_id);
525    let verbosity = parse::verbosity(verbosity_level);
526    crate::get_validator_changes(rpc_id, node_address, verbosity)
527        .await
528        .map_err(CliError::from)
529}
530
531/// Retrieves the IDs and addresses of the specified node's peers.
532///
533/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
534pub async fn get_peers(
535    maybe_rpc_id: &str,
536    node_address: &str,
537    verbosity_level: u64,
538) -> Result<SuccessResponse<GetPeersResult>, CliError> {
539    let rpc_id = parse::rpc_id(maybe_rpc_id);
540    let verbosity = parse::verbosity(verbosity_level);
541    crate::get_peers(rpc_id, node_address, verbosity)
542        .await
543        .map_err(CliError::from)
544}
545
546/// Retrieves the status of the specified node.
547///
548/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
549pub async fn get_node_status(
550    maybe_rpc_id: &str,
551    node_address: &str,
552    verbosity_level: u64,
553) -> Result<SuccessResponse<GetNodeStatusResult>, CliError> {
554    let rpc_id = parse::rpc_id(maybe_rpc_id);
555    let verbosity = parse::verbosity(verbosity_level);
556    crate::get_node_status(rpc_id, node_address, verbosity)
557        .await
558        .map_err(CliError::from)
559}
560
561/// Retrieves the Chainspec of the network.
562///
563/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
564pub async fn get_chainspec(
565    maybe_rpc_id: &str,
566    node_address: &str,
567    verbosity_level: u64,
568) -> Result<SuccessResponse<GetChainspecResult>, CliError> {
569    let rpc_id = parse::rpc_id(maybe_rpc_id);
570    let verbosity = parse::verbosity(verbosity_level);
571    crate::get_chainspec(rpc_id, node_address, verbosity)
572        .await
573        .map_err(CliError::from)
574}
575
576/// Retrieves the interface description (the schema including examples in OpenRPC format) of the
577/// JSON-RPC server's API.
578///
579/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
580pub async fn list_rpcs(
581    maybe_rpc_id: &str,
582    node_address: &str,
583    verbosity_level: u64,
584) -> Result<SuccessResponse<ListRpcsResult>, CliError> {
585    let rpc_id = parse::rpc_id(maybe_rpc_id);
586    let verbosity = parse::verbosity(verbosity_level);
587    crate::list_rpcs(rpc_id, node_address, verbosity)
588        .await
589        .map_err(CliError::from)
590}
591
592/// JSON-encode and pretty-print the given value to stdout at the given verbosity level.
593///
594/// When `verbosity_level` is `0`, nothing is printed.  For `1`, the value is printed with long
595/// string fields shortened to a string indicating the character count of the field.  Greater than
596/// `1` is the same as for `1` except without abbreviation of long fields.
597#[cfg(feature = "std-fs-io")]
598pub fn json_pretty_print<T: ?Sized + Serialize>(
599    value: &T,
600    verbosity_level: u64,
601) -> Result<(), CliError> {
602    let verbosity = parse::verbosity(verbosity_level);
603    crate::json_pretty_print(value, verbosity).map_err(CliError::from)
604}
605
606/// Retrieves era information from the network at a given switch [`Block`].
607///
608/// For details of the parameters, see [the module docs](crate::cli#common-parameters).
609#[deprecated(
610    since = "2.0.0",
611    note = "prefer 'get_era_summary' as it doesn't require a switch block"
612)]
613pub async fn get_era_info(
614    maybe_rpc_id: &str,
615    node_address: &str,
616    verbosity_level: u64,
617    maybe_block_id: &str,
618) -> Result<SuccessResponse<GetEraInfoResult>, CliError> {
619    let rpc_id = parse::rpc_id(maybe_rpc_id);
620    let verbosity = parse::verbosity(verbosity_level);
621    let maybe_block_id = parse::block_identifier(maybe_block_id)?;
622    #[allow(deprecated)]
623    crate::get_era_info(rpc_id, node_address, verbosity, maybe_block_id)
624        .await
625        .map_err(CliError::from)
626}
627
628/// Verifies the smart contract code against the one installed
629/// by deploy or transaction with given hash.
630#[cfg(feature = "std-fs-io")]
631pub async fn verify_contract(
632    hash_str: &str,
633    verification_url_base_path: &str,
634    verification_project_path: Option<&str>,
635    verbosity_level: u64,
636) -> Result<VerificationDetails, CliError> {
637    let verbosity = parse::verbosity(verbosity_level);
638    crate::verify_contract(
639        hash_str,
640        verification_url_base_path,
641        verification_project_path,
642        verbosity,
643    )
644    .await
645    .map_err(CliError::from)
646}