diff --git a/Cargo.lock b/Cargo.lock index 0d9007917..b67b22af2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,6 +85,17 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.14", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -459,6 +470,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake2" version = "0.9.2" @@ -563,6 +586,28 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -1438,6 +1483,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.30" @@ -1635,6 +1686,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -2352,6 +2406,7 @@ dependencies = [ "openssl", "prettytable", "reqwest", + "rust_decimal", "self_update", "semver", "serde", @@ -3314,6 +3369,26 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quick-xml" version = "0.23.1" @@ -3332,6 +3407,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.7.3" @@ -3485,6 +3566,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" version = "0.11.27" @@ -3534,6 +3624,51 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -3651,6 +3786,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "secp256k1" version = "0.27.0" @@ -3973,6 +4114,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "slab" version = "0.4.9" @@ -4182,6 +4329,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tar" version = "0.4.40" @@ -4747,6 +4900,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" + [[package]] name = "valuable" version = "0.1.0" @@ -5132,6 +5291,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "xattr" version = "1.3.1" diff --git a/Cargo.toml b/Cargo.toml index 84f0f2a81..480f5ddb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,8 @@ keyring = "2.0.5" interactive-clap = "0.2.10" interactive-clap-derive = "0.2.10" +rust_decimal = "1.35.0" + [features] default = ["ledger", "self-update"] ledger = ["near-ledger"] diff --git a/src/commands/account/view_account_summary/mod.rs b/src/commands/account/view_account_summary/mod.rs index 5d24176f9..83b4fd369 100644 --- a/src/commands/account/view_account_summary/mod.rs +++ b/src/commands/account/view_account_summary/mod.rs @@ -54,9 +54,14 @@ impl ViewAccountSummaryContext { })? .access_key_list_view()?; - let validators = match crate::common::fetch_validators_api(&account_id, network_config.fastnear_url.clone()) { - Ok(api_validators) => api_validators, - Err(_) => crate::common::fetch_validators_rpc(&json_rpc_client, network_config.staking_pools_factory_account_id.clone())?, + let historically_delegated_validators = network_config.fastnear_url.as_ref() + .and_then(|fastnear_url| crate::common::fetch_historically_delegated_staking_pools(fastnear_url, &account_id).ok()); + let validators = if let Some(validators) = historically_delegated_validators { + validators + } else if let Some(staking_pools_factory_account_id) = &network_config.staking_pools_factory_account_id { + crate::common::fetch_currently_active_staking_pools(&json_rpc_client, staking_pools_factory_account_id)? + } else { + Default::default() }; let runtime = tokio::runtime::Builder::new_multi_thread() diff --git a/src/commands/config/add_connection/mod.rs b/src/commands/config/add_connection/mod.rs index 5c0cc9fda..698b5f003 100644 --- a/src/commands/config/add_connection/mod.rs +++ b/src/commands/config/add_connection/mod.rs @@ -36,10 +36,13 @@ pub struct AddNetworkConnection { meta_transaction_relayer_url: Option, #[interactive_clap(long)] #[interactive_clap(skip_default_input_arg)] - fastnear_url: Option, + fastnear_url: Option, #[interactive_clap(long)] #[interactive_clap(skip_default_input_arg)] staking_pools_factory_account_id: Option, + #[interactive_clap(long)] + #[interactive_clap(skip_default_input_arg)] + coingecko_url: Option, } #[derive(Debug, Clone)] @@ -74,13 +77,20 @@ impl AddNetworkConnectionContext { .meta_transaction_relayer_url .clone() .map(|meta_transaction_relayer_url| meta_transaction_relayer_url.into()), - fastnear_url: scope.fastnear_url.clone(), + fastnear_url: scope + .fastnear_url + .clone() + .map(|fastnear_url| fastnear_url.into()), staking_pools_factory_account_id: scope .staking_pools_factory_account_id .clone() .map(|staking_pools_factory_account_id| { staking_pools_factory_account_id.into() }), + coingecko_url: scope + .coingecko_url + .clone() + .map(|coingecko_url| coingecko_url.into()), }, ); eprintln!(); @@ -225,7 +235,7 @@ impl AddNetworkConnection { fn input_fastnear_url( _context: &crate::GlobalContext, - ) -> color_eyre::eyre::Result> { + ) -> color_eyre::eyre::Result> { eprintln!(); #[derive(strum_macros::Display)] enum ConfirmOptions { @@ -240,7 +250,7 @@ impl AddNetworkConnection { ) .prompt()?; if let ConfirmOptions::Yes = select_choose_input { - let stake_delegators_api: String = + let stake_delegators_api: crate::types::url::Url = CustomType::new("What is the fastnear API url?").prompt()?; Ok(Some(stake_delegators_api)) } else { @@ -272,4 +282,31 @@ impl AddNetworkConnection { Ok(None) } } + + fn input_coingecko_url( + _context: &crate::GlobalContext, + ) -> color_eyre::eyre::Result> { + eprintln!(); + #[derive(strum_macros::Display)] + enum ConfirmOptions { + #[strum(to_string = "Yes, I want to enter the coingecko API url")] + Yes, + #[strum(to_string = "No, I don't want to enter the coingecko API url")] + No, + } + let select_choose_input = Select::new( + "Do you want to enter the coingecko API url?", + vec![ConfirmOptions::Yes, ConfirmOptions::No], + ) + .prompt()?; + if let ConfirmOptions::Yes = select_choose_input { + let coingecko_api: crate::types::url::Url = + CustomType::new("What is the coingecko API url?") + .with_starting_input("https://api.coingecko.com/") + .prompt()?; + Ok(Some(coingecko_api)) + } else { + Ok(None) + } + } } diff --git a/src/common.rs b/src/common.rs index b92dab4fc..acc7719f7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,8 +5,8 @@ use std::str::FromStr; use color_eyre::eyre::{ContextCompat, WrapErr}; use futures::{StreamExt, TryStreamExt}; -use near_primitives::borsh::BorshDeserialize; use prettytable::Table; +use rust_decimal::prelude::FromPrimitive; use tracing_indicatif::span_ext::IndicatifSpanExt; use tracing_indicatif::suspend_tracing_indicatif; @@ -816,7 +816,7 @@ pub fn rpc_transaction_error( Ok("Timeout error transaction".to_string()) } near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::InvalidTransaction { context } => { - match handler_invalid_tx_error(context) { + match convert_invalid_tx_error_to_cli_result(context) { Ok(_) => Ok("".to_string()), Err(err) => Err(err) } @@ -858,7 +858,9 @@ pub fn rpc_transaction_error( } } -pub fn print_action_error(action_error: &near_primitives::errors::ActionError) -> crate::CliResult { +pub fn convert_action_error_to_cli_result( + action_error: &near_primitives::errors::ActionError, +) -> crate::CliResult { match &action_error.kind { near_primitives::errors::ActionErrorKind::AccountAlreadyExists { account_id } => { color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!("Error: Create Account action tries to create an account with account ID <{}> which already exists in the storage.", account_id)) @@ -997,7 +999,7 @@ pub fn print_action_error(action_error: &near_primitives::errors::ActionError) - } } -pub fn handler_invalid_tx_error( +pub fn convert_invalid_tx_error_to_cli_result( invalid_tx_error: &near_primitives::errors::InvalidTxError, ) -> crate::CliResult { match invalid_tx_error { @@ -1123,18 +1125,50 @@ pub fn handler_invalid_tx_error( } } -pub fn print_transaction_error( - tx_execution_error: &near_primitives::errors::TxExecutionError, -) -> crate::CliResult { - eprintln!("Failed transaction"); - match tx_execution_error { - near_primitives::errors::TxExecutionError::ActionError(action_error) => { - print_action_error(action_error) - } - near_primitives::errors::TxExecutionError::InvalidTxError(invalid_tx_error) => { - handler_invalid_tx_error(invalid_tx_error) +fn get_near_usd_exchange_rate(coingecko_url: &url::Url) -> color_eyre::Result { + #[derive(serde::Deserialize)] + struct CoinGeckoResponse { + near: CoinGeckoNearData, + } + + #[derive(serde::Deserialize)] + struct CoinGeckoNearData { + usd: f64, + } + + let coingecko_exchange_rate_api_url = + coingecko_url.join("api/v3/simple/price?ids=near&vs_currencies=usd")?; + let mut last_error_message = String::new(); + + for _ in 0..10 { + match reqwest::blocking::get(coingecko_exchange_rate_api_url.clone()) { + Ok(response) => match response.json::() { + Ok(parsed_body) => return Ok(parsed_body.near.usd), + Err(err) => { + last_error_message = + format!("Failed to parse the response from Coingecko API as JSON: {err}"); + } + }, + Err(err) => { + last_error_message = + format!("Failed to get the response from Coingecko API: {err}"); + } } + + std::thread::sleep(std::time::Duration::from_millis(100)); } + + Err(color_eyre::eyre::eyre!(last_error_message)) +} + +fn calculate_usd_amount(tokens: u128, price: f64) -> Option { + let tokens_decimal = rust_decimal::Decimal::from_u128(tokens)?; + let price_decimal = rust_decimal::Decimal::from_f64(price)?; + + let divisor = rust_decimal::Decimal::from_u128(10u128.pow(24))?; + let tokens_decimal = tokens_decimal / divisor; + + Some(tokens_decimal * price_decimal) } pub fn print_transaction_status( @@ -1142,7 +1176,14 @@ pub fn print_transaction_status( network_config: &crate::config::NetworkConfig, ) -> crate::CliResult { eprintln!("--- Logs ---------------------------"); + + let mut total_gas_burnt = transaction_info.transaction_outcome.outcome.gas_burnt; + let mut total_tokens_burnt = transaction_info.transaction_outcome.outcome.tokens_burnt; + for receipt in transaction_info.receipts_outcome.iter() { + total_gas_burnt += receipt.outcome.gas_burnt; + total_tokens_burnt += receipt.outcome.tokens_burnt; + if receipt.outcome.logs.is_empty() { eprintln!("Logs [{}]: No logs", receipt.outcome.executor_id); } else { @@ -1150,11 +1191,20 @@ pub fn print_transaction_status( eprintln!(" {}", receipt.outcome.logs.join("\n ")); }; } - match &transaction_info.status { + + let return_value = match &transaction_info.status { near_primitives::views::FinalExecutionStatus::NotStarted | near_primitives::views::FinalExecutionStatus::Started => unreachable!(), near_primitives::views::FinalExecutionStatus::Failure(tx_execution_error) => { - return print_transaction_error(tx_execution_error); + eprintln!("--- Transaction failed ------------"); + match tx_execution_error { + near_primitives::errors::TxExecutionError::ActionError(action_error) => { + convert_action_error_to_cli_result(action_error) + } + near_primitives::errors::TxExecutionError::InvalidTxError(invalid_tx_error) => { + convert_invalid_tx_error_to_cli_result(invalid_tx_error) + } + } } near_primitives::views::FinalExecutionStatus::SuccessValue(bytes_result) => { eprintln!("--- Result -------------------------"); @@ -1170,14 +1220,36 @@ pub fn print_transaction_status( eprintln!("The returned value is not printable (binary data)"); } eprintln!("------------------------------------\n"); - print_value_successful_transaction(transaction_info.clone()) + print_value_successful_transaction(transaction_info.clone()); + Ok(()) } }; + + eprintln!(); + eprintln!("Gas burned: {}", NearGas::from_gas(total_gas_burnt)); + let near_usd_exchange_rate = network_config + .coingecko_url + .as_ref() + .map(get_near_usd_exchange_rate); + eprintln!( + "Transaction fee: {}{}", + crate::types::near_token::NearToken::from_yoctonear(total_tokens_burnt), + match near_usd_exchange_rate { + Some(Ok(exchange_rate)) => calculate_usd_amount(total_tokens_burnt, exchange_rate).map_or_else( + || format!(" (USD equivalent is too big to be displayed, using ${:.2} USD/NEAR exchange rate)", exchange_rate), + |amount| format!(" (approximately ${:.8} USD, using ${:.2} USD/NEAR exchange rate)", amount, exchange_rate) + ), + Some(Err(err)) => format!(" (USD equivalent is unavailable due to an error: {})", err), + None => String::new(), + } + ); + eprintln!("Transaction ID: {id}\nTo see the transaction in the transaction explorer, please open this url in your browser:\n{path}{id}\n", id=transaction_info.transaction_outcome.id, path=network_config.explorer_transaction_url ); - Ok(()) + + return_value } pub fn save_access_key_to_keychain( @@ -1468,19 +1540,12 @@ struct StakingResponse { pools: Vec, } -pub fn fetch_validators_api( +pub fn fetch_historically_delegated_staking_pools( + fastnear_url: &url::Url, account_id: &near_primitives::types::AccountId, - fastnear_url: Option, ) -> color_eyre::Result> { - let Some(fastnear_url) = fastnear_url else { - return Err(color_eyre::Report::msg( - "Stake delegators API is not set for selected network", - )); - }; - - let url = format!("{fastnear_url}/v1/account/{account_id}/staking"); - - let request = reqwest::blocking::get(url)?; + let request = + reqwest::blocking::get(fastnear_url.join(&format!("v1/account/{}/staking", account_id))?)?; let response: StakingResponse = request.json()?; Ok(response @@ -1490,21 +1555,15 @@ pub fn fetch_validators_api( .collect()) } -pub fn fetch_validators_rpc( +pub fn fetch_currently_active_staking_pools( json_rpc_client: &near_jsonrpc_client::JsonRpcClient, - staking_pools_factory_account_id: Option, + staking_pools_factory_account_id: &near_primitives::types::AccountId, ) -> color_eyre::Result> { - let Some(staking_pools_factory_account_id) = staking_pools_factory_account_id else { - return Err(color_eyre::Report::msg( - "Staking pools factory account ID is not set for selected network", - )); - }; - let query_view_method_response = json_rpc_client .blocking_call(near_jsonrpc_client::methods::query::RpcQueryRequest { block_reference: near_primitives::types::Finality::Final.into(), request: near_primitives::views::QueryRequest::ViewState { - account_id: staking_pools_factory_account_id, + account_id: staking_pools_factory_account_id.clone(), prefix: near_primitives::types::StoreKey::from(Vec::new()), include_proof: false, }, @@ -1515,16 +1574,10 @@ pub fn fetch_validators_rpc( { Ok(result .values - .iter() - .filter_map(|item| { - if &item.key[..2] == b"se" { - String::try_from_slice(&item.value) - .ok() - .and_then(|result| result.parse().ok()) - } else { - None - } - }) + .into_iter() + .filter(|item| &item.key[..2] == b"se") + .filter_map(|item| String::from_utf8(item.value.into()).ok()) + .filter_map(|result| result.parse().ok()) .collect()) } else { Err(color_eyre::Report::msg("Error call result".to_string())) diff --git a/src/config/migrations.rs b/src/config/migrations.rs index e0e9aada4..4995da5f4 100644 --- a/src/config/migrations.rs +++ b/src/config/migrations.rs @@ -49,8 +49,9 @@ impl From for NetworkConfigV2 { .near_social_db_contract_account_id, faucet_url: network_config.faucet_url, meta_transaction_relayer_url: network_config.meta_transaction_relayer_url, - fastnear_url: Some(String::from("https://api.fastnear.com")), + fastnear_url: Some("https://api.fastnear.com".parse().unwrap()), staking_pools_factory_account_id: Some("poolv1.near".parse().unwrap()), + coingecko_url: Some("https://api.coingecko.com/".parse().unwrap()), }, "testnet" => NetworkConfigV2 { network_name: network_config.network_name, @@ -65,6 +66,7 @@ impl From for NetworkConfigV2 { meta_transaction_relayer_url: network_config.meta_transaction_relayer_url, fastnear_url: None, staking_pools_factory_account_id: Some("pool.f863973.m0".parse().unwrap()), + coingecko_url: None, }, _ => NetworkConfigV2 { network_name: network_config.network_name, @@ -79,6 +81,7 @@ impl From for NetworkConfigV2 { meta_transaction_relayer_url: network_config.meta_transaction_relayer_url, fastnear_url: None, staking_pools_factory_account_id: None, + coingecko_url: None, }, } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 3e47e2cda..3e835de40 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -33,8 +33,9 @@ impl Default for Config { near_social_db_contract_account_id: Some("social.near".parse().unwrap()), faucet_url: None, meta_transaction_relayer_url: None, - fastnear_url: Some(String::from("https://api.fastnear.com")), + fastnear_url: Some("https://api.fastnear.com/".parse().unwrap()), staking_pools_factory_account_id: Some("poolv1.near".parse().unwrap()), + coingecko_url: Some("https://api.coingecko.com/".parse().unwrap()), }, ); network_connection.insert( @@ -53,6 +54,7 @@ impl Default for Config { meta_transaction_relayer_url: None, fastnear_url: None, staking_pools_factory_account_id: Some("pool.f863973.m0".parse().unwrap()), + coingecko_url: None, }, ); @@ -136,8 +138,9 @@ pub struct NetworkConfig { pub near_social_db_contract_account_id: Option, pub faucet_url: Option, pub meta_transaction_relayer_url: Option, - pub fastnear_url: Option, + pub fastnear_url: Option, pub staking_pools_factory_account_id: Option, + pub coingecko_url: Option, } impl NetworkConfig { diff --git a/src/transaction_signature_options/send/mod.rs b/src/transaction_signature_options/send/mod.rs index 5c85f8979..b75570c86 100644 --- a/src/transaction_signature_options/send/mod.rs +++ b/src/transaction_signature_options/send/mod.rs @@ -61,9 +61,14 @@ impl SendContext { }; }; - crate::common::print_transaction_status( - &transaction_info, - &previous_context.network_config, + tracing_indicatif::suspend_tracing_indicatif( + || -> color_eyre::eyre::Result<()> { + crate::common::print_transaction_status( + &transaction_info, + &previous_context.network_config, + )?; + Ok(()) + }, )?; (previous_context.on_after_sending_transaction_callback)(