From aa9b108c83ce01f64a41a56c64ccfca50e05248c Mon Sep 17 00:00:00 2001 From: FroVolod Date: Sat, 7 Feb 2026 18:06:18 +0200 Subject: [PATCH 1/7] refactored message tracing style --- src/lib.rs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 12d30ab6f..3cf5fdba4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub fn setup_tracing_with_extra_directives( verbosity: Verbosity, extra_directives: &[&str], ) -> CliResult { + use tracing::field::{Field, Visit}; use tracing::{Event, Level, Subscriber}; use tracing_indicatif::IndicatifLayer; use tracing_indicatif::style::ProgressStyle; @@ -48,6 +49,25 @@ pub fn setup_tracing_with_extra_directives( registry::LookupSpan, }; + struct RawMessageVisitor<'a> { + writer: Writer<'a>, + result: std::fmt::Result, + } + + impl<'a> Visit for RawMessageVisitor<'a> { + fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { + if field.name() == "message" { + self.result = write!(self.writer, "{:?}", value); + } + } + + fn record_str(&mut self, field: &Field, value: &str) { + if field.name() == "message" { + self.result = write!(self.writer, "{}", value); + } + } + } + struct SimpleFormatter; impl FormatEvent for SimpleFormatter @@ -57,7 +77,7 @@ pub fn setup_tracing_with_extra_directives( { fn format_event( &self, - ctx: &FmtContext<'_, S, N>, + _ctx: &FmtContext<'_, S, N>, mut writer: Writer<'_>, event: &Event<'_>, ) -> std::fmt::Result { @@ -72,9 +92,14 @@ pub fn setup_tracing_with_extra_directives( write!(writer, "{color_code}├ {icon}")?; - write!(writer, "\x1b[0m")?; + let mut visitor = RawMessageVisitor { + writer: writer.by_ref(), + result: Ok(()), + }; + event.record(&mut visitor); + visitor.result?; - ctx.field_format().format_fields(writer.by_ref(), event)?; + write!(writer, "\x1b[0m")?; writeln!(writer) } From 9f5797b49cadb149569b7b44196150e02ec37e7b Mon Sep 17 00:00:00 2001 From: FroVolod Date: Thu, 12 Feb 2026 13:54:44 +0200 Subject: [PATCH 2/7] refactored AccountStateError --- .../fund_myself_create_account/mod.rs | 56 ++-- .../fund_myself_create_account/sign_as/mod.rs | 22 +- src/commands/account/delete_account/mod.rs | 33 ++- src/commands/account/import_account/mod.rs | 6 +- .../import_account/using_private_key/mod.rs | 2 +- .../import_account/using_seed_phrase/mod.rs | 2 +- .../import_account/using_web_wallet/mod.rs | 2 +- .../storage_management/storage_deposit.rs | 9 +- .../account/update_social_profile/sign_as.rs | 9 +- src/commands/contract/call_function/mod.rs | 39 ++- src/commands/tokens/send_ft/amount_ft.rs | 6 +- .../add_action/delete_account/mod.rs | 35 ++- .../add_action/delete_account/mod.rs | 35 ++- .../add_action/delete_account/mod.rs | 37 ++- .../send_meta_transaction/sign_as/mod.rs | 9 +- src/common.rs | 242 +++++++++++------- src/config/mod.rs | 2 + 17 files changed, 346 insertions(+), 200 deletions(-) diff --git a/src/commands/account/create_account/fund_myself_create_account/mod.rs b/src/commands/account/create_account/fund_myself_create_account/mod.rs index 9cbb9a51a..6d18efd71 100644 --- a/src/commands/account/create_account/fund_myself_create_account/mod.rs +++ b/src/commands/account/create_account/fund_myself_create_account/mod.rs @@ -1,3 +1,4 @@ +use color_eyre::owo_colors::OwoColorize; use inquire::{CustomType, Select}; use crate::commands::account::MIN_ALLOWED_TOP_LEVEL_ACCOUNT_LENGTH; @@ -63,7 +64,7 @@ impl NewAccount { No, } let select_choose_input = - Select::new("\nDo you want to check the existence of the specified account so that you don’t waste tokens with sending a transaction that won't succeed?", + Select::new("Do you want to check the existence of the specified account so that you don't waste tokens with sending a transaction that won't succeed?", vec![ConfirmOptions::Yes{account_id: new_account_id.clone()}, ConfirmOptions::No], ) .prompt()?; @@ -71,11 +72,20 @@ impl NewAccount { let network = crate::common::find_network_where_account_exist( context, account_id.clone().into(), - )?; - if let Some(network_config) = network { - eprintln!( - "\nHeads up! You will only waste tokens if you proceed creating <{}> account on <{}> as the account already exists.", + ); + + if let Err(crate::common::AccountStateError::Skip) = network { + tracing::warn!( + "It was not checked whether <{account_id}> was available on the network." + ); + return Ok(Some(new_account_id)); + }; + + if let Some(network_config) = network.map_err(color_eyre::Report::msg)? { + tracing::warn!("{}", format!( + "Heads up! You will only waste tokens if you proceed creating <{}> account on <{}> as the account already exists.", &account_id, network_config.network_name + ).red() ); if !crate::common::ask_if_different_account_id_wanted()? { return Ok(Some(account_id)); @@ -84,8 +94,8 @@ impl NewAccount { < MIN_ALLOWED_TOP_LEVEL_ACCOUNT_LENGTH && account_id.0.is_top_level() { - eprintln!( - "\nAccount <{}> has <{}> character count. Only the registrar account can create new top level accounts that are shorter than {} characters. Read more about it in nomicon: https://nomicon.io/DataStructures/Account#top-level-accounts", + tracing::warn!( + "Account <{}> has <{}> character count. Only the registrar account can create new top level accounts that are shorter than {} characters. Read more about it in nomicon: https://nomicon.io/DataStructures/Account#top-level-accounts", &account_id, &account_id.0.as_str().chars().count(), MIN_ALLOWED_TOP_LEVEL_ACCOUNT_LENGTH, @@ -94,22 +104,36 @@ impl NewAccount { return Ok(Some(account_id)); }; } else { + tracing::info!("{}", format!("The account <{}> does not exist on [{}] networks. So, you can create this account.", + account_id, + context.config.network_names().join(", ")).green() + ); let parent_account_id = account_id.clone().get_parent_account_id_from_sub_account(); if !near_primitives::types::AccountId::from(parent_account_id.clone()) .is_top_level() { - if crate::common::find_network_where_account_exist( - context, - parent_account_id.clone().into(), - )? - .is_none() - { - eprintln!( - "\nThe parent account <{}> does not exist on [{}] networks. Therefore, you cannot create an account <{}>.", + let network_where_account_exist = + match crate::common::find_network_where_account_exist( + context, + parent_account_id.clone().into(), + ) { + Ok(network_config) => network_config, + Err(crate::common::AccountStateError::Skip) => { + return Ok(Some(account_id)); + } + Err(err) => { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( + err + )); + } + }; + if network_where_account_exist.is_none() { + tracing::warn!("{}", + format!("The parent account <{}> does not exist on [{}] networks. Therefore, you cannot create an account <{}>.", parent_account_id, context.config.network_names().join(", "), - account_id + account_id).red() ); if !crate::common::ask_if_different_account_id_wanted()? { return Ok(Some(account_id)); diff --git a/src/commands/account/create_account/fund_myself_create_account/sign_as/mod.rs b/src/commands/account/create_account/fund_myself_create_account/sign_as/mod.rs index 90ac26430..0e6e092f4 100644 --- a/src/commands/account/create_account/fund_myself_create_account/sign_as/mod.rs +++ b/src/commands/account/create_account/fund_myself_create_account/sign_as/mod.rs @@ -1,3 +1,4 @@ +use color_eyre::owo_colors::OwoColorize; use serde_json::json; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -197,9 +198,15 @@ fn validate_new_account_id( account_id, network_config.network_name )), - Err(crate::common::AccountStateError::Cancel) => color_eyre::eyre::Result::Err( - color_eyre::eyre::eyre!("Operation was canceled by the user"), - ), + Err(crate::common::AccountStateError::Skip) => { + tracing::warn!( + "{}", + format!( + "Account <{account_id}> is not verified. You can sign and send the created transaction later." + ) + ); + Ok(()) + } Err(crate::common::AccountStateError::JsonRpcError( near_jsonrpc_client::errors::JsonRpcError::ServerError( near_jsonrpc_client::errors::JsonRpcServerError::HandlerError( @@ -212,13 +219,14 @@ fn validate_new_account_id( )) => { tracing::warn!( parent: &tracing::Span::none(), - "Transport error.{}", + "{}{}", + "Transport error.".red(), crate::common::indent_payload( - "\nIt is currently possible to continue creating an account offline.\nYou can sign and send the created transaction later.\n" - ) + "\nIt is currently possible to continue creating an account offline.\nYou can sign and send the created transaction later.\n " + ).yellow() ); Ok(()) } - Err(err) => color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!("{:?}", err)), + Err(err) => color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)), } } diff --git a/src/commands/account/delete_account/mod.rs b/src/commands/account/delete_account/mod.rs index 9823ff000..750488f3c 100644 --- a/src/commands/account/delete_account/mod.rs +++ b/src/commands/account/delete_account/mod.rs @@ -126,7 +126,7 @@ impl BeneficiaryAccount { }; if beneficiary_account_id.0 == context.account_id { - eprintln!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); + tracing::warn!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); continue; } @@ -151,16 +151,27 @@ impl BeneficiaryAccount { ) .prompt()?; if let ConfirmOptions::Yes { account_id } = select_choose_input { - if crate::common::find_network_where_account_exist( - &context.global_context, - account_id.clone().into(), - )? - .is_none() - { - eprintln!( - "\nHeads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", - account_id, - context.global_context.config.network_names().join(", ") + let network_where_account_exist = + match crate::common::find_network_where_account_exist( + &context.global_context, + account_id.clone().into(), + ) { + Ok(network_config) => network_config, + Err(crate::common::AccountStateError::Skip) => { + tracing::warn!("{}", "Cannot verify beneficiary. Proceeding may result in total loss of NEAR tokens of the deleting account.".red()); + return Ok(Some(account_id)); + } + Err(err) => { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); + } + }; + if network_where_account_exist.is_none() { + tracing::warn!("{}", + format!( + "Heads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", + account_id, + context.global_context.config.network_names().join(", ") + ).red() ); if !crate::common::ask_if_different_account_id_wanted()? { return Ok(Some(account_id)); diff --git a/src/commands/account/import_account/mod.rs b/src/commands/account/import_account/mod.rs index 375206bef..85c9f86bf 100644 --- a/src/commands/account/import_account/mod.rs +++ b/src/commands/account/import_account/mod.rs @@ -66,10 +66,8 @@ pub fn login( public_key.clone(), network_config.clone(), ); - if let Err(crate::common::AccountStateError::Cancel) = access_key_view { - return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( - "Operation was canceled by the user" - )); + if let Err(err @ crate::common::AccountStateError::Cancel) = access_key_view { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); } if access_key_view.is_err() { tracing::warn!( diff --git a/src/commands/account/import_account/using_private_key/mod.rs b/src/commands/account/import_account/using_private_key/mod.rs index b604ccd2b..8b5c92e2e 100644 --- a/src/commands/account/import_account/using_private_key/mod.rs +++ b/src/commands/account/import_account/using_private_key/mod.rs @@ -36,7 +36,7 @@ impl LoginFromPrivateKeyContext { &key_pair_properties_buf, &public_key.to_string(), &format!( - "\nIt is currently not possible to verify the account access key on network <{}>.\nYou may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n", + "\nIt is currently not possible to verify the account access key on network <{}>.\nYou may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n ", network_config.network_name ), ) diff --git a/src/commands/account/import_account/using_seed_phrase/mod.rs b/src/commands/account/import_account/using_seed_phrase/mod.rs index 2429d97ff..8144561f4 100644 --- a/src/commands/account/import_account/using_seed_phrase/mod.rs +++ b/src/commands/account/import_account/using_seed_phrase/mod.rs @@ -37,7 +37,7 @@ impl LoginFromSeedPhraseContext { &key_pair_properties_buf, &key_pair_properties.public_key_str, &format!( - "\nIt is currently not possible to verify the account access key on network <{}>.\nYou may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n", + "\nIt is currently not possible to verify the account access key on network <{}>.\nYou may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n ", network_config.network_name ), ) diff --git a/src/commands/account/import_account/using_web_wallet/mod.rs b/src/commands/account/import_account/using_web_wallet/mod.rs index 4f355b7b3..45e414e63 100644 --- a/src/commands/account/import_account/using_web_wallet/mod.rs +++ b/src/commands/account/import_account/using_web_wallet/mod.rs @@ -37,7 +37,7 @@ impl LoginFromWebWalletContext { let key_pair_properties_buf = serde_json::to_string(&key_pair_properties)?; let error_message = format!( - "\nIt is currently not possible to verify the account access key.\nYou may not be logged in to {} or you may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n", + "\nIt is currently not possible to verify the account access key.\nYou may not be logged in to {} or you may have entered an incorrect account_id.\nYou have the option to reconfirm your account or save your access key information.\n ", &url.as_str() ); super::login( diff --git a/src/commands/account/storage_management/storage_deposit.rs b/src/commands/account/storage_management/storage_deposit.rs index 7de30c892..6da526bcd 100644 --- a/src/commands/account/storage_management/storage_deposit.rs +++ b/src/commands/account/storage_management/storage_deposit.rs @@ -59,9 +59,12 @@ impl DepositArgs { &context.global_context.config.network_connection, receiver_account_id.clone().into(), )? { - eprintln!( - "\nThe account <{receiver_account_id}> does not exist on [{}] networks.", - context.global_context.config.network_names().join(", ") + tracing::warn!( + "{}", + format!( + "The account <{receiver_account_id}> does not exist on [{}] networks.", + context.global_context.config.network_names().join(", ") + ) ); #[derive(strum_macros::Display)] enum ConfirmOptions { diff --git a/src/commands/account/update_social_profile/sign_as.rs b/src/commands/account/update_social_profile/sign_as.rs index 649b09b71..f61850a91 100644 --- a/src/commands/account/update_social_profile/sign_as.rs +++ b/src/commands/account/update_social_profile/sign_as.rs @@ -122,9 +122,12 @@ impl Signer { &context.global_context.config.network_connection, signer_account_id.clone().into(), )? { - eprintln!( - "\nThe account <{signer_account_id}> does not exist on [{}] networks.", - context.global_context.config.network_names().join(", ") + tracing::warn!( + "{}", + format!( + "The account <{signer_account_id}> does not exist on [{}] networks.", + context.global_context.config.network_names().join(", ") + ) ); #[derive(strum_macros::Display)] enum ConfirmOptions { diff --git a/src/commands/contract/call_function/mod.rs b/src/commands/contract/call_function/mod.rs index 4982542a2..4e1c08818 100644 --- a/src/commands/contract/call_function/mod.rs +++ b/src/commands/contract/call_function/mod.rs @@ -55,34 +55,29 @@ fn input_function_name( function_kind: near_abi::AbiFunctionKind, message: &str, ) -> color_eyre::eyre::Result> { - let network_config = crate::common::find_network_where_account_exist( - global_context, - contract_account_id.clone(), - )?; - - if let Some(network_config) = network_config { - let json_rpc_client = network_config.json_rpc_client(); - if let Ok(contract_abi) = + if let Ok(network) = + crate::common::find_network_where_account_exist(global_context, contract_account_id.clone()) + && let Some(network_config) = network + && let Ok(contract_abi) = tokio::runtime::Runtime::new() .unwrap() .block_on(super::get_contract_abi( - &json_rpc_client, + &network_config.json_rpc_client(), &near_primitives::types::Finality::Final.into(), contract_account_id, )) - { - let function_names = contract_abi - .body - .functions - .into_iter() - .filter(|function| function_kind == function.kind) - .map(|function| function.name) - .collect::>(); - if !function_names.is_empty() { - return Ok(Some( - Select::new(message, function_names).prompt()?.to_string(), - )); - } + { + let function_names = contract_abi + .body + .functions + .into_iter() + .filter(|function| function_kind == function.kind) + .map(|function| function.name) + .collect::>(); + if !function_names.is_empty() { + return Ok(Some( + Select::new(message, function_names).prompt()?.to_string(), + )); } } diff --git a/src/commands/tokens/send_ft/amount_ft.rs b/src/commands/tokens/send_ft/amount_ft.rs index f8c946b77..af6b128fb 100644 --- a/src/commands/tokens/send_ft/amount_ft.rs +++ b/src/commands/tokens/send_ft/amount_ft.rs @@ -36,7 +36,8 @@ impl AmountFtContext { let network_config = crate::common::find_network_where_account_exist( &previous_context.global_context, previous_context.ft_contract_account_id.clone(), - )? + ) + .map_err(color_eyre::Report::msg)? .wrap_err_with(|| { format!( "Contract <{}> does not exist in networks", @@ -69,7 +70,8 @@ impl AmountFt { let network_config = crate::common::find_network_where_account_exist( &context.global_context, context.ft_contract_account_id.clone(), - )? + ) + .map_err(color_eyre::Report::msg)? .wrap_err_with(|| { format!( "Contract <{}> does not exist in networks", diff --git a/src/commands/transaction/construct_transaction/add_action_1/add_action/delete_account/mod.rs b/src/commands/transaction/construct_transaction/add_action_1/add_action/delete_account/mod.rs index b846d8d64..f41c5cdf7 100644 --- a/src/commands/transaction/construct_transaction/add_action_1/add_action/delete_account/mod.rs +++ b/src/commands/transaction/construct_transaction/add_action_1/add_action/delete_account/mod.rs @@ -58,7 +58,7 @@ impl DeleteAccountAction { }; if beneficiary_account_id.0 == context.signer_account_id { - eprintln!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); + tracing::warn!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); continue; } @@ -78,21 +78,32 @@ impl DeleteAccountAction { No, } let select_choose_input = - Select::new("\nDo you want to check the existence of the specified account so that you don't lose tokens?", + Select::new("Do you want to check the existence of the specified account so that you don't lose tokens?", vec![ConfirmOptions::Yes{account_id: beneficiary_account_id.clone()}, ConfirmOptions::No], ) .prompt()?; if let ConfirmOptions::Yes { account_id } = select_choose_input { - if crate::common::find_network_where_account_exist( - &context.global_context, - account_id.clone().into(), - )? - .is_none() - { - eprintln!( - "\nHeads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", - account_id, - context.global_context.config.network_names().join(", ") + let network_where_account_exist = + match crate::common::find_network_where_account_exist( + &context.global_context, + account_id.clone().into(), + ) { + Ok(network_config) => network_config, + Err(crate::common::AccountStateError::Skip) => { + tracing::warn!("{}", "Cannot verify beneficiary. Proceeding may result in total loss of NEAR tokens of the deleting account.".red()); + return Ok(Some(account_id)); + } + Err(err) => { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); + } + }; + if network_where_account_exist.is_none() { + tracing::warn!("{}", + format!( + "Heads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", + account_id, + context.global_context.config.network_names().join(", ") + ).red() ); if !crate::common::ask_if_different_account_id_wanted()? { return Ok(Some(account_id)); diff --git a/src/commands/transaction/construct_transaction/add_action_2/add_action/delete_account/mod.rs b/src/commands/transaction/construct_transaction/add_action_2/add_action/delete_account/mod.rs index 2e6c75b42..7e461a8ab 100644 --- a/src/commands/transaction/construct_transaction/add_action_2/add_action/delete_account/mod.rs +++ b/src/commands/transaction/construct_transaction/add_action_2/add_action/delete_account/mod.rs @@ -58,7 +58,7 @@ impl DeleteAccountAction { }; if beneficiary_account_id.0 == context.signer_account_id { - eprintln!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); + tracing::warn!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); continue; } @@ -78,21 +78,32 @@ impl DeleteAccountAction { No, } let select_choose_input = - Select::new("\nDo you want to check the existence of the specified account so that you don't lose tokens?", + Select::new("Do you want to check the existence of the specified account so that you don't lose tokens?", vec![ConfirmOptions::Yes{account_id: beneficiary_account_id.clone()}, ConfirmOptions::No], ) .prompt()?; if let ConfirmOptions::Yes { account_id } = select_choose_input { - if crate::common::find_network_where_account_exist( - &context.global_context, - account_id.clone().into(), - )? - .is_none() - { - eprintln!( - "\nHeads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", - account_id, - context.global_context.config.network_names().join(", ") + let network_where_account_exist = + match crate::common::find_network_where_account_exist( + &context.global_context, + account_id.clone().into(), + ) { + Ok(network_config) => network_config, + Err(crate::common::AccountStateError::Skip) => { + tracing::warn!("{}", "Cannot verify beneficiary. Proceeding may result in total loss of NEAR tokens of the deleting account.".red()); + return Ok(Some(account_id)); + } + Err(err) => { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); + } + }; + if network_where_account_exist.is_none() { + tracing::warn!("{}", + format!( + "Heads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", + account_id, + context.global_context.config.network_names().join(", ") + ).red() ); if !crate::common::ask_if_different_account_id_wanted()? { return Ok(Some(account_id)); diff --git a/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs b/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs index ce1c61fb1..1830e5882 100644 --- a/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs +++ b/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs @@ -58,7 +58,7 @@ impl DeleteAccountAction { }; if beneficiary_account_id.0 == context.signer_account_id { - eprintln!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); + tracing::warn!("{}", "You have selected a beneficiary account ID that will now be deleted. This will result in the loss of your funds. So make your choice again.".red()); continue; } @@ -78,21 +78,34 @@ impl DeleteAccountAction { No, } let select_choose_input = - Select::new("\nDo you want to check the existence of the specified account so that you don't lose tokens?", + Select::new("Do you want to check the existence of the specified account so that you don't lose tokens?", vec![ConfirmOptions::Yes{account_id: beneficiary_account_id.clone()}, ConfirmOptions::No], ) .prompt()?; if let ConfirmOptions::Yes { account_id } = select_choose_input { - if crate::common::find_network_where_account_exist( - &context.global_context, - account_id.clone().into(), - )? - .is_none() - { - eprintln!( - "\nHeads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", - account_id, - context.global_context.config.network_names().join(", ") + let network_where_account_exist = + match crate::common::find_network_where_account_exist( + &context.global_context, + account_id.clone().into(), + ) { + Ok(network_config) => network_config, + Err(crate::common::AccountStateError::Skip) => { + tracing::warn!("{}", "Cannot verify beneficiary. Proceeding may result in total loss of NEAR tokens of the deleting account.".red()); + return Ok(Some(account_id)); + } + Err(err) => { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( + "{err:?}" + )); + } + }; + if network_where_account_exist.is_none() { + tracing::warn!("{}", + format!( + "Heads up! You will lose remaining NEAR tokens on the account you delete if you specify the account <{}> as the beneficiary as it does not exist on [{}] networks.", + account_id, + context.global_context.config.network_names().join(", ") + ).red() ); if !crate::common::ask_if_different_account_id_wanted()? { return Ok(Some(account_id)); diff --git a/src/commands/transaction/send_meta_transaction/sign_as/mod.rs b/src/commands/transaction/send_meta_transaction/sign_as/mod.rs index b18b877b7..473d0da11 100644 --- a/src/commands/transaction/send_meta_transaction/sign_as/mod.rs +++ b/src/commands/transaction/send_meta_transaction/sign_as/mod.rs @@ -92,9 +92,12 @@ impl RelayerAccountId { &context.global_context.config.network_connection, relayer_account_id.clone().into(), )? { - eprintln!( - "\nThe account <{relayer_account_id}> does not exist on [{}] networks.", - context.global_context.config.network_names().join(", ") + tracing::warn!( + "{}", + format!( + "The account <{relayer_account_id}> does not exist on [{}] networks.", + context.global_context.config.network_names().join(", ") + ) ); #[derive(strum_macros::Display)] enum ConfirmOptions { diff --git a/src/common.rs b/src/common.rs index 59f983ea4..3cd8e3f62 100644 --- a/src/common.rs +++ b/src/common.rs @@ -168,6 +168,20 @@ impl AccountTransferAllowance { pub enum AccountStateError { JsonRpcError(near_jsonrpc_client::errors::JsonRpcError), Cancel, + Skip, +} + +impl std::fmt::Display for AccountStateError +where + E: std::fmt::Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::JsonRpcError(err) => write!(f, "{err:?}"), + Self::Cancel => write!(f, "Operation was canceled by the user"), + Self::Skip => write!(f, "Operation was skipped by the user"), + } + } } #[tracing::instrument(name = "Getting the transfer allowance for the account ...", skip_all)] @@ -212,10 +226,8 @@ pub async fn get_account_transfer_allowance( network_config.network_name )); } - Err(AccountStateError::Cancel) => { - return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( - "Operation was canceled by the user" - )); + Err(err @ (AccountStateError::Cancel | AccountStateError::Skip)) => { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); } }; let storage_amount_per_byte = @@ -282,10 +294,15 @@ pub fn verify_account_access_key( return Err(AccountStateError::JsonRpcError(err)); } Err(near_jsonrpc_client::errors::JsonRpcError::TransportError(err)) => { - let need_check_account = need_check_account(format!( - "\nAccount information ({account_id}) cannot be fetched on <{}> network due to connectivity issue.", - network_config.network_name - )); + let need_check_account = suspend_tracing_indicatif::< + _, + color_eyre::eyre::Result, + >(|| { + need_check_account(format!( + "Account information ({account_id}) cannot be fetched on <{}> network due to connectivity issue.", + network_config.network_name + )) + }); if need_check_account.is_err() { return Err(AccountStateError::Cancel); } @@ -296,10 +313,15 @@ pub fn verify_account_access_key( } } Err(near_jsonrpc_client::errors::JsonRpcError::ServerError(err)) => { - let need_check_account = need_check_account(format!( - "\nAccount information ({account_id}) cannot be fetched on <{}> network due to server error.", - network_config.network_name - )); + let need_check_account = suspend_tracing_indicatif::< + _, + color_eyre::eyre::Result, + >(|| { + need_check_account(format!( + "Account information ({account_id}) cannot be fetched on <{}> network due to server error.", + network_config.network_name + )) + }); if need_check_account.is_err() { return Err(AccountStateError::Cancel); } @@ -319,7 +341,14 @@ pub fn is_account_exist( account_id: near_primitives::types::AccountId, ) -> color_eyre::eyre::Result { tracing::info!(target: "near_teach_me", "Checking the existence of the account ..."); + let mut checked_networks: Vec = Vec::new(); for (_, network_config) in networks { + if checked_networks.contains(&network_config.network_name) { + continue; + } else { + checked_networks.push(network_config.network_name.clone()); + } + let result = tokio::runtime::Runtime::new() .unwrap() .block_on(get_account_state( @@ -332,11 +361,22 @@ pub fn is_account_exist( return Ok(true); } - if let Err(AccountStateError::Cancel) = result { - return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( - "Operation was canceled by the user" - )); + if let Err(err @ (AccountStateError::Cancel | AccountStateError::Skip)) = result { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); } + + if let Err(AccountStateError::JsonRpcError( + near_jsonrpc_client::errors::JsonRpcError::ServerError( + near_jsonrpc_client::errors::JsonRpcServerError::HandlerError( + near_jsonrpc_primitives::types::query::RpcQueryError::UnknownAccount { .. }, + ), + ), + )) = result + { + continue; + } + + checked_networks.pop(); } Ok(false) } @@ -345,10 +385,24 @@ pub fn is_account_exist( pub fn find_network_where_account_exist( context: &crate::GlobalContext, new_account_id: near_primitives::types::AccountId, -) -> color_eyre::eyre::Result> { +) -> color_eyre::eyre::Result< + Option, + AccountStateError, +> { tracing::Span::current().pb_set_message(new_account_id.as_str()); tracing::info!(target: "near_teach_me", "Searching for a network where an account exists for {new_account_id} ..."); + let mut networks: Vec = Vec::new(); + let mut returned_result: color_eyre::eyre::Result< + Option, + AccountStateError, + > = Ok(None); for (_, network_config) in context.config.network_connection.iter() { + if networks.contains(&network_config.network_name) { + continue; + } else { + networks.push(network_config.network_name.clone()); + } + let result = tokio::runtime::Runtime::new() .unwrap() .block_on(get_account_state( @@ -357,17 +411,29 @@ pub fn find_network_where_account_exist( near_primitives::types::BlockReference::latest(), )); - if result.is_ok() { - return Ok(Some(network_config.clone())); - } - - if let Err(AccountStateError::Cancel) = result { - return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( - "Operation was canceled by the user" - )); + match result { + Ok(_) => return Ok(Some(network_config.clone())), + Err(err @ (AccountStateError::Cancel | AccountStateError::Skip)) => { + return Err(err); + } + Err(AccountStateError::JsonRpcError( + near_jsonrpc_client::errors::JsonRpcError::ServerError( + near_jsonrpc_client::errors::JsonRpcServerError::HandlerError( + near_jsonrpc_primitives::types::query::RpcQueryError::UnknownAccount { + .. + }, + ), + ), + )) => { + returned_result = Ok(None); + } + Err(err) => { + networks.pop(); + returned_result = Err(err); + } } } - Ok(None) + returned_result } pub fn ask_if_different_account_id_wanted() -> color_eyre::eyre::Result { @@ -395,85 +461,81 @@ pub async fn get_account_state( near_primitives::views::AccountView, AccountStateError, > { - loop { - tracing::Span::current().pb_set_message(&format!( - "<{account_id}> on network <{}> ...", - network_config.network_name - )); - tracing::info!(target: "near_teach_me", "Getting account status information for <{account_id}> on network <{}> ...", network_config.network_name); + tracing::Span::current().pb_set_message(&format!( + "<{account_id}> on network <{}> ...", + network_config.network_name + )); + tracing::info!(target: "near_teach_me", "Getting account status information for <{account_id}> on network <{}> ...", network_config.network_name); - let query_view_method_response = view_account( - format!("{}", network_config.rpc_url), - &network_config.json_rpc_client(), - account_id, - block_reference.clone(), - ) - .await; + let query_view_method_response = view_account( + format!("{}", network_config.rpc_url), + &network_config.json_rpc_client(), + account_id, + block_reference.clone(), + ) + .await; - match query_view_method_response { - Ok(rpc_query_response) => { - if let near_jsonrpc_primitives::types::query::QueryResponseKind::ViewAccount( - account_view, - ) = rpc_query_response.kind - { - return Ok(account_view); - } else { - return Err(AccountStateError::JsonRpcError(near_jsonrpc_client::errors::JsonRpcError::TransportError(near_jsonrpc_client::errors::RpcTransportError::RecvError( + match query_view_method_response { + Ok(rpc_query_response) => { + if let near_jsonrpc_primitives::types::query::QueryResponseKind::ViewAccount( + account_view, + ) = rpc_query_response.kind + { + return Ok(account_view); + } else { + return Err(AccountStateError::JsonRpcError(near_jsonrpc_client::errors::JsonRpcError::TransportError(near_jsonrpc_client::errors::RpcTransportError::RecvError( near_jsonrpc_client::errors::JsonRpcTransportRecvError::UnexpectedServerResponse( near_jsonrpc_primitives::message::Message::error(near_jsonrpc_primitives::errors::RpcError::parse_error("Transport error: unexpected server response".to_string())) ), )))); - } } - Err( - err @ near_jsonrpc_client::errors::JsonRpcError::ServerError( - near_jsonrpc_client::errors::JsonRpcServerError::HandlerError( - near_jsonrpc_primitives::types::query::RpcQueryError::UnknownAccount { - .. - }, - ), + } + Err( + err @ near_jsonrpc_client::errors::JsonRpcError::ServerError( + near_jsonrpc_client::errors::JsonRpcServerError::HandlerError( + near_jsonrpc_primitives::types::query::RpcQueryError::UnknownAccount { .. }, ), - ) => { - return Err(AccountStateError::JsonRpcError(err)); - } - Err(near_jsonrpc_client::errors::JsonRpcError::TransportError(err)) => { - let need_check_account = suspend_tracing_indicatif::< - _, - color_eyre::eyre::Result, - >(|| { + ), + ) => { + return Err(AccountStateError::JsonRpcError(err)); + } + Err(near_jsonrpc_client::errors::JsonRpcError::TransportError(err)) => { + let need_check_account = suspend_tracing_indicatif::<_, color_eyre::eyre::Result>( + || { need_check_account(format!( - "\nAccount information ({account_id}) cannot be fetched on <{}> network due to connectivity issue.", + "Account information ({account_id}) cannot be fetched on <{}> network due to connectivity issue.", network_config.network_name )) - }); - if need_check_account.is_err() { - return Err(AccountStateError::Cancel); - } - if let Ok(false) = need_check_account { - return Err(AccountStateError::JsonRpcError( - near_jsonrpc_client::errors::JsonRpcError::TransportError(err), - )); - } + }, + ); + if need_check_account.is_err() { + return Err(AccountStateError::Cancel); } - Err(near_jsonrpc_client::errors::JsonRpcError::ServerError(err)) => { - let need_check_account = suspend_tracing_indicatif::< - _, - color_eyre::eyre::Result, - >(|| { + if let Ok(true) = need_check_account { + return Err(AccountStateError::JsonRpcError( + near_jsonrpc_client::errors::JsonRpcError::TransportError(err), + )); + } + return Err(AccountStateError::Skip); + } + Err(near_jsonrpc_client::errors::JsonRpcError::ServerError(err)) => { + let need_check_account = suspend_tracing_indicatif::<_, color_eyre::eyre::Result>( + || { need_check_account(format!( - "\nAccount information ({account_id}) cannot be fetched on <{}> network due to server error.", + "Account information ({account_id}) cannot be fetched on <{}> network due to server error.", network_config.network_name )) - }); - if need_check_account.is_err() { - return Err(AccountStateError::Cancel); - } - if let Ok(false) = need_check_account { - return Err(AccountStateError::JsonRpcError( - near_jsonrpc_client::errors::JsonRpcError::ServerError(err), - )); - } + }, + ); + if need_check_account.is_err() { + return Err(AccountStateError::Cancel); + } + if let Ok(true) = need_check_account { + return Err(AccountStateError::JsonRpcError( + near_jsonrpc_client::errors::JsonRpcError::ServerError(err), + )); } + return Err(AccountStateError::Skip); } } } @@ -563,7 +625,7 @@ fn need_check_account(message: String) -> color_eyre::eyre::Result { No, } let select_choose_input = Select::new( - &format!("{message}\nDo you want to try again?"), + &format!("{message} Do you want to try again?"), vec![ConfirmOptions::Yes, ConfirmOptions::No], ) .prompt()?; diff --git a/src/config/mod.rs b/src/config/mod.rs index fde0183b9..b4d9acc92 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -157,6 +157,8 @@ impl Config { self.network_connection .iter() .map(|(_, network_config)| network_config.network_name.clone()) + .collect::>() + .into_iter() .collect() } From acb0af93ef2f6c7dfc70399c73851b12de1b170f Mon Sep 17 00:00:00 2001 From: FroVolod Date: Sat, 14 Feb 2026 08:32:36 +0200 Subject: [PATCH 3/7] Update src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../add_action_3/add_action/delete_account/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs b/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs index 1830e5882..ccc9b61bc 100644 --- a/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs +++ b/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs @@ -95,7 +95,7 @@ impl DeleteAccountAction { } Err(err) => { return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( - "{err:?}" + "{err}" )); } }; From becacf7d4d7517c9a49ec0bddcb0158cfd0bd11b Mon Sep 17 00:00:00 2001 From: FroVolod Date: Mon, 16 Feb 2026 17:20:40 +0200 Subject: [PATCH 4/7] refactored format_event() --- src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3cf5fdba4..9e095b257 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,18 +52,21 @@ pub fn setup_tracing_with_extra_directives( struct RawMessageVisitor<'a> { writer: Writer<'a>, result: std::fmt::Result, + is_message_printed: bool, } impl<'a> Visit for RawMessageVisitor<'a> { fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { if field.name() == "message" { self.result = write!(self.writer, "{:?}", value); + self.is_message_printed = true; } } fn record_str(&mut self, field: &Field, value: &str) { if field.name() == "message" { self.result = write!(self.writer, "{}", value); + self.is_message_printed = true; } } } @@ -95,10 +98,24 @@ pub fn setup_tracing_with_extra_directives( let mut visitor = RawMessageVisitor { writer: writer.by_ref(), result: Ok(()), + is_message_printed: false, }; event.record(&mut visitor); visitor.result?; + let mut has_fields = false; + event.record( + &mut |field: &tracing::field::Field, value: &dyn std::fmt::Debug| { + if field.name() != "message" { + if !has_fields { + let _ = write!(writer, " "); + has_fields = true; + } + let _ = write!(writer, " {}={:?}", field.name(), value); + } + }, + ); + write!(writer, "\x1b[0m")?; writeln!(writer) From e75c873100f629d6c5cd9375888b6f33a1c94782 Mon Sep 17 00:00:00 2001 From: FroVolod Date: Mon, 16 Feb 2026 17:33:07 +0200 Subject: [PATCH 5/7] refactored network_names() --- src/config/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index b4d9acc92..441a2384d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -154,12 +154,15 @@ impl Default for Config { impl Config { pub fn network_names(&self) -> Vec { - self.network_connection - .iter() - .map(|(_, network_config)| network_config.network_name.clone()) + let mut network_names: Vec = self + .network_connection + .values() + .map(|network_config| network_config.network_name.clone()) .collect::>() .into_iter() - .collect() + .collect(); + network_names.sort(); + network_names } pub fn into_latest_version(self) -> migrations::ConfigVersion { From c1b513c7047c670ab4c7872e081b56220dd830e8 Mon Sep 17 00:00:00 2001 From: FroVolod Date: Tue, 17 Feb 2026 08:14:01 +0200 Subject: [PATCH 6/7] refactored input_function_name() --- src/commands/contract/call_function/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/commands/contract/call_function/mod.rs b/src/commands/contract/call_function/mod.rs index 4e1c08818..c1d96ad38 100644 --- a/src/commands/contract/call_function/mod.rs +++ b/src/commands/contract/call_function/mod.rs @@ -55,8 +55,16 @@ fn input_function_name( function_kind: near_abi::AbiFunctionKind, message: &str, ) -> color_eyre::eyre::Result> { - if let Ok(network) = - crate::common::find_network_where_account_exist(global_context, contract_account_id.clone()) + let network_config = crate::common::find_network_where_account_exist( + global_context, + contract_account_id.clone(), + ); + + if let Err(err @ crate::common::AccountStateError::Cancel) = network_config { + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(err)); + } + + if let Ok(network) = network_config && let Some(network_config) = network && let Ok(contract_abi) = tokio::runtime::Runtime::new() From 3808b086c25be99e19061508f5a5d6a8deeeaee5 Mon Sep 17 00:00:00 2001 From: FroVolod Date: Sun, 1 Mar 2026 16:46:18 +0200 Subject: [PATCH 7/7] fmt --- .../add_action_3/add_action/delete_account/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs b/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs index 6de9bf580..782b4468a 100644 --- a/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs +++ b/src/commands/transaction/construct_transaction/add_action_3/add_action/delete_account/mod.rs @@ -95,9 +95,7 @@ impl DeleteAccountAction { return Ok(Some(account_id)); } Err(err) => { - return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!( - "{err}" - )); + return color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!("{err}")); } }; if network_where_account_exist.is_none() {