From ca3bfc859a1430acaecb19d33eadf16c6cddeed0 Mon Sep 17 00:00:00 2001 From: farbanas Date: Tue, 31 Jan 2023 15:09:35 +0100 Subject: [PATCH] merge conflicts --- CHANGELOG.md | 29 ++-- Cargo.lock | 21 +-- clients/client-core/Cargo.toml | 2 +- clients/client-core/src/config/mod.rs | 16 +-- clients/client-core/src/init/mod.rs | 2 +- clients/native/Cargo.toml | 2 +- clients/native/src/commands/init.rs | 2 +- clients/native/src/commands/run.rs | 2 +- clients/native/src/commands/upgrade.rs | 2 +- clients/socks5/Cargo.toml | 2 +- clients/socks5/src/commands/init.rs | 2 +- clients/socks5/src/commands/run.rs | 2 +- clients/socks5/src/commands/upgrade.rs | 2 +- common/config/src/lib.rs | 38 ++--- .../multisig-contract/Cargo.toml | 1 + .../multisig-contract}/src/error.rs | 3 + .../multisig-contract/src/lib.rs | 1 + contracts/coconut-test/src/helpers.rs | 3 +- .../multisig/cw3-flex-multisig/Cargo.toml | 1 - .../cw3-flex-multisig/src/contract.rs | 2 +- .../multisig/cw3-flex-multisig/src/lib.rs | 3 - envs/qa-qwerty.env | 8 +- explorer-api/Cargo.toml | 2 +- explorer/CHANGELOG.md | 10 ++ explorer/package.json | 4 +- explorer/src/api/constants.ts | 2 +- explorer/src/api/index.ts | 12 +- explorer/src/components/Gateways.ts | 10 +- explorer/src/pages/GatewayDetail/index.tsx | 6 +- explorer/src/pages/Gateways/index.tsx | 18 +++ explorer/src/typeDefs/explorer-api.ts | 10 +- gateway/Cargo.toml | 2 +- gateway/src/commands/init.rs | 2 +- gateway/src/commands/upgrade.rs | 2 +- gateway/src/config/mod.rs | 10 +- gateway/src/support/config.rs | 4 +- mixnode/Cargo.toml | 2 +- mixnode/src/commands/describe.rs | 4 +- mixnode/src/commands/init.rs | 2 +- mixnode/src/commands/node_details.rs | 2 +- mixnode/src/commands/run.rs | 2 +- mixnode/src/commands/sign.rs | 2 +- mixnode/src/commands/upgrade.rs | 2 +- mixnode/src/config/mod.rs | 8 +- mixnode/src/node/mod.rs | 2 +- nym-api/Cargo.toml | 2 +- nym-api/nym-api-requests/src/models.rs | 2 +- .../src/circulating_supply_api/cache/data.rs | 6 +- .../src/circulating_supply_api/cache/mod.rs | 2 +- nym-api/src/coconut/dkg/verification_key.rs | 15 +- nym-api/src/coconut/helpers.rs | 18 +++ nym-api/src/coconut/mod.rs | 7 +- nym-api/src/support/cli/mod.rs | 24 +++- nym-api/src/support/config/mod.rs | 62 ++++---- nym-connect/CHANGELOG.md | 8 ++ nym-connect/package.json | 6 +- nym-connect/src-tauri/Cargo.toml | 2 +- nym-connect/src-tauri/src/config/mod.rs | 2 +- nym-connect/src-tauri/src/error.rs | 4 +- nym-connect/src-tauri/src/state.rs | 2 +- nym-connect/src-tauri/src/tasks.rs | 2 +- nym-connect/src-tauri/tauri.conf.json | 18 ++- nym-connect/src/App.tsx | 44 ++---- .../src/assets/help-step-one-legacy.png | Bin 0 -> 14403 bytes nym-connect/src/assets/help-step-one.png | Bin 14403 -> 36448 bytes .../src/assets/help-step-two-legacy.png | Bin 0 -> 35631 bytes nym-connect/src/assets/help-step-two.png | Bin 35631 -> 18353 bytes nym-connect/src/components/AppVersion.tsx | 4 +- nym-connect/src/components/AppWindowFrame.tsx | 33 ++--- .../src/components/ConnectionButton.tsx | 14 +- .../src/components/ConnectionStatus.tsx | 93 ++++++------ nym-connect/src/components/CustomTitleBar.tsx | 44 +++--- .../src/components/ExperimentalWarning.tsx | 13 ++ .../Growth/TestAndEarnButtonArea.tsx | 2 +- .../components/Growth/TestAndEarnPopup.tsx | 8 +- .../Growth/context/TestAndEarnContext.tsx | 2 +- nym-connect/src/components/HelpPage.tsx | 8 +- nym-connect/src/components/HelpPageImage.tsx | 5 +- .../src/components/HelpPageStepIndicator.tsx | 7 +- nym-connect/src/components/InfoModal.tsx | 4 +- .../src/components/IpAddressAndPortModal.tsx | 16 ++- nym-connect/src/components/PowerButton.tsx | 132 ++++++++++++++++++ ...erviceProviderInfo.tsx => TooltipInfo.tsx} | 13 +- nym-connect/src/context/main.tsx | 116 ++++++++------- nym-connect/src/context/mocks/main.tsx | 9 +- nym-connect/src/index.tsx | 24 ++-- nym-connect/src/layouts/ConnectedLayout.tsx | 57 -------- nym-connect/src/layouts/ConnectionLayout.tsx | 30 ++++ nym-connect/src/layouts/DefaultLayout.tsx | 49 ------- nym-connect/src/layouts/HelpGuideLayout.tsx | 70 ---------- .../src/pages/connection/Connected.tsx | 75 ++++++++++ .../src/pages/connection/Disconnected.tsx | 55 ++++++++ nym-connect/src/pages/connection/index.tsx | 85 +++++++++++ nym-connect/src/pages/menu/Apps.tsx | 42 ++++++ nym-connect/src/pages/menu/Guide.tsx | 47 +++++++ nym-connect/src/pages/menu/index.tsx | 30 ++++ nym-connect/src/routes/index.tsx | 18 +++ nym-connect/src/stories/AppFlow.stories.tsx | 22 +-- .../src/stories/ConnectedLayout.stories.tsx | 22 +-- .../src/stories/ConnectionButton.stories.tsx | 2 +- .../src/stories/DefaultLayout.stories.tsx | 22 ++- .../src/stories/PowerButton.stories.tsx | 29 ++++ nym-connect/src/theme/theme.tsx | 2 +- nym-wallet/Cargo.lock | 1 + .../network-requester/Cargo.toml | 2 +- .../network-statistics/Cargo.toml | 2 +- tools/nym-cli/Cargo.toml | 2 +- yarn.lock | 77 +--------- 108 files changed, 1112 insertions(+), 668 deletions(-) rename {contracts/multisig/cw3-flex-multisig => common/cosmwasm-smart-contracts/multisig-contract}/src/error.rs (90%) create mode 100644 nym-api/src/coconut/helpers.rs create mode 100644 nym-connect/src/assets/help-step-one-legacy.png create mode 100644 nym-connect/src/assets/help-step-two-legacy.png create mode 100644 nym-connect/src/components/ExperimentalWarning.tsx create mode 100644 nym-connect/src/components/PowerButton.tsx rename nym-connect/src/components/{ServiceProviderInfo.tsx => TooltipInfo.tsx} (60%) delete mode 100644 nym-connect/src/layouts/ConnectedLayout.tsx create mode 100644 nym-connect/src/layouts/ConnectionLayout.tsx delete mode 100644 nym-connect/src/layouts/DefaultLayout.tsx delete mode 100644 nym-connect/src/layouts/HelpGuideLayout.tsx create mode 100644 nym-connect/src/pages/connection/Connected.tsx create mode 100644 nym-connect/src/pages/connection/Disconnected.tsx create mode 100644 nym-connect/src/pages/connection/index.tsx create mode 100644 nym-connect/src/pages/menu/Apps.tsx create mode 100644 nym-connect/src/pages/menu/Guide.tsx create mode 100644 nym-connect/src/pages/menu/index.tsx create mode 100644 nym-connect/src/routes/index.tsx create mode 100644 nym-connect/src/stories/PowerButton.stories.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index af9cf92aac..ec9414c775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,18 +4,31 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// # [Unreleased] +### Added + +- remove coconut feature and unify builds ([#2890]) + +[#2890]: https://github.com/nymtech/nym/pull/2890 + +# [v1.1.8] (2023-01-31) ### Added -- dkg rerun from scratch and dkg-specific epochs ([#2839]) -- nym-sdk: add support for surb storage ([#2870]) -- nym-sdk: enable reply-SURBs by default ([#2874]) -- remove coconut feature and unify builds ([#2890]) +- Rust SDK - Support SURBS (anonymous send + storage) ([#2754]) +- dkg rerun from scratch and dkg-specific epochs ([#2810]) +- Rename `'initial_supply'` field to `'total_supply'` in the circulating supply endpoint ([#2931]) +- Circulating supply api endpoint (read the note inside before testing/deploying) ([#1902]) + +### Changed + +- nym-api: an `--id` flag is now always explicitly required ([#2873]) + +[#2754]: https://github.com/nymtech/nym/issues/2754 +[#2839]: https://github.com/nymtech/nym/issues/2810 +[#2931]: https://github.com/nymtech/nym/issues/2931 +[#1902]: https://github.com/nymtech/nym/issues/1902 +[#2873]: https://github.com/nymtech/nym/issues/2873 -[#2839]: https://github.com/nymtech/nym/pull/2839 -[#2870]: https://github.com/nymtech/nym/pull/2870 -[#2874]: https://github.com/nymtech/nym/pull/2874 -[#2890]: https://github.com/nymtech/nym/pull/2890 # [v1.1.7] (2023-01-24) diff --git a/Cargo.lock b/Cargo.lock index 30841aab70..0f404263c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -701,7 +701,7 @@ dependencies = [ [[package]] name = "client-core" -version = "1.1.7" +version = "1.1.8" dependencies = [ "async-trait", "client-connections", @@ -1891,7 +1891,7 @@ dependencies = [ [[package]] name = "explorer-api" -version = "1.1.7" +version = "1.1.8" dependencies = [ "chrono", "clap 4.1.3", @@ -3314,6 +3314,7 @@ dependencies = [ "cw4", "schemars", "serde", + "thiserror", ] [[package]] @@ -3437,7 +3438,7 @@ dependencies = [ [[package]] name = "nym-api" -version = "1.1.7" +version = "1.1.8" dependencies = [ "anyhow", "async-trait", @@ -3535,7 +3536,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.7" +version = "1.1.8" dependencies = [ "anyhow", "base64 0.13.1", @@ -3593,7 +3594,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.7" +version = "1.1.8" dependencies = [ "build-information", "clap 4.1.3", @@ -3633,7 +3634,7 @@ dependencies = [ [[package]] name = "nym-gateway" -version = "1.1.7" +version = "1.1.8" dependencies = [ "anyhow", "async-trait", @@ -3685,7 +3686,7 @@ dependencies = [ [[package]] name = "nym-mixnode" -version = "1.1.8" +version = "1.1.9" dependencies = [ "anyhow", "atty", @@ -3730,7 +3731,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.7" +version = "1.1.8" dependencies = [ "async-trait", "clap 4.1.3", @@ -3762,7 +3763,7 @@ dependencies = [ [[package]] name = "nym-network-statistics" -version = "1.1.7" +version = "1.1.8" dependencies = [ "dirs", "log", @@ -3819,7 +3820,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.7" +version = "1.1.8" dependencies = [ "build-information", "clap 4.1.3", diff --git a/clients/client-core/Cargo.toml b/clients/client-core/Cargo.toml index 34ddb0de78..f9802bc367 100644 --- a/clients/client-core/Cargo.toml +++ b/clients/client-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "client-core" -version = "1.1.7" +version = "1.1.8" authors = ["Dave Hrycyszyn "] edition = "2021" rust-version = "1.66" diff --git a/clients/client-core/src/config/mod.rs b/clients/client-core/src/config/mod.rs index d7eada542c..e6085720a2 100644 --- a/clients/client-core/src/config/mod.rs +++ b/clients/client-core/src/config/mod.rs @@ -546,35 +546,35 @@ impl Default for Client { impl Client { fn default_private_identity_key_file(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("private_identity.pem") + T::default_data_directory(id).join("private_identity.pem") } fn default_public_identity_key_file(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("public_identity.pem") + T::default_data_directory(id).join("public_identity.pem") } fn default_private_encryption_key_file(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("private_encryption.pem") + T::default_data_directory(id).join("private_encryption.pem") } fn default_public_encryption_key_file(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("public_encryption.pem") + T::default_data_directory(id).join("public_encryption.pem") } fn default_gateway_shared_key_file(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("gateway_shared.pem") + T::default_data_directory(id).join("gateway_shared.pem") } fn default_ack_key_file(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("ack_key.pem") + T::default_data_directory(id).join("ack_key.pem") } fn default_reply_surb_database_path(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join("persistent_reply_store.sqlite") + T::default_data_directory(id).join("persistent_reply_store.sqlite") } fn default_database_path(id: &str) -> PathBuf { - T::default_data_directory(Some(id)).join(DB_FILE_NAME) + T::default_data_directory(id).join(DB_FILE_NAME) } } diff --git a/clients/client-core/src/init/mod.rs b/clients/client-core/src/init/mod.rs index 9af8a7c1bc..e236bd588b 100644 --- a/clients/client-core/src/init/mod.rs +++ b/clients/client-core/src/init/mod.rs @@ -149,7 +149,7 @@ pub fn load_existing_gateway_config(id: &str) -> Result", "Jędrzej Stuczyński "] description = "Implementation of the Nym Client" edition = "2021" diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index e3a0845223..c2273c020f 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -108,7 +108,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { let id = &args.id; - let already_init = Config::default_config_file_path(Some(id)).exists(); + let already_init = Config::default_config_file_path(id).exists(); if already_init { println!("Client \"{id}\" was already initialised before"); } diff --git a/clients/native/src/commands/run.rs b/clients/native/src/commands/run.rs index f7e73ba6fc..f0537be3c9 100644 --- a/clients/native/src/commands/run.rs +++ b/clients/native/src/commands/run.rs @@ -94,7 +94,7 @@ fn version_check(cfg: &Config) -> bool { pub(crate) async fn execute(args: &Run) -> Result<(), Box> { let id = &args.id; - let mut config = match Config::load_from_file(Some(id)) { + let mut config = match Config::load_from_file(id) { Ok(cfg) => cfg, Err(err) => { error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id); diff --git a/clients/native/src/commands/upgrade.rs b/clients/native/src/commands/upgrade.rs index 2d4a258011..a440054aea 100644 --- a/clients/native/src/commands/upgrade.rs +++ b/clients/native/src/commands/upgrade.rs @@ -131,7 +131,7 @@ pub(crate) fn execute(args: &Upgrade) { let id = &args.id; - let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| { + let existing_config = Config::load_from_file(id).unwrap_or_else(|err| { eprintln!("failed to load existing config file! - {err}"); process::exit(1) }); diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index c559c6351a..da121b4ad0 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-socks5-client" -version = "1.1.7" +version = "1.1.8" authors = ["Dave Hrycyszyn "] description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" edition = "2021" diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 0f451c67ae..38df141afe 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -117,7 +117,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> { let id = &args.id; let provider_address = &args.provider; - let already_init = Config::default_config_file_path(Some(id)).exists(); + let already_init = Config::default_config_file_path(id).exists(); if already_init { println!("SOCKS5 client \"{id}\" was already initialised before"); } diff --git a/clients/socks5/src/commands/run.rs b/clients/socks5/src/commands/run.rs index 9157f62513..cfb71032ba 100644 --- a/clients/socks5/src/commands/run.rs +++ b/clients/socks5/src/commands/run.rs @@ -108,7 +108,7 @@ fn version_check(cfg: &Config) -> bool { pub(crate) async fn execute(args: &Run) -> Result<(), Box> { let id = &args.id; - let mut config = match Config::load_from_file(Some(id)) { + let mut config = match Config::load_from_file(id) { Ok(cfg) => cfg, Err(err) => { error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id); diff --git a/clients/socks5/src/commands/upgrade.rs b/clients/socks5/src/commands/upgrade.rs index db77167f34..121f045905 100644 --- a/clients/socks5/src/commands/upgrade.rs +++ b/clients/socks5/src/commands/upgrade.rs @@ -144,7 +144,7 @@ pub(crate) fn execute(args: &Upgrade) { let id = &args.id; - let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| { + let existing_config = Config::load_from_file(id).unwrap_or_else(|err| { eprintln!("failed to load existing config file! - {err}"); process::exit(1) }); diff --git a/common/config/src/lib.rs b/common/config/src/lib.rs index d0ebecdca3..f14b94faf2 100644 --- a/common/config/src/lib.rs +++ b/common/config/src/lib.rs @@ -30,23 +30,15 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned { fn default_root_directory() -> PathBuf; // default, most probable, implementations; can be easily overridden where required - fn default_config_directory(id: Option<&str>) -> PathBuf { - if let Some(id) = id { - Self::default_root_directory().join(id).join(CONFIG_DIR) - } else { - Self::default_root_directory().join(CONFIG_DIR) - } + fn default_config_directory(id: &str) -> PathBuf { + Self::default_root_directory().join(id).join(CONFIG_DIR) } - fn default_data_directory(id: Option<&str>) -> PathBuf { - if let Some(id) = id { - Self::default_root_directory().join(id).join(DATA_DIR) - } else { - Self::default_root_directory().join(DATA_DIR) - } + fn default_data_directory(id: &str) -> PathBuf { + Self::default_root_directory().join(id).join(DATA_DIR) } - fn default_config_file_path(id: Option<&str>) -> PathBuf { + fn default_config_file_path(id: &str) -> PathBuf { Self::default_config_directory(id).join(Self::config_file_name()) } @@ -54,23 +46,15 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned { fn try_default_root_directory() -> Option; - fn try_default_config_directory(id: Option<&str>) -> Option { - if let Some(id) = id { - Self::try_default_root_directory().map(|d| d.join(id).join(CONFIG_DIR)) - } else { - Self::try_default_root_directory().map(|d| d.join(CONFIG_DIR)) - } + fn try_default_config_directory(id: &str) -> Option { + Self::try_default_root_directory().map(|d| d.join(id).join(CONFIG_DIR)) } - fn try_default_data_directory(id: Option<&str>) -> Option { - if let Some(id) = id { - Self::try_default_root_directory().map(|d| d.join(id).join(DATA_DIR)) - } else { - Self::try_default_root_directory().map(|d| d.join(DATA_DIR)) - } + fn try_default_data_directory(id: &str) -> Option { + Self::try_default_root_directory().map(|d| d.join(id).join(DATA_DIR)) } - fn try_default_config_file_path(id: Option<&str>) -> Option { + fn try_default_config_file_path(id: &str) -> Option { Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name())) } @@ -113,7 +97,7 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned { Ok(()) } - fn load_from_file(id: Option<&str>) -> io::Result { + fn load_from_file(id: &str) -> io::Result { let file = Self::default_config_file_path(id); log::trace!("Loading from file: {:#?}", file); let config_contents = fs::read_to_string(file)?; diff --git a/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml b/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml index f493cb6635..096e4affe0 100644 --- a/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml @@ -13,3 +13,4 @@ cw4 = { version = "0.13.4" } cosmwasm-std = "1.0.0" schemars = "0.8" serde = { version = "1.0.103", default-features = false, features = ["derive"] } +thiserror = { version = "1.0.23" } diff --git a/contracts/multisig/cw3-flex-multisig/src/error.rs b/common/cosmwasm-smart-contracts/multisig-contract/src/error.rs similarity index 90% rename from contracts/multisig/cw3-flex-multisig/src/error.rs rename to common/cosmwasm-smart-contracts/multisig-contract/src/error.rs index 75a546ca0e..b10fa6b506 100644 --- a/contracts/multisig/cw3-flex-multisig/src/error.rs +++ b/common/cosmwasm-smart-contracts/multisig-contract/src/error.rs @@ -1,3 +1,6 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + use cosmwasm_std::StdError; use cw_utils::ThresholdError; diff --git a/common/cosmwasm-smart-contracts/multisig-contract/src/lib.rs b/common/cosmwasm-smart-contracts/multisig-contract/src/lib.rs index d0e87a0d30..a968ed14e5 100644 --- a/common/cosmwasm-smart-contracts/multisig-contract/src/lib.rs +++ b/common/cosmwasm-smart-contracts/multisig-contract/src/lib.rs @@ -1 +1,2 @@ +pub mod error; pub mod msg; diff --git a/contracts/coconut-test/src/helpers.rs b/contracts/coconut-test/src/helpers.rs index 319e523c91..f5bd455d62 100644 --- a/contracts/coconut-test/src/helpers.rs +++ b/contracts/coconut-test/src/helpers.rs @@ -2,8 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use cosmwasm_std::{entry_point, Addr, Coin, DepsMut, Empty, Env, Response}; -use cw3_flex_multisig::{state::CONFIG, ContractError}; +use cw3_flex_multisig::state::CONFIG; use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper}; +use multisig_contract_common::error::ContractError; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/contracts/multisig/cw3-flex-multisig/Cargo.toml b/contracts/multisig/cw3-flex-multisig/Cargo.toml index e014c728b7..dd127b54ba 100644 --- a/contracts/multisig/cw3-flex-multisig/Cargo.toml +++ b/contracts/multisig/cw3-flex-multisig/Cargo.toml @@ -26,7 +26,6 @@ cw-storage-plus = { version = "0.13.4" } cosmwasm-std = { version = "1.0.0" } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.23" } group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" } multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" } diff --git a/contracts/multisig/cw3-flex-multisig/src/contract.rs b/contracts/multisig/cw3-flex-multisig/src/contract.rs index 677006daf4..edd1a648b2 100644 --- a/contracts/multisig/cw3-flex-multisig/src/contract.rs +++ b/contracts/multisig/cw3-flex-multisig/src/contract.rs @@ -17,8 +17,8 @@ use cw4::{Cw4Contract, MemberChangedHookMsg, MemberDiff}; use cw_storage_plus::Bound; use cw_utils::{maybe_addr, Expiration, ThresholdResponse}; -use crate::error::ContractError; use crate::state::{Config, CONFIG}; +use multisig_contract_common::error::ContractError; use multisig_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; // version info for migration info diff --git a/contracts/multisig/cw3-flex-multisig/src/lib.rs b/contracts/multisig/cw3-flex-multisig/src/lib.rs index e544aa55c8..3407c199dd 100644 --- a/contracts/multisig/cw3-flex-multisig/src/lib.rs +++ b/contracts/multisig/cw3-flex-multisig/src/lib.rs @@ -1,5 +1,2 @@ pub mod contract; -pub mod error; pub mod state; - -pub use crate::error::ContractError; diff --git a/envs/qa-qwerty.env b/envs/qa-qwerty.env index 30130fd6e9..474bf8d073 100644 --- a/envs/qa-qwerty.env +++ b/envs/qa-qwerty.env @@ -12,10 +12,10 @@ DENOMS_EXPONENT=6 MIXNET_CONTRACT_ADDRESS=n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0 -COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n12ckdkm3q7eytefs7rwu4ue3t9hxgvl9v08jddmtwgct2ve0pv50q0t8dlt -GROUP_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m -MULTISIG_CONTRACT_ADDRESS=n14krxe8ukzagwhvec0rmteexu62w8k9kp9sra9ww6em2hnmzcukqsa0utc8 -COCONUT_DKG_CONTRACT_ADDRESS=n1rl5n6cxuz2hdy3f7d9hsnw8zn0zwwwr0r4dxfz7tktgpgkcnz9zshmvksc +COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n19d2nwj7fdhxqmyvgy8lf3ad49a6vmww4shryhrkj2mqk36att66s6xzszw +GROUP_CONTRACT_ADDRESS=n1fqquzw4mk0pkamgr2ywt2v7h2j9nuyjjn4gvpy8zlpp6xn0uyuzqfm28l5 +MULTISIG_CONTRACT_ADDRESS=n1gaq3666chd5348apj8cka8t2mckv7azp9espyr7wgpxyuzur5d0sazpysy +COCONUT_DKG_CONTRACT_ADDRESS=n18yadscxw8v35dds7ksv3j0svmjh3h6e7tmxpadk96mvgz27zygkshuf4vs REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy STATISTICS_SERVICE_DOMAIN_ADDRESS="https://mainnet-stats.nymte.ch:8090" NYXD="https://qwerty-validator.qa.nymte.ch/" diff --git a/explorer-api/Cargo.toml b/explorer-api/Cargo.toml index 3d4e48f1ab..5d09ccb5c3 100644 --- a/explorer-api/Cargo.toml +++ b/explorer-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "explorer-api" -version = "1.1.7" +version = "1.1.8" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/explorer/CHANGELOG.md b/explorer/CHANGELOG.md index b021d3babc..2bdbaeab0e 100644 --- a/explorer/CHANGELOG.md +++ b/explorer/CHANGELOG.md @@ -1,5 +1,15 @@ ## UNRELEASED +## [nym-explorer-v1.0.4](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.4) (2023-01-31) + +- Add routing score on gateway list ([#2913]) +- Add gateway's last Routing Score to the gateways list page ([#2186]) +- Upgrade Sandbox and make below changes: ([#2332]) + +[#2913]: https://github.com/nymtech/nym/pull/2913 +[#2186]: https://github.com/nymtech/nym/issues/2186 +[#2332]: https://github.com/nymtech/nym/issues/2332 + ## [nym-explorer-v1.0.3](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.3) (2023-01-24) - Stake Saturation tooltip on node list and node pages updated ([#2877]) diff --git a/explorer/package.json b/explorer/package.json index 3ca03f5b56..c4b82c7a78 100644 --- a/explorer/package.json +++ b/explorer/package.json @@ -1,6 +1,6 @@ { "name": "@nym/network-explorer", - "version": "1.0.3", + "version": "1.0.4", "private": true, "license": "Apache-2.0", "dependencies": { @@ -120,4 +120,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/explorer/src/api/constants.ts b/explorer/src/api/constants.ts index e0488df565..81f6592c48 100644 --- a/explorer/src/api/constants.ts +++ b/explorer/src/api/constants.ts @@ -9,7 +9,7 @@ export const OVERVIEW_API = `${API_BASE_URL}/overview`; export const MIXNODE_PING = `${API_BASE_URL}/ping`; export const MIXNODES_API = `${API_BASE_URL}/mix-nodes`; export const MIXNODE_API = `${API_BASE_URL}/mix-node`; -export const GATEWAYS_API = `${NYM_API_BASE_URL}/api/v1/gateways`; +export const GATEWAYS_API = `${NYM_API_BASE_URL}/api/v1/status/gateways/detailed`; export const VALIDATORS_API = `${VALIDATOR_BASE_URL}/validators`; export const BLOCK_API = `${NYM_API_BASE_URL}/block`; export const COUNTRY_DATA_API = `${API_BASE_URL}/countries`; diff --git a/explorer/src/api/index.ts b/explorer/src/api/index.ts index 37e68b8096..49dcb04e85 100644 --- a/explorer/src/api/index.ts +++ b/explorer/src/api/index.ts @@ -15,7 +15,6 @@ import { CountryDataResponse, DelegationsResponse, UniqDelegationsResponse, - GatewayResponse, GatewayReportResponse, UptimeStoryResponse, MixNodeDescriptionResponse, @@ -27,7 +26,10 @@ import { StatusResponse, SummaryOverviewResponse, ValidatorsResponse, + GatewayBondAnnotated, + GatewayBond, } from '../typeDefs/explorer-api'; +import { toPercentIntegerString } from '../utils'; function getFromCache(key: string) { const ts = Number(localStorage.getItem('ts')); @@ -89,9 +91,13 @@ export class Api { return response.json(); }; - static fetchGateways = async (): Promise => { + static fetchGateways = async (): Promise => { const res = await fetch(GATEWAYS_API); - return res.json(); + const gatewaysAnnotated: GatewayBondAnnotated[] = await res.json(); + return gatewaysAnnotated.map(({ gateway_bond, performance }) => ({ + ...gateway_bond, + performance: toPercentIntegerString(performance), + })); }; static fetchGatewayUptimeStoryById = async (id: string): Promise => diff --git a/explorer/src/components/Gateways.ts b/explorer/src/components/Gateways.ts index aa055a71d0..1f81900ddc 100644 --- a/explorer/src/components/Gateways.ts +++ b/explorer/src/components/Gateways.ts @@ -1,4 +1,4 @@ -import { GatewayResponse, GatewayResponseItem, GatewayReportResponse } from '../typeDefs/explorer-api'; +import { GatewayResponse, GatewayBond, GatewayReportResponse } from '../typeDefs/explorer-api'; export type GatewayRowType = { id: string; @@ -8,6 +8,7 @@ export type GatewayRowType = { host: string; location: string; version: string; + performance: string; }; export type GatewayEnrichedRowType = GatewayRowType & { @@ -28,13 +29,11 @@ export function gatewayToGridRow(arrayOfGateways: GatewayResponse): GatewayRowTy bond: gw.pledge_amount.amount || 0, host: gw.gateway.host || '', version: gw.gateway.version || '', + performance: gw.performance, })); } -export function gatewayEnrichedToGridRow( - gateway: GatewayResponseItem, - report: GatewayReportResponse, -): GatewayEnrichedRowType { +export function gatewayEnrichedToGridRow(gateway: GatewayBond, report: GatewayReportResponse): GatewayEnrichedRowType { return { id: gateway.owner, owner: gateway.owner, @@ -47,5 +46,6 @@ export function gatewayEnrichedToGridRow( mixPort: gateway.gateway.mix_port || 0, routingScore: `${report.most_recent}%`, avgUptime: `${report.last_day || report.last_hour}%`, + performance: gateway.performance, }; } diff --git a/explorer/src/pages/GatewayDetail/index.tsx b/explorer/src/pages/GatewayDetail/index.tsx index 752b1be58a..6989fc2216 100644 --- a/explorer/src/pages/GatewayDetail/index.tsx +++ b/explorer/src/pages/GatewayDetail/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Alert, AlertTitle, Box, CircularProgress, Grid } from '@mui/material'; import { useParams } from 'react-router-dom'; -import { GatewayResponseItem } from '../../typeDefs/explorer-api'; +import { GatewayBond } from '../../typeDefs/explorer-api'; import { ColumnsType, DetailTable } from '../../components/DetailTable'; import { gatewayEnrichedToGridRow, GatewayEnrichedRowType } from '../../components/Gateways'; import { ComponentError } from '../../components/ComponentError'; @@ -69,7 +69,7 @@ const columns: ColumnsType[] = [ /** * Shows gateway details */ -const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: GatewayResponseItem | undefined }) => { +const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: GatewayBond | undefined }) => { const [enrichGateway, setEnrichGateway] = React.useState(); const [status, setStatus] = React.useState(); const { uptimeReport, uptimeStory } = useGatewayContext(); @@ -130,7 +130,7 @@ const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: Gat * Guard component to handle loading and not found states */ const PageGatewayDetailGuard: FCWithChildren = () => { - const [selectedGateway, setSelectedGateway] = React.useState(); + const [selectedGateway, setSelectedGateway] = React.useState(); const { gateways } = useMainContext(); const { id } = useParams<{ id: string | undefined }>(); diff --git a/explorer/src/pages/Gateways/index.tsx b/explorer/src/pages/Gateways/index.tsx index aa2b7077bd..ab93e4c4eb 100644 --- a/explorer/src/pages/Gateways/index.tsx +++ b/explorer/src/pages/Gateways/index.tsx @@ -81,6 +81,24 @@ export const PageGateways: FCWithChildren = () => { ), }, + { + field: 'performance', + headerName: 'Routing Score', + renderHeader: () => , + width: 150, + headerAlign: 'left', + headerClassName: 'MuiDataGrid-header-override', + renderCell: (params: GridRenderCellParams) => ( + + {`${params.value}%`} + + ), + }, { field: 'host', renderHeader: () => , diff --git a/explorer/src/typeDefs/explorer-api.ts b/explorer/src/typeDefs/explorer-api.ts index 188a0c3ac0..48cf2091d9 100644 --- a/explorer/src/typeDefs/explorer-api.ts +++ b/explorer/src/typeDefs/explorer-api.ts @@ -116,15 +116,21 @@ export interface StatsResponse { export type MixNodeHistoryResponse = StatsResponse; -export interface GatewayResponseItem { +export interface GatewayBond { block_height: number; pledge_amount: Amount; total_delegation: Amount; owner: string; gateway: Gateway; + performance: string; } -export type GatewayResponse = GatewayResponseItem[]; +export interface GatewayBondAnnotated { + gateway_bond: GatewayBond; + performance: string; +} + +export type GatewayResponse = GatewayBond[]; export interface GatewayReportResponse { identity: string; diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 3a6f126b69..5b1fd14ccf 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-gateway" -version = "1.1.7" +version = "1.1.8" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/gateway/src/commands/init.rs b/gateway/src/commands/init.rs index 70f979b844..45548d7cd8 100644 --- a/gateway/src/commands/init.rs +++ b/gateway/src/commands/init.rs @@ -102,7 +102,7 @@ impl From for OverrideConfig { pub async fn execute(args: Init, output: OutputFormat) -> Result<(), Box> { println!("Initialising gateway {}...", args.id); - let already_init = if Config::default_config_file_path(Some(&args.id)).exists() { + let already_init = if Config::default_config_file_path(&args.id).exists() { eprintln!( "Gateway \"{}\" was already initialised before! Config information will be \ overwritten (but keys will be kept)!", diff --git a/gateway/src/commands/upgrade.rs b/gateway/src/commands/upgrade.rs index b4ea39c493..b3eefd9ed2 100644 --- a/gateway/src/commands/upgrade.rs +++ b/gateway/src/commands/upgrade.rs @@ -139,7 +139,7 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) { pub async fn execute(args: &Upgrade) { let package_version = parse_package_version(); - let existing_config = Config::load_from_file(Some(&args.id)).unwrap_or_else(|err| { + let existing_config = Config::load_from_file(&args.id).unwrap_or_else(|err| { eprintln!("failed to load existing config file! - {err}"); process::exit(1) }); diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index 6f7f937594..924f361779 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -374,23 +374,23 @@ pub struct Gateway { impl Gateway { fn default_private_sphinx_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("private_sphinx.pem") + Config::default_data_directory(id).join("private_sphinx.pem") } fn default_public_sphinx_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("public_sphinx.pem") + Config::default_data_directory(id).join("public_sphinx.pem") } fn default_private_identity_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("private_identity.pem") + Config::default_data_directory(id).join("private_identity.pem") } fn default_public_identity_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("public_identity.pem") + Config::default_data_directory(id).join("public_identity.pem") } fn default_database_path(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("db.sqlite") + Config::default_data_directory(id).join("db.sqlite") } } diff --git a/gateway/src/support/config.rs b/gateway/src/support/config.rs index ff61d95da8..90576a4d89 100644 --- a/gateway/src/support/config.rs +++ b/gateway/src/support/config.rs @@ -11,14 +11,14 @@ pub(crate) fn build_config>( id: String, override_args: O, ) -> Result { - let config = match Config::load_from_file(Some(&id)) { + let config = match Config::load_from_file(&id) { Ok(cfg) => cfg, Err(err) => { error!( "Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})", ); return Err(GatewayError::ConfigLoadFailure { - path: Config::default_config_file_path(Some(&id)), + path: Config::default_config_file_path(&id), id, source: err, }); diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index ea5577f64c..69b4deb6e2 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-mixnode" -version = "1.1.8" +version = "1.1.9" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/mixnode/src/commands/describe.rs b/mixnode/src/commands/describe.rs index 5b66eb8d87..d9cecbe410 100644 --- a/mixnode/src/commands/describe.rs +++ b/mixnode/src/commands/describe.rs @@ -41,7 +41,7 @@ fn read_user_input() -> String { pub(crate) fn execute(args: Describe) { // ensure that the mixnode has in fact been initialized - match Config::load_from_file(Some(&args.id)) { + match Config::load_from_file(&args.id) { Ok(cfg) => cfg, Err(err) => { error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", &args.id); @@ -83,7 +83,7 @@ pub(crate) fn execute(args: Describe) { // save the struct NodeDescription::save_to_file( &node_description, - Config::default_config_directory(Some(&args.id)), + Config::default_config_directory(&args.id), ) .unwrap() } diff --git a/mixnode/src/commands/init.rs b/mixnode/src/commands/init.rs index d25b234ab8..fe6b18bc4f 100644 --- a/mixnode/src/commands/init.rs +++ b/mixnode/src/commands/init.rs @@ -68,7 +68,7 @@ pub(crate) fn execute(args: &Init, output: OutputFormat) { let id = &override_config_fields.id; eprintln!("Initialising mixnode {id}..."); - let already_init = if Config::default_config_file_path(Some(id)).exists() { + let already_init = if Config::default_config_file_path(id).exists() { eprintln!("Mixnode \"{id}\" was already initialised before! Config information will be overwritten (but keys will be kept)!"); true } else { diff --git a/mixnode/src/commands/node_details.rs b/mixnode/src/commands/node_details.rs index cdc0d5162a..98298cea74 100644 --- a/mixnode/src/commands/node_details.rs +++ b/mixnode/src/commands/node_details.rs @@ -15,7 +15,7 @@ pub(crate) struct NodeDetails { } pub(crate) fn execute(args: &NodeDetails, output: OutputFormat) { - let config = match Config::load_from_file(Some(&args.id)) { + let config = match Config::load_from_file(&args.id) { Ok(cfg) => cfg, Err(err) => { error!( diff --git a/mixnode/src/commands/run.rs b/mixnode/src/commands/run.rs index 910b9fc869..e578c422c1 100644 --- a/mixnode/src/commands/run.rs +++ b/mixnode/src/commands/run.rs @@ -79,7 +79,7 @@ fn special_addresses() -> Vec<&'static str> { pub(crate) async fn execute(args: &Run, output: OutputFormat) { eprintln!("Starting mixnode {}...", args.id); - let mut config = match Config::load_from_file(Some(&args.id)) { + let mut config = match Config::load_from_file(&args.id) { Ok(cfg) => cfg, Err(err) => { error!( diff --git a/mixnode/src/commands/sign.rs b/mixnode/src/commands/sign.rs index ed84cc6d3b..52360d7a03 100644 --- a/mixnode/src/commands/sign.rs +++ b/mixnode/src/commands/sign.rs @@ -71,7 +71,7 @@ fn print_signed_text(private_key: &identity::PrivateKey, text: &str) { } pub(crate) fn execute(args: &Sign) { - let config = match Config::load_from_file(Some(&args.id)) { + let config = match Config::load_from_file(&args.id) { Ok(cfg) => cfg, Err(err) => { error!( diff --git a/mixnode/src/commands/upgrade.rs b/mixnode/src/commands/upgrade.rs index 3ba4192289..46c8192312 100644 --- a/mixnode/src/commands/upgrade.rs +++ b/mixnode/src/commands/upgrade.rs @@ -125,7 +125,7 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) { pub(crate) fn execute(args: &Upgrade) { let package_version = parse_package_version(); - let existing_config = Config::load_from_file(Some(&args.id)).unwrap_or_else(|err| { + let existing_config = Config::load_from_file(&args.id).unwrap_or_else(|err| { eprintln!("failed to load existing config file! - {err}"); process::exit(1) }); diff --git a/mixnode/src/config/mod.rs b/mixnode/src/config/mod.rs index 2b69e45725..6183ba073e 100644 --- a/mixnode/src/config/mod.rs +++ b/mixnode/src/config/mod.rs @@ -376,19 +376,19 @@ struct MixNode { impl MixNode { fn default_private_identity_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("private_identity.pem") + Config::default_data_directory(id).join("private_identity.pem") } fn default_public_identity_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("public_identity.pem") + Config::default_data_directory(id).join("public_identity.pem") } fn default_private_sphinx_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("private_sphinx.pem") + Config::default_data_directory(id).join("private_sphinx.pem") } fn default_public_sphinx_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("public_sphinx.pem") + Config::default_data_directory(id).join("public_sphinx.pem") } } diff --git a/mixnode/src/node/mod.rs b/mixnode/src/node/mod.rs index ccf4a9a3db..e581860fbd 100644 --- a/mixnode/src/node/mod.rs +++ b/mixnode/src/node/mod.rs @@ -58,7 +58,7 @@ impl MixNode { } fn load_node_description(config: &Config) -> NodeDescription { - NodeDescription::load_from_file(Config::default_config_directory(Some(&config.get_id()))) + NodeDescription::load_from_file(Config::default_config_directory(&config.get_id())) .unwrap_or_default() } diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index ea1b70f0e5..a32ea8c807 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-api" -version = "1.1.7" +version = "1.1.8" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/nym-api/nym-api-requests/src/models.rs b/nym-api/nym-api-requests/src/models.rs index 237f4ce90d..e241fad0e1 100644 --- a/nym-api/nym-api-requests/src/models.rs +++ b/nym-api/nym-api-requests/src/models.rs @@ -291,7 +291,7 @@ pub struct GatewayUptimeHistoryResponse { #[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] pub struct CirculatingSupplyResponse { - pub initial_supply: Coin, + pub total_supply: Coin, pub mixmining_reserve: Coin, pub vesting_tokens: Coin, pub circulating_supply: Coin, diff --git a/nym-api/src/circulating_supply_api/cache/data.rs b/nym-api/src/circulating_supply_api/cache/data.rs index 9fb68a8cac..17e906dff3 100644 --- a/nym-api/src/circulating_supply_api/cache/data.rs +++ b/nym-api/src/circulating_supply_api/cache/data.rs @@ -7,7 +7,7 @@ use validator_client::nyxd::Coin; pub(crate) struct CirculatingSupplyCacheData { // no need to cache that one as it's constant, but let's put it here for consistency sake - pub(crate) initial_supply: Coin, + pub(crate) total_supply: Coin, pub(crate) mixmining_reserve: Cache, pub(crate) vesting_tokens: Cache, pub(crate) circulating_supply: Cache, @@ -18,7 +18,7 @@ impl CirculatingSupplyCacheData { let zero_coin = Coin::new(0, &mix_denom); CirculatingSupplyCacheData { - initial_supply: Coin::new(1_000_000_000_000_000, mix_denom), + total_supply: Coin::new(1_000_000_000_000_000, mix_denom), mixmining_reserve: Cache::new(zero_coin.clone()), vesting_tokens: Cache::new(zero_coin.clone()), circulating_supply: Cache::new(zero_coin), @@ -29,7 +29,7 @@ impl CirculatingSupplyCacheData { impl<'a> From<&'a CirculatingSupplyCacheData> for CirculatingSupplyResponse { fn from(value: &'a CirculatingSupplyCacheData) -> Self { CirculatingSupplyResponse { - initial_supply: value.initial_supply.clone().into(), + total_supply: value.total_supply.clone().into(), mixmining_reserve: value.mixmining_reserve.clone().into_inner().into(), vesting_tokens: value.vesting_tokens.clone().into_inner().into(), circulating_supply: value.circulating_supply.clone().into_inner().into(), diff --git a/nym-api/src/circulating_supply_api/cache/mod.rs b/nym-api/src/circulating_supply_api/cache/mod.rs index 5e12477476..2f432c8d4d 100644 --- a/nym-api/src/circulating_supply_api/cache/mod.rs +++ b/nym-api/src/circulating_supply_api/cache/mod.rs @@ -76,7 +76,7 @@ impl CirculatingSupplyCache { pub(crate) async fn update(&self, mixmining_reserve: Coin, vesting_tokens: Coin) { let mut cache = self.data.write().await; - let mut circulating_supply = cache.initial_supply.clone(); + let mut circulating_supply = cache.total_supply.clone(); circulating_supply.amount -= mixmining_reserve.amount; circulating_supply.amount -= vesting_tokens.amount; diff --git a/nym-api/src/coconut/dkg/verification_key.rs b/nym-api/src/coconut/dkg/verification_key.rs index 15f0138a90..9aed655cfa 100644 --- a/nym-api/src/coconut/dkg/verification_key.rs +++ b/nym-api/src/coconut/dkg/verification_key.rs @@ -5,6 +5,7 @@ use crate::coconut::dkg::client::DkgClient; use crate::coconut::dkg::complaints::ComplaintReason; use crate::coconut::dkg::state::{ConsistentState, State}; use crate::coconut::error::CoconutError; +use crate::coconut::helpers::accepted_vote_err; use coconut_dkg_common::event_attributes::DKG_PROPOSAL_ID; use coconut_dkg_common::types::{NodeIndex, TOTAL_DEALINGS}; use coconut_dkg_common::verification_key::owner_from_cosmos_msgs; @@ -203,21 +204,23 @@ pub(crate) async fn verification_key_validation( .iter() .position(|node_index| contract_share.node_index == *node_index) { - if !check_vk_pairing(¶ms, &recovered_partials[idx], &vk) { + let ret = if !check_vk_pairing(¶ms, &recovered_partials[idx], &vk) { dkg_client .vote_verification_key_share(proposal_id, false) - .await?; + .await } else { dkg_client .vote_verification_key_share(proposal_id, true) - .await?; - } + .await + }; + accepted_vote_err(ret)?; } } Err(_) => { - dkg_client + let ret = dkg_client .vote_verification_key_share(proposal_id, false) - .await? + .await; + accepted_vote_err(ret)?; } } } diff --git a/nym-api/src/coconut/helpers.rs b/nym-api/src/coconut/helpers.rs new file mode 100644 index 0000000000..986bb6b305 --- /dev/null +++ b/nym-api/src/coconut/helpers.rs @@ -0,0 +1,18 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::coconut::error::CoconutError; +use validator_client::nyxd::error::NyxdError::AbciError; + +// If the result is already established, the vote might be redundant and +// thus the transaction might fail +pub(crate) fn accepted_vote_err(ret: Result<(), CoconutError>) -> Result<(), CoconutError> { + if let Err(CoconutError::NyxdError(AbciError { ref log, .. })) = ret { + let accepted_err = multisig_contract_common::error::ContractError::NotOpen {}.to_string(); + // If redundant voting is not the case, error out on all other error variants + if !log.value().contains(&accepted_err) { + ret?; + } + } + Ok(()) +} diff --git a/nym-api/src/coconut/mod.rs b/nym-api/src/coconut/mod.rs index a0aa042440..dd059923cb 100644 --- a/nym-api/src/coconut/mod.rs +++ b/nym-api/src/coconut/mod.rs @@ -5,6 +5,7 @@ use self::comm::APICommunicationChannel; use crate::coconut::client::Client as LocalClient; use crate::coconut::deposit::extract_encryption_key; use crate::coconut::error::{CoconutError, Result}; +use crate::coconut::helpers::accepted_vote_err; use crate::support::storage::NymApiStorage; use coconut_bandwidth_contract_common::spend_credential::{ funds_from_cosmos_msgs, SpendCredentialStatus, @@ -40,6 +41,7 @@ pub(crate) mod comm; mod deposit; pub(crate) mod dkg; pub(crate) mod error; +pub(crate) mod helpers; pub(crate) mod keypair; #[cfg(test)] pub(crate) mod tests; @@ -301,7 +303,7 @@ pub async fn verify_bandwidth_credential( ); // Vote yes or no on the proposal based on the verification result - state + let ret = state .client .vote_proposal( proposal_id, @@ -312,7 +314,8 @@ pub async fn verify_bandwidth_credential( Some(verify_credential_body.gateway_cosmos_addr().to_owned()), )), ) - .await?; + .await; + accepted_vote_err(ret)?; Ok(Json(VerifyCredentialResponse::new(vote_yes))) } diff --git a/nym-api/src/support/cli/mod.rs b/nym-api/src/support/cli/mod.rs index 674e29fc1c..3000177dbf 100644 --- a/nym-api/src/support/cli/mod.rs +++ b/nym-api/src/support/cli/mod.rs @@ -44,7 +44,7 @@ pub(crate) struct CliArgs { /// Id of the nym-api we want to run #[clap(long)] - pub(crate) id: Option, + pub(crate) id: String, /// Specifies whether network monitoring is enabled on this API #[clap(short = 'm', long)] @@ -102,12 +102,13 @@ pub(crate) struct CliArgs { } pub(crate) fn build_config(args: CliArgs) -> Result { + let id = args.id.clone(); + // try to load config from the file, if it doesn't exist, use default values - let id = args.id.as_deref(); - let (config_from_file, _already_initialized) = match Config::load_from_file(id) { + let (config_from_file, already_initialized) = match Config::load_from_file(&id) { Ok(cfg) => (cfg, true), Err(_) => { - let config_path = Config::default_config_file_path(id) + let config_path = Config::default_config_file_path(&id) .into_os_string() .into_string() .unwrap(); @@ -121,7 +122,17 @@ pub(crate) fn build_config(args: CliArgs) -> Result { let config = override_config(config_from_file, args); +<<<<<<< HEAD if !_already_initialized { +======= + if already_initialized { + fs::create_dir_all(Config::default_config_directory(&id)) + .expect("Could not create config directory"); + fs::create_dir_all(Config::default_data_directory(&id)) + .expect("Could not create data directory"); + + #[cfg(feature = "coconut")] +>>>>>>> release/v1.1.8 crate::coconut::dkg::controller::init_keypair(&config)?; } @@ -129,6 +140,7 @@ pub(crate) fn build_config(args: CliArgs) -> Result { } pub(crate) fn override_config(mut config: Config, args: CliArgs) -> Config { +<<<<<<< HEAD if let Some(id) = args.id { fs::create_dir_all(Config::default_config_directory(Some(&id))) .expect("Could not create config directory"); @@ -138,6 +150,10 @@ pub(crate) fn override_config(mut config: Config, args: CliArgs) -> Config { } config +======= + config = config + .with_id(&args.id) +>>>>>>> release/v1.1.8 .with_optional(Config::with_custom_nyxd_validator, args.nyxd_validator) .with_optional_env( Config::with_custom_mixnet_contract, diff --git a/nym-api/src/support/config/mod.rs b/nym-api/src/support/config/mod.rs index 50bdb34826..1b2645c393 100644 --- a/nym-api/src/support/config/mod.rs +++ b/nym-api/src/support/config/mod.rs @@ -201,8 +201,8 @@ pub struct NetworkMonitor { impl NetworkMonitor { pub const DB_FILE: &'static str = "credentials_database.db"; - fn default_credentials_database_path() -> PathBuf { - Config::default_data_directory(None).join(Self::DB_FILE) + fn default_credentials_database_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::DB_FILE) } } @@ -220,7 +220,7 @@ impl Default for NetworkMonitor { gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT, gateway_connection_timeout: DEFAULT_GATEWAY_CONNECTION_TIMEOUT, packet_delivery_timeout: DEFAULT_PACKET_DELIVERY_TIMEOUT, - credentials_database_path: Self::default_credentials_database_path(), + credentials_database_path: Default::default(), test_routes: DEFAULT_TEST_ROUTES, minimum_test_routes: DEFAULT_MINIMUM_TEST_ROUTES, route_test_packets: DEFAULT_ROUTE_TEST_PACKETS, @@ -242,15 +242,15 @@ pub struct NodeStatusAPI { impl NodeStatusAPI { pub const DB_FILE: &'static str = "db.sqlite"; - fn default_database_path() -> PathBuf { - Config::default_data_directory(None).join(Self::DB_FILE) + fn default_database_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::DB_FILE) } } impl Default for NodeStatusAPI { fn default() -> Self { NodeStatusAPI { - database_path: Self::default_database_path(), + database_path: Default::default(), caching_interval: DEFAULT_NODE_STATUS_CACHE_INTERVAL, } } @@ -342,24 +342,24 @@ impl CoconutSigner { pub const COCONUT_VERIFICATION_KEY_FILE: &'static str = "coconut_verification_key.pem"; pub const COCONUT_SECRET_KEY_FILE: &'static str = "coconut_secret_key.pem"; - fn default_coconut_verification_key_path() -> PathBuf { - Config::default_data_directory(None).join(Self::COCONUT_VERIFICATION_KEY_FILE) + fn default_coconut_verification_key_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::COCONUT_VERIFICATION_KEY_FILE) } - fn default_coconut_secret_key_path() -> PathBuf { - Config::default_data_directory(None).join(Self::COCONUT_SECRET_KEY_FILE) + fn default_coconut_secret_key_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::COCONUT_SECRET_KEY_FILE) } - fn default_dkg_persistent_state_path() -> PathBuf { - Config::default_data_directory(None).join(Self::DKG_PERSISTENT_STATE_FILE) + fn default_dkg_persistent_state_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::DKG_PERSISTENT_STATE_FILE) } - fn default_dkg_decryption_key_path() -> PathBuf { - Config::default_data_directory(None).join(Self::DKG_DECRYPTION_KEY_FILE) + fn default_dkg_decryption_key_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::DKG_DECRYPTION_KEY_FILE) } - fn default_dkg_public_key_with_proof_path() -> PathBuf { - Config::default_data_directory(None).join(Self::DKG_PUBLIC_KEY_WITH_PROOF_FILE) + fn default_dkg_public_key_with_proof_path(id: &str) -> PathBuf { + Config::default_data_directory(id).join(Self::DKG_PUBLIC_KEY_WITH_PROOF_FILE) } } @@ -367,11 +367,11 @@ impl Default for CoconutSigner { fn default() -> Self { Self { enabled: Default::default(), - dkg_persistent_state_path: CoconutSigner::default_dkg_persistent_state_path(), - verification_key_path: CoconutSigner::default_coconut_verification_key_path(), - secret_key_path: CoconutSigner::default_coconut_secret_key_path(), - decryption_key_path: CoconutSigner::default_dkg_decryption_key_path(), - public_key_with_proof_path: CoconutSigner::default_dkg_public_key_with_proof_path(), + dkg_persistent_state_path: Default::default(), + verification_key_path: Default::default(), + secret_key_path: Default::default(), + decryption_key_path: Default::default(), + public_key_with_proof_path: Default::default(), dkg_contract_polling_rate: DEFAULT_DKG_CONTRACT_POLLING_RATE, } } @@ -384,20 +384,18 @@ impl Config { pub fn with_id(mut self, id: &str) -> Self { self.base.id = id.to_string(); - self.node_status_api.database_path = - Config::default_data_directory(Some(id)).join(NodeStatusAPI::DB_FILE); + self.node_status_api.database_path = NodeStatusAPI::default_database_path(id); self.network_monitor.credentials_database_path = - Config::default_data_directory(Some(id)).join(NetworkMonitor::DB_FILE); + NetworkMonitor::default_credentials_database_path(id); self.coconut_signer.dkg_persistent_state_path = - Config::default_data_directory(Some(id)).join(CoconutSigner::DKG_PERSISTENT_STATE_FILE); - self.coconut_signer.verification_key_path = Config::default_data_directory(Some(id)) - .join(CoconutSigner::COCONUT_VERIFICATION_KEY_FILE); - self.coconut_signer.secret_key_path = - Config::default_data_directory(Some(id)).join(CoconutSigner::COCONUT_SECRET_KEY_FILE); + CoconutSigner::default_dkg_persistent_state_path(id); + self.coconut_signer.verification_key_path = + CoconutSigner::default_coconut_verification_key_path(id); + self.coconut_signer.secret_key_path = CoconutSigner::default_coconut_secret_key_path(id); self.coconut_signer.decryption_key_path = - Config::default_data_directory(Some(id)).join(CoconutSigner::DKG_DECRYPTION_KEY_FILE); - self.coconut_signer.public_key_with_proof_path = Config::default_data_directory(Some(id)) - .join(CoconutSigner::DKG_PUBLIC_KEY_WITH_PROOF_FILE); + CoconutSigner::default_dkg_decryption_key_path(id); + self.coconut_signer.public_key_with_proof_path = + CoconutSigner::default_dkg_public_key_with_proof_path(id); self } diff --git a/nym-connect/CHANGELOG.md b/nym-connect/CHANGELOG.md index cddba036e0..c1bf4a7b85 100644 --- a/nym-connect/CHANGELOG.md +++ b/nym-connect/CHANGELOG.md @@ -2,6 +2,14 @@ ## UNRELEASED +## [nym-connect-v1.1.8](https://github.com/nymtech/nym/tree/nym-connect-v1.1.8) (2023-01-31) + +- Add supported apps in the menu + update guide ([#2868]) +- Copy changes to remove the dropdown: ([#2777]) + +[#2868]: https://github.com/nymtech/nym/issues/2868 +[#2777]: https://github.com/nymtech/nym/issues/2777 + ## [nym-connect-v1.1.7](https://github.com/nymtech/nym/tree/nym-connect-v1.1.7) (2023-01-24) - Remove test and earn ([#2865]) diff --git a/nym-connect/package.json b/nym-connect/package.json index 4fb0869862..127ac38de1 100644 --- a/nym-connect/package.json +++ b/nym-connect/package.json @@ -1,6 +1,6 @@ { "name": "@nym/nym-connect", - "version": "1.1.7", + "version": "1.1.8", "main": "index.js", "license": "MIT", "scripts": { @@ -43,7 +43,7 @@ "react-error-boundary": "^3.1.3", "react-hook-form": "^7.14.2", "react-markdown": "^8.0.4", - "react-router-dom": "^5.2.0", + "react-router-dom": "^6.7.0", "semver": "^6.3.0", "yup": "^0.32.9" }, @@ -113,4 +113,4 @@ "webpack-merge": "^5.8.0", "yaml-loader": "^0.8.0" } -} +} \ No newline at end of file diff --git a/nym-connect/src-tauri/Cargo.toml b/nym-connect/src-tauri/Cargo.toml index dd88c73c49..54c39aac73 100644 --- a/nym-connect/src-tauri/Cargo.toml +++ b/nym-connect/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-connect" -version = "1.1.7" +version = "1.1.8" description = "nym-connect" authors = ["Nym Technologies SA"] license = "" diff --git a/nym-connect/src-tauri/src/config/mod.rs b/nym-connect/src-tauri/src/config/mod.rs index b7fa03636b..9c51348b42 100644 --- a/nym-connect/src-tauri/src/config/mod.rs +++ b/nym-connect/src-tauri/src/config/mod.rs @@ -93,7 +93,7 @@ impl Config { } pub fn config_file_location(id: &str) -> Result { - Socks5Config::try_default_config_file_path(Some(id)) + Socks5Config::try_default_config_file_path(id) .ok_or(BackendError::CouldNotGetConfigFilename) } } diff --git a/nym-connect/src-tauri/src/error.rs b/nym-connect/src-tauri/src/error.rs index 50a672f8ac..11ae239f77 100644 --- a/nym-connect/src-tauri/src/error.rs +++ b/nym-connect/src-tauri/src/error.rs @@ -56,9 +56,9 @@ pub enum BackendError { InitializationPanic, #[error("could not get config id before gateway is set")] CouldNotGetIdWithoutGateway, - #[error("could initialize without gateway set")] + #[error("could not initialize without gateway set")] CouldNotInitWithoutGateway, - #[error("could initialize without service provider set")] + #[error("could not initialize without service provider set")] CouldNotInitWithoutServiceProvider, #[error("could not get file name")] CouldNotGetFilename, diff --git a/nym-connect/src-tauri/src/state.rs b/nym-connect/src-tauri/src/state.rs index 84526f1d11..949adfe8dc 100644 --- a/nym-connect/src-tauri/src/state.rs +++ b/nym-connect/src-tauri/src/state.rs @@ -154,7 +154,7 @@ impl State { pub fn load_socks5_config(&self) -> Result { let id = self.get_config_id()?; - let config = Socks5Config::load_from_file(Some(&id)) + let config = Socks5Config::load_from_file(&id) .tap_err(|_| log::warn!("Failed to load configuration file"))?; Ok(config) } diff --git a/nym-connect/src-tauri/src/tasks.rs b/nym-connect/src-tauri/src/tasks.rs index 423097d0ab..1cf53b55d3 100644 --- a/nym-connect/src-tauri/src/tasks.rs +++ b/nym-connect/src-tauri/src/tasks.rs @@ -41,7 +41,7 @@ pub fn start_nym_socks5_client( GatewayEndpointConfig, )> { log::info!("Loading config from file: {id}"); - let config = Socks5Config::load_from_file(Some(id)) + let config = Socks5Config::load_from_file(id) .tap_err(|_| log::warn!("Failed to load configuration file"))?; let used_gateway = config.get_base().get_gateway_endpoint().clone(); diff --git a/nym-connect/src-tauri/tauri.conf.json b/nym-connect/src-tauri/tauri.conf.json index 96cc9f0fa6..deff29513f 100644 --- a/nym-connect/src-tauri/tauri.conf.json +++ b/nym-connect/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "nym-connect", - "version": "1.1.7" + "version": "1.1.8" }, "build": { "distDir": "../dist", @@ -19,7 +19,13 @@ "active": true, "targets": "all", "identifier": "net.nymtech.connect", - "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], "resources": [], "externalBin": [], "copyright": "Copyright © 2021-2022 Nym Technologies SA", @@ -44,7 +50,9 @@ }, "updater": { "active": true, - "endpoints": ["https://nymtech.net/.wellknown/connect/updater.json"], + "endpoints": [ + "https://nymtech.net/.wellknown/connect/updater.json" + ], "dialog": true, "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IENCNzQ2M0E5N0VFODE2NApSV1JrZ2U2WE9rYTNETTg1OTBKdE5uWUEra0hML2syOVUvQ2lxZmFZRzZ1T3NWbGM0eVRzUTVhVwo=" }, @@ -68,7 +76,7 @@ { "title": "NymConnect", "width": 240, - "height": 635, + "height": 480, "resizable": false, "decorations": false, "transparent": true @@ -78,4 +86,4 @@ "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'" } } -} +} \ No newline at end of file diff --git a/nym-connect/src/App.tsx b/nym-connect/src/App.tsx index 3b3295ccd8..9d57dcf4d8 100644 --- a/nym-connect/src/App.tsx +++ b/nym-connect/src/App.tsx @@ -1,17 +1,15 @@ import React, { useEffect } from 'react'; import { DateTime } from 'luxon'; import { forage } from '@tauri-apps/tauri-forage'; -import { ConnectionStatusKind } from './types'; import { useClientContext } from './context/main'; -import { DefaultLayout } from './layouts/DefaultLayout'; -import { ConnectedLayout } from './layouts/ConnectedLayout'; -import { HelpGuideLayout } from './layouts/HelpGuideLayout'; import { useTauriEvents } from './utils'; +import { AppRoutes } from './routes'; +import { Connected } from './pages/connection/Connected'; export const App: FCWithChildren = () => { const context = useClientContext(); const [busy, setBusy] = React.useState(); - const [showInfoModal, setShowInfoModal] = React.useState(false); + useTauriEvents('help://clear-storage', (_event) => { console.log('About to clear local storage...'); // clear local storage @@ -25,16 +23,16 @@ export const App: FCWithChildren = () => { const handleConnectClick = React.useCallback(async () => { const currentStatus = context.connectionStatus; - if (currentStatus === ConnectionStatusKind.connected || currentStatus === ConnectionStatusKind.disconnected) { + if (currentStatus === 'connected' || currentStatus === 'disconnected') { setBusy(true); // eslint-disable-next-line default-case switch (currentStatus) { - case ConnectionStatusKind.disconnected: + case 'disconnected': await context.startConnecting(); context.setConnectedSince(DateTime.now()); break; - case ConnectionStatusKind.connected: + case 'connected': await context.startDisconnecting(); context.setConnectedSince(undefined); break; @@ -43,40 +41,22 @@ export const App: FCWithChildren = () => { } }, [context.connectionStatus]); - useEffect(() => { - if (context.connectionStatus === ConnectionStatusKind.connected) setShowInfoModal(true); - }, [context.connectionStatus]); - - if (context.showHelp) return ; - - if ( - context.connectionStatus === ConnectionStatusKind.disconnected || - context.connectionStatus === ConnectionStatusKind.connecting - ) { - return ( - - ); + if (context.connectionStatus === 'disconnected' || context.connectionStatus === 'connecting') { + return ; } return ( - setShowInfoModal(false)} + context.setShowInfoModal(false)} busy={busy} onConnectClick={handleConnectClick} ipAddress="127.0.0.1" port={1080} gatewayPerformance={context.gatewayPerformance} connectedSince={context.connectedSince} - serviceProvider={context.serviceProvider} + serviceProvider={context.selectedProvider} stats={[ { label: 'in:', diff --git a/nym-connect/src/assets/help-step-one-legacy.png b/nym-connect/src/assets/help-step-one-legacy.png new file mode 100644 index 0000000000000000000000000000000000000000..5e91a29cffe020f951bfe5a752a4e4d0aa76b008 GIT binary patch literal 14403 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 QH2?qr07*qoM6N<$g8v&Kn*aa+ literal 14403 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ð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 M07*qoM6N<$f_|#uPXGV_ literal 35631 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ð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 { const { appVersion } = useClientContext(); return ( - - + + Version {appVersion} diff --git a/nym-connect/src/components/AppWindowFrame.tsx b/nym-connect/src/components/AppWindowFrame.tsx index 89a68f7f66..164ac64baf 100644 --- a/nym-connect/src/components/AppWindowFrame.tsx +++ b/nym-connect/src/components/AppWindowFrame.tsx @@ -1,20 +1,21 @@ import React from 'react'; import { Box } from '@mui/material'; import { CustomTitleBar } from './CustomTitleBar'; -import { AppVersion } from './AppVersion'; +import { useLocation, useParams } from 'react-router-dom'; -export const AppWindowFrame: FCWithChildren = ({ children }) => ( - - - {children} - - -); +export const AppWindowFrame: FCWithChildren = ({ children }) => { + const location = useLocation(); + + return ( + + + {children} + + ); +}; diff --git a/nym-connect/src/components/ConnectionButton.tsx b/nym-connect/src/components/ConnectionButton.tsx index 29fb90c1db..1dd72f78df 100644 --- a/nym-connect/src/components/ConnectionButton.tsx +++ b/nym-connect/src/components/ConnectionButton.tsx @@ -10,13 +10,13 @@ const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isErro } switch (status) { - case ConnectionStatusKind.disconnected: + case 'disconnected': if (hover) { return '#FFFF33'; } return '#FFE600'; - case ConnectionStatusKind.connecting: - case ConnectionStatusKind.disconnecting: + case 'connecting': + case 'disconnecting': return '#FFE600'; default: // connected @@ -29,11 +29,11 @@ const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isErro const getStatusText = (status: ConnectionStatusKind, hover: boolean): string => { switch (status) { - case ConnectionStatusKind.disconnected: + case 'disconnected': return 'Connect'; - case ConnectionStatusKind.connecting: + case 'connecting': return 'Connecting'; - case ConnectionStatusKind.disconnecting: + case 'disconnecting': return 'Connected'; default: // connected @@ -89,7 +89,7 @@ export const ConnectionButton: FCWithChildren<{ - {status === ConnectionStatusKind.connected && hover ? ( + {status === 'connected' && hover ? ( = ({ status }) => { + serviceProvider?: ServiceProvider; + gatewayError: boolean; +}> = ({ status, serviceProvider, gatewayError }) => { + if (gatewayError) { + return ( + : undefined}> + + + + Gateway has issues + + + + ); + } switch (status) { - case ConnectionStatusKind.connected: + case 'connected': return ( - - Connected to + : undefined}> + + + + Connected to Nym Mixnet + + + + ); + case 'disconnected': + return ( + + Connect to the mixnet ); - case ConnectionStatusKind.disconnecting: + case 'disconnecting': return ( - + Disconnecting... ); - case ConnectionStatusKind.connecting: + case 'connecting': return ( @@ -37,20 +70,7 @@ const ConnectionStatusContent: FCWithChildren<{ ); - case ConnectionStatusKind.disconnected: - return ( - - You are not protected - - ); + default: return null; } @@ -62,29 +82,18 @@ export const ConnectionStatus: FCWithChildren<{ connectedSince?: DateTime; serviceProvider?: ServiceProvider; }> = ({ status, serviceProvider, gatewayPerformance }) => { - const color = - status === ConnectionStatusKind.connected || status === ConnectionStatusKind.disconnecting - ? '#21D072' - : 'warning.main'; + const color = status === 'connected' || status === 'disconnecting' ? '#21D072' : 'white'; + console.log(gatewayPerformance); return ( <> - - {status === ConnectionStatusKind.connected && gatewayPerformance !== 'Good' ? ( - - Gateway has issues - - ) : ( - - )} + + - {serviceProvider ? ( - }> - - {serviceProvider && {serviceProvider.description}} - - - ) : null} ); }; diff --git a/nym-connect/src/components/CustomTitleBar.tsx b/nym-connect/src/components/CustomTitleBar.tsx index 41c71137b9..85a89fd540 100644 --- a/nym-connect/src/components/CustomTitleBar.tsx +++ b/nym-connect/src/components/CustomTitleBar.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import { ArrowBack, Close, HelpOutline, Minimize } from '@mui/icons-material'; -import { Box, IconButton } from '@mui/material'; +import { ArrowBack, Close, Menu, Minimize } from '@mui/icons-material'; +import { Box, IconButton, Typography } from '@mui/material'; import { NymWordmark } from '@nymproject/react/logo/NymWordmark'; import { appWindow } from '@tauri-apps/api/window'; -import { useClientContext } from 'src/context/main'; +import { useNavigate } from 'react-router-dom'; const customTitleBarStyles = { titlebar: { @@ -24,22 +24,34 @@ const CustomButton = ({ Icon, onClick }: { Icon: React.JSXElementConstructor ); -export const CustomTitleBar = () => { - const { showHelp, handleShowHelp } = useClientContext(); +const MenuIcon = () => { + const navigate = useNavigate(); + return navigate('/menu')} />; +}; + +const ArrowBackIcon = () => { + const navigate = useNavigate(); + return navigate(-1)} />; +}; + +const getTitleIcon = (path: string) => { + if (path !== '/') { + const title = path.split('/').slice(-1); + return ( + + {title} + + ); + } + return ; +}; + +export const CustomTitleBar = ({ path = '/' }: { path?: string }) => { return ( {/* set width to keep logo centered */} - - { - handleShowHelp(); - }} - /> - - - - + {path === '/' ? : } + {getTitleIcon(path)} appWindow.minimize()} /> appWindow.close()} /> diff --git a/nym-connect/src/components/ExperimentalWarning.tsx b/nym-connect/src/components/ExperimentalWarning.tsx new file mode 100644 index 0000000000..122f741d0b --- /dev/null +++ b/nym-connect/src/components/ExperimentalWarning.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Box, Typography } from '@mui/material'; + +export const ExperimentalWarning = () => ( + + + This is experimental software. + + + Do not rely on it for strong anonymity (yet). + + +); diff --git a/nym-connect/src/components/Growth/TestAndEarnButtonArea.tsx b/nym-connect/src/components/Growth/TestAndEarnButtonArea.tsx index 92c88ec321..ffca05043b 100644 --- a/nym-connect/src/components/Growth/TestAndEarnButtonArea.tsx +++ b/nym-connect/src/components/Growth/TestAndEarnButtonArea.tsx @@ -25,7 +25,7 @@ export const Wrapper: FCWithChildren<{ disabled: boolean }> = ({ disabled, child export const TestAndEarnButtonArea: FCWithChildren = () => { const clientContext = useClientContext(); const context = useTestAndEarnContext(); - const disabled = clientContext.connectionStatus !== ConnectionStatusKind.connected; + const disabled = clientContext.connectionStatus !== 'connected'; const pinger = React.useRef(); const doPing = async () => { diff --git a/nym-connect/src/components/Growth/TestAndEarnPopup.tsx b/nym-connect/src/components/Growth/TestAndEarnPopup.tsx index dc1148c1e5..2535f2ef6f 100644 --- a/nym-connect/src/components/Growth/TestAndEarnPopup.tsx +++ b/nym-connect/src/components/Growth/TestAndEarnPopup.tsx @@ -28,7 +28,7 @@ export const TestAndEarnPopupContent: FCWithChildren<{ ); } - if (!connectionStatus || connectionStatus === ConnectionStatusKind.disconnected) { + if (!connectionStatus || connectionStatus === 'disconnected') { return ( @@ -36,7 +36,7 @@ export const TestAndEarnPopupContent: FCWithChildren<{ ); } - if (connectionStatus === ConnectionStatusKind.connecting || connectionStatus === ConnectionStatusKind.disconnecting) { + if (connectionStatus === 'connecting' || connectionStatus === 'disconnecting') { return ( @@ -77,7 +77,7 @@ export const TestAndEarnPopup: FCWithChildren = () => { const context = useTestAndEarnContext(); React.useEffect(() => { - if (clientContext.connectionStatus === ConnectionStatusKind.connected) { + if (clientContext.connectionStatus === 'connected') { context.refresh(); } }, [clientContext.connectionStatus]); @@ -94,7 +94,7 @@ export const TestAndEarnPopup: FCWithChildren = () => { return () => clearInterval(interval); }, []); - if (!context.loadedOnce && clientContext.connectionStatus === ConnectionStatusKind.connected) { + if (!context.loadedOnce && clientContext.connectionStatus === 'connected') { const message = 'Waiting for data to be transferred over the mixnet...'; return ( diff --git a/nym-connect/src/components/Growth/context/TestAndEarnContext.tsx b/nym-connect/src/components/Growth/context/TestAndEarnContext.tsx index a28fd221e2..5c4776a4a7 100644 --- a/nym-connect/src/components/Growth/context/TestAndEarnContext.tsx +++ b/nym-connect/src/components/Growth/context/TestAndEarnContext.tsx @@ -151,7 +151,7 @@ export const TestAndEarnContextProvider: FCWithChildren = ({ children }) => { }, []); React.useEffect(() => { - if (registration && clientContext.connectionStatus === ConnectionStatusKind.connected) { + if (registration && clientContext.connectionStatus === 'connected') { setTimeout(() => { loadDraws().catch(console.error); }, 1000 * 3); diff --git a/nym-connect/src/components/HelpPage.tsx b/nym-connect/src/components/HelpPage.tsx index 788f7264d5..5cc7815117 100644 --- a/nym-connect/src/components/HelpPage.tsx +++ b/nym-connect/src/components/HelpPage.tsx @@ -6,24 +6,26 @@ import { StepIndicator } from './HelpPageStepIndicator'; export const HelpPage = ({ step, + totalSteps, description, img, onNext, onPrev, }: { step: number; + totalSteps: number; description: string; img: any; onNext?: () => void; onPrev?: () => void; }) => ( - + - How to connect guide {step}/4 + How to connect guide {step}/{totalSteps} - + {description} diff --git a/nym-connect/src/components/HelpPageImage.tsx b/nym-connect/src/components/HelpPageImage.tsx index 27a8dcdca3..8e9920ca4d 100644 --- a/nym-connect/src/components/HelpPageImage.tsx +++ b/nym-connect/src/components/HelpPageImage.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { Box } from '@mui/material'; -export const HelpImage = ({ img, imageDescription }: { img: any; imageDescription: string }) => ( - {imageDescription} +export const HelpImage = ({ img, imageDescription }: { img: string; imageDescription: string }) => ( + {imageDescription} ); diff --git a/nym-connect/src/components/HelpPageStepIndicator.tsx b/nym-connect/src/components/HelpPageStepIndicator.tsx index b5dff42b34..02d0b3338e 100644 --- a/nym-connect/src/components/HelpPageStepIndicator.tsx +++ b/nym-connect/src/components/HelpPageStepIndicator.tsx @@ -1,15 +1,14 @@ -import { Box } from '@mui/material'; import React from 'react'; +import { Box } from '@mui/material'; const Step = ({ highlight }: { highlight: boolean }) => ( - + ); export const StepIndicator = ({ step }: { step: number }) => ( - + = 2} /> = 3} /> - = 4} /> ); diff --git a/nym-connect/src/components/InfoModal.tsx b/nym-connect/src/components/InfoModal.tsx index ed628de7eb..8b1157689e 100644 --- a/nym-connect/src/components/InfoModal.tsx +++ b/nym-connect/src/components/InfoModal.tsx @@ -18,7 +18,7 @@ const styles = { const ModalTitle = ({ title, withCloseIcon }: { title: string; withCloseIcon: boolean }) => ( - + {title} @@ -27,7 +27,7 @@ const ModalTitle = ({ title, withCloseIcon }: { title: string; withCloseIcon: bo const ModalBody = ({ description, children }: { description: string; children?: React.ReactElement }) => ( {children} - + {description} diff --git a/nym-connect/src/components/IpAddressAndPortModal.tsx b/nym-connect/src/components/IpAddressAndPortModal.tsx index 8ed6d51e20..8afe0acd1b 100644 --- a/nym-connect/src/components/IpAddressAndPortModal.tsx +++ b/nym-connect/src/components/IpAddressAndPortModal.tsx @@ -3,6 +3,9 @@ import { Box, Button, Typography } from '@mui/material'; import { InfoModal } from './InfoModal'; import { CopyToClipboard } from './CopyToClipboard'; +const FONT_SIZE = '12px'; +const FONT_COLOR = 'grey.400'; + export const IpAddressAndPortModal = ({ show, ipAddress, @@ -16,12 +19,15 @@ export const IpAddressAndPortModal = ({ }) => ( Done} + title="You are half way there" + description="Check NymConnect menu for supported apps" + onClose={onClose} > - + + Paste below values in the proxy settings of your app + + Socks5 address @@ -29,7 +35,7 @@ export const IpAddressAndPortModal = ({ - + Port diff --git a/nym-connect/src/components/PowerButton.tsx b/nym-connect/src/components/PowerButton.tsx new file mode 100644 index 0000000000..426028a767 --- /dev/null +++ b/nym-connect/src/components/PowerButton.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { ConnectionStatusKind } from 'src/types'; + +const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isError: boolean): string => { + if (isError && hover) { + return '#21D072'; + } + if (isError) { + return '#40475C'; + } + + switch (status) { + case 'disconnected': + if (hover) { + return '#FFF'; + } + return '#BBB'; + case 'connecting': + return '#FFF'; + case 'disconnecting': + return '#FFF'; + default: + // connected + if (hover) { + return '#E43E3E'; + } + return '#21D072'; + } +}; + +export const PowerButton: FCWithChildren<{ + onClick?: (status: ConnectionStatusKind) => void; + isError?: boolean; + disabled?: boolean; + status: ConnectionStatusKind; + busy?: boolean; +}> = ({ onClick, disabled, status, isError }) => { + const [hover, setHover] = React.useState(false); + + const handleClick = () => { + if (disabled === true) { + return; + } + if (onClick) { + onClick(status); + } + }; + + const statusFillColor = getStatusFillColor(status, hover, Boolean(isError)); + + return ( + !disabled && setHover(true)} + onMouseLeave={() => !disabled && setHover(false)} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/nym-connect/src/components/ServiceProviderInfo.tsx b/nym-connect/src/components/TooltipInfo.tsx similarity index 60% rename from nym-connect/src/components/ServiceProviderInfo.tsx rename to nym-connect/src/components/TooltipInfo.tsx index a6289b5c41..2d76c6859e 100644 --- a/nym-connect/src/components/ServiceProviderInfo.tsx +++ b/nym-connect/src/components/TooltipInfo.tsx @@ -7,14 +7,23 @@ export const ServiceProviderInfo = ({ serviceProvider }: { serviceProvider: Serv Connection info - {serviceProvider.description} Gateway {serviceProvider.gateway} - Provider {serviceProvider.address.slice(0, 35)}... + Service provider {serviceProvider.address.slice(0, 35)}... ); + +export const GatwayWarningInfo = () => ( + + + Connection issue + + + Try disconnecting and connecting again + +); diff --git a/nym-connect/src/context/main.tsx b/nym-connect/src/context/main.tsx index bba01764e7..3ea8a3cad2 100644 --- a/nym-connect/src/context/main.tsx +++ b/nym-connect/src/context/main.tsx @@ -21,19 +21,17 @@ export type TClientContext = { connectionStatus: ConnectionStatusKind; connectionStats?: ConnectionStatsItem[]; connectedSince?: DateTime; - services?: Services; - serviceProvider?: ServiceProvider; - showHelp: boolean; error?: Error; gatewayPerformance: GatewayPerformance; + selectedProvider?: ServiceProvider; + showInfoModal: boolean; setMode: (mode: ModeType) => void; clearError: () => void; - handleShowHelp: () => void; setConnectionStatus: (connectionStatus: ConnectionStatusKind) => void; setConnectionStats: (connectionStats: ConnectionStatsItem[] | undefined) => void; setConnectedSince: (connectedSince: DateTime | undefined) => void; - setServiceProvider: (serviceProvider?: ServiceProvider) => void; - + setShowInfoModal: (show: boolean) => void; + setRandomSerivceProvider: () => void; startConnecting: () => Promise; startDisconnecting: () => Promise; }; @@ -42,28 +40,40 @@ export const ClientContext = createContext({} as TClientContext); export const ClientContextProvider: FCWithChildren = ({ children }) => { const [mode, setMode] = useState('dark'); - const [connectionStatus, setConnectionStatus] = useState(ConnectionStatusKind.disconnected); + const [connectionStatus, setConnectionStatus] = useState(ConnectionStatusKind.connected); const [connectionStats, setConnectionStats] = useState(); const [connectedSince, setConnectedSince] = useState(); - const [services, setServices] = React.useState([]); - const [serviceProvider, setRawServiceProvider] = React.useState(); - const [showHelp, setShowHelp] = useState(false); + const [selectedProvider, setSelectedProvider] = React.useState(); + const [serviceProviders, setServiceProviders] = React.useState(); const [error, setError] = useState(); const [appVersion, setAppVersion] = useState(); const [gatewayPerformance, setGatewayPerformance] = useState('Good'); + const [showInfoModal, setShowInfoModal] = useState(false); const getAppVersion = async () => { const version = await getVersion(); - setAppVersion(version); + return version; }; const timerId = useRef(); + const flattenProviders = (services: Services) => { + return services.reduce((a: ServiceProvider[], b) => { + return [...a, ...b.items]; + }, []); + }; + + const initialiseApp = async () => { + const services = await invoke('get_services'); + const allServiceProviders = flattenProviders(services as Services); + const AppVersion = await getAppVersion(); + + setAppVersion(AppVersion); + setServiceProviders(allServiceProviders); + }; + useEffect(() => { - invoke('get_services').then((result) => { - setServices(result as Services); - }); - getAppVersion(); + initialiseApp(); }, []); useEffect(() => { @@ -129,12 +139,18 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { const startDisconnecting = useCallback(async () => { try { await invoke('start_disconnecting'); - setGatewayPerformance('Good'); } catch (e) { console.log(e); } }, []); + const setServiceProvider = async (newServiceProvider?: ServiceProvider) => { + if (newServiceProvider) { + await invoke('set_gateway', { gateway: newServiceProvider.gateway }); + await invoke('set_service_provider', { serviceProvider: newServiceProvider.address }); + } + }; + const setSpInStorage = async (sp: ServiceProvider) => { await forage.setItem({ key: 'nym-connect-sp', @@ -142,51 +158,36 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { } as any)(); }; - const setServiceProvider = useCallback(async (newServiceProvider?: ServiceProvider) => { - await invoke('set_gateway', { gateway: newServiceProvider?.gateway }); - await invoke('set_service_provider', { serviceProvider: newServiceProvider?.address }); - if (newServiceProvider) { - await setSpInStorage(newServiceProvider); - } - setRawServiceProvider(newServiceProvider); - }, []); + const removeSpFromStorage = async () => { + await forage.removeItem({ + key: 'nym-connect-sp', + })(); + }; - const getSpFromStorage = async () => { + const getSpFromStorage = async (): Promise => { try { const spFromStorage = await forage.getItem({ key: 'nym-connect-sp' })(); - if (spFromStorage) { - setRawServiceProvider(spFromStorage); - setServiceProvider(spFromStorage); - } + return spFromStorage; } catch (e) { console.warn(e); } }; - const handleShowHelp = () => setShowHelp((show) => !show); + const getRandomSPFromList = (serviceProviders: ServiceProvider[]) => { + const randomSelection = serviceProviders[Math.floor(Math.random() * serviceProviders.length)]; + return randomSelection; + }; + + const setRandomSerivceProvider = async () => { + if (serviceProviders) { + const randomServiceProvider = getRandomSPFromList(serviceProviders); + await setServiceProvider(randomServiceProvider); + setSelectedProvider(randomServiceProvider); + } + }; const clearError = () => setError(undefined); - useEffect(() => { - const validityCheck = async () => { - if (services.length > 0 && serviceProvider) { - const isValid = services.some(({ items }) => items.some(({ id }) => id === serviceProvider.id)); - if (!isValid) { - console.warn('invalid SP, cleaning local storage'); - await forage.removeItem({ - key: 'nym-connect-sp', - })(); - setRawServiceProvider(undefined); - } - } - }; - validityCheck(); - }, [services, serviceProvider]); - - useEffect(() => { - getSpFromStorage(); - }, []); - const contextValue = useMemo( () => ({ mode, @@ -197,31 +198,28 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => { connectionStatus, setConnectionStatus, connectionStats, + showInfoModal, setConnectionStats, + selectedProvider, connectedSince, setConnectedSince, + setRandomSerivceProvider, startConnecting, startDisconnecting, - services, - serviceProvider, - setServiceProvider, - showHelp, - handleShowHelp, gatewayPerformance, + setShowInfoModal, }), [ - appVersion, mode, appVersion, error, + showInfoModal, connectedSince, - showHelp, connectionStatus, connectionStats, connectedSince, - services, - serviceProvider, gatewayPerformance, + selectedProvider, ], ); diff --git a/nym-connect/src/context/mocks/main.tsx b/nym-connect/src/context/mocks/main.tsx index 9b4341cc23..ea86bb365d 100644 --- a/nym-connect/src/context/mocks/main.tsx +++ b/nym-connect/src/context/mocks/main.tsx @@ -6,19 +6,18 @@ const mockValues: TClientContext = { appVersion: 'v1.x.x', mode: 'dark', connectionStatus: ConnectionStatusKind.disconnected, - services: [], - showHelp: false, - serviceProvider: { id: '1', description: 'Keybase service provider', gateway: 'abc123', address: '123abc' }, + selectedProvider: { id: '1', description: 'Keybase service provider', gateway: 'abc123', address: '123abc' }, gatewayPerformance: 'Good', + showInfoModal: false, + setShowInfoModal: () => {}, setMode: () => {}, clearError: () => {}, - handleShowHelp: () => {}, setConnectedSince: () => {}, setConnectionStats: () => {}, setConnectionStatus: () => {}, - setServiceProvider: () => {}, startConnecting: async () => {}, startDisconnecting: async () => {}, + setRandomSerivceProvider: () => {}, }; export const MockProvider: FCWithChildren<{ diff --git a/nym-connect/src/index.tsx b/nym-connect/src/index.tsx index 8f682fd98b..7041b86787 100644 --- a/nym-connect/src/index.tsx +++ b/nym-connect/src/index.tsx @@ -7,6 +7,9 @@ import { NymMixnetTheme } from './theme'; import { App } from './App'; import { AppWindowFrame } from './components/AppWindowFrame'; import { TestAndEarnContextProvider } from './components/Growth/context/TestAndEarnContext'; +import { BrowserRouter as Router } from 'react-router-dom'; +import { AppRoutes } from './routes'; +import { GlobalStyles } from '@mui/material'; const elem = document.getElementById('root'); @@ -14,15 +17,18 @@ if (elem) { const root = createRoot(elem); root.render( - - - - - - - - - + + + + + + + + + + + + , ); } diff --git a/nym-connect/src/layouts/ConnectedLayout.tsx b/nym-connect/src/layouts/ConnectedLayout.tsx deleted file mode 100644 index da4c757208..0000000000 --- a/nym-connect/src/layouts/ConnectedLayout.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import { Box, Divider } from '@mui/material'; -import { DateTime } from 'luxon'; -import { IpAddressAndPortModal } from 'src/components/IpAddressAndPortModal'; -import { ConnectionTimer } from 'src/components/ConntectionTimer'; -import { ConnectionStatus } from '../components/ConnectionStatus'; -import { ConnectionStatusKind, GatewayPerformance } from '../types'; -import { ConnectionStatsItem } from '../components/ConnectionStats'; -import { ConnectionButton } from '../components/ConnectionButton'; -import { IpAddressAndPort } from '../components/IpAddressAndPort'; -import { ServiceProvider } from '../types/directory'; -import { TestAndEarnButtonArea } from '../components/Growth/TestAndEarnButtonArea'; - -export const ConnectedLayout: FCWithChildren<{ - status: ConnectionStatusKind; - gatewayPerformance: GatewayPerformance; - stats: ConnectionStatsItem[]; - ipAddress: string; - port: number; - connectedSince?: DateTime; - busy?: boolean; - showInfoModal: boolean; - isError?: boolean; - handleCloseInfoModal: () => void; - onConnectClick?: (status: ConnectionStatusKind) => void; - serviceProvider?: ServiceProvider; -}> = ({ - status, - gatewayPerformance, - showInfoModal, - handleCloseInfoModal, - ipAddress, - port, - connectedSince, - busy, - isError, - serviceProvider, - onConnectClick, -}) => ( - <> - - - - - - - - - {/* */} - - - -); diff --git a/nym-connect/src/layouts/ConnectionLayout.tsx b/nym-connect/src/layouts/ConnectionLayout.tsx new file mode 100644 index 0000000000..d37c7ec888 --- /dev/null +++ b/nym-connect/src/layouts/ConnectionLayout.tsx @@ -0,0 +1,30 @@ +import { Box } from '@mui/material'; +import React from 'react'; + +const layout = { + display: 'grid', + gridTemplateColumns: '1fr', + gridTemplateRows: '80px 180px 1fr', + gridColumnGap: '0px', + gridRowGap: '4px', + overflow: 'hidden', + height: '100%', +}; + +export const ConnectionLayout = ({ + TopContent, + ConnectButton, + BottomContent, +}: { + TopContent: React.ReactNode; + ConnectButton: React.ReactNode; + BottomContent: React.ReactNode; +}) => ( + + {TopContent} + + {ConnectButton} + + {BottomContent} + +); diff --git a/nym-connect/src/layouts/DefaultLayout.tsx b/nym-connect/src/layouts/DefaultLayout.tsx deleted file mode 100644 index 29858afe7f..0000000000 --- a/nym-connect/src/layouts/DefaultLayout.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { Box, Typography } from '@mui/material'; -import { ConnectionStatus } from 'src/components/ConnectionStatus'; -import { ConnectionTimer } from 'src/components/ConntectionTimer'; -import { InfoModal } from 'src/components/InfoModal'; -import { Error } from 'src/types/error'; -import { ConnectionButton } from '../components/ConnectionButton'; -import { ServiceSelector } from '../components/ServiceSelector'; -import { useClientContext } from '../context/main'; -import { ConnectionStatusKind } from '../types'; -import { Services } from '../types/directory'; -import { TestAndEarnButtonArea } from '../components/Growth/TestAndEarnButtonArea'; -import { AppVersion } from '../components/AppVersion'; - -export const DefaultLayout: FCWithChildren<{ - error?: Error; - status: ConnectionStatusKind; - services?: Services; - busy?: boolean; - isError?: boolean; - clearError: () => void; - onConnectClick?: (status: ConnectionStatusKind) => void; -}> = ({ status, error, services, busy, isError, onConnectClick, clearError }) => { - const context = useClientContext(); - - return ( - - {error && } - - - - Connect to the Nym
mixnet for privacy. -
- - This is experimental software. Do not rely on it for strong anonymity (yet). - -
- - - -
- ); -}; diff --git a/nym-connect/src/layouts/HelpGuideLayout.tsx b/nym-connect/src/layouts/HelpGuideLayout.tsx deleted file mode 100644 index d56fd6b0ae..0000000000 --- a/nym-connect/src/layouts/HelpGuideLayout.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useState } from 'react'; -import { HelpPage } from 'src/components/HelpPage'; -import { Button, Link, Stack } from '@mui/material'; -import Image1 from '../assets/help-step-one.png'; -import Image2 from '../assets/help-step-two.png'; -import Image3 from '../assets/help-step-three.png'; -import Image4 from '../assets/help-step-four.png'; - -export const HelpGuideLayout = () => { - const [step, setStep] = useState(0); - - if (step === 1) - return ( - setStep(2)} - /> - ); - - if (step === 2) - return ( - setStep(1)} - onNext={() => setStep(3)} - /> - ); - - if (step === 3) - return ( - setStep(2)} - onNext={() => setStep(4)} - /> - ); - - if (step === 4) - return ( - setStep(3)} - /> - ); - - return ( - - - - - ); -}; diff --git a/nym-connect/src/pages/connection/Connected.tsx b/nym-connect/src/pages/connection/Connected.tsx new file mode 100644 index 0000000000..63da0d6fb1 --- /dev/null +++ b/nym-connect/src/pages/connection/Connected.tsx @@ -0,0 +1,75 @@ +import React, { useState } from 'react'; +import { Box, Stack } from '@mui/material'; +import { DateTime } from 'luxon'; +import { IpAddressAndPortModal } from 'src/components/IpAddressAndPortModal'; +import { ConnectionTimer } from 'src/components/ConntectionTimer'; +import { ConnectionStatus } from 'src/components/ConnectionStatus'; +import { ConnectionStatusKind, GatewayPerformance } from 'src/types'; +import { ConnectionStatsItem } from 'src/components/ConnectionStats'; +import { IpAddressAndPort } from 'src/components/IpAddressAndPort'; +import { ServiceProvider } from 'src/types/directory'; +import { ExperimentalWarning } from 'src/components/ExperimentalWarning'; +import { ConnectionLayout } from 'src/layouts/ConnectionLayout'; +import { PowerButton } from 'src/components/PowerButton'; + +export const Connected: FCWithChildren<{ + status: ConnectionStatusKind; + showInfoModal: boolean; + gatewayPerformance: GatewayPerformance; + stats: ConnectionStatsItem[]; + ipAddress: string; + port: number; + connectedSince?: DateTime; + busy?: boolean; + isError?: boolean; + serviceProvider?: ServiceProvider; + onConnectClick: (status: ConnectionStatusKind) => void; + closeInfoModal: () => void; +}> = ({ + status, + showInfoModal, + gatewayPerformance, + ipAddress, + port, + connectedSince, + busy, + isError, + serviceProvider, + onConnectClick, + closeInfoModal, +}) => { + return ( + <> + + + + +
+ } + ConnectButton={ + + } + BottomContent={ + + + + + + + } + /> + + ); +}; diff --git a/nym-connect/src/pages/connection/Disconnected.tsx b/nym-connect/src/pages/connection/Disconnected.tsx new file mode 100644 index 0000000000..f92d70ad55 --- /dev/null +++ b/nym-connect/src/pages/connection/Disconnected.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Stack, Typography } from '@mui/material'; +import { ConnectionStatus } from 'src/components/ConnectionStatus'; +import { ConnectionTimer } from 'src/components/ConntectionTimer'; +import { useClientContext } from 'src/context/main'; +import { InfoModal } from 'src/components/InfoModal'; +import { Error } from 'src/types/error'; +import { ExperimentalWarning } from 'src/components/ExperimentalWarning'; +import { ServiceProvider, Services } from 'src/types/directory'; +import { ConnectionStatusKind } from 'src/types'; +import { ConnectionButton } from 'src/components/ConnectionButton'; +import { PowerButton } from 'src/components/PowerButton'; +import { Box } from '@mui/system'; +import { ConnectionLayout } from 'src/layouts/ConnectionLayout'; + +export const Disconnected: FCWithChildren<{ + error?: Error; + status: ConnectionStatusKind; + services?: Services; + busy?: boolean; + isError?: boolean; + serviceProvider?: ServiceProvider; + clearError: () => void; + onConnectClick: (status: ConnectionStatusKind) => void; +}> = ({ status, error, onConnectClick, clearError, serviceProvider }) => { + return ( + <> + {error && } + + + +
+ } + ConnectButton={} + BottomContent={ + + + You are not protected + + + + } + /> + + ); +}; diff --git a/nym-connect/src/pages/connection/index.tsx b/nym-connect/src/pages/connection/index.tsx new file mode 100644 index 0000000000..9489137367 --- /dev/null +++ b/nym-connect/src/pages/connection/index.tsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { forage } from '@tauri-apps/tauri-forage'; +import { DateTime } from 'luxon'; +import { useClientContext } from 'src/context/main'; +import { useTauriEvents } from 'src/utils'; +import { Connected } from './Connected'; +import { Disconnected } from './Disconnected'; + +export const ConnectionPage = () => { + const context = useClientContext(); + const [busy, setBusy] = React.useState(); + + useTauriEvents('help://clear-storage', (_event) => { + console.log('About to clear local storage...'); + // clear local storage + try { + forage.clear()(); + console.log('Local storage cleared'); + } catch (e) { + console.error('Failed to clear local storage', e); + } + }); + + const handleConnectClick = async () => { + const currentStatus = context.connectionStatus; + if (currentStatus === 'connected' || currentStatus === 'disconnected') { + setBusy(true); + // eslint-disable-next-line default-case + switch (currentStatus) { + case 'disconnected': + await context.setRandomSerivceProvider(); + await context.startConnecting(); + context.setConnectedSince(DateTime.now()); + context.setShowInfoModal(true); + break; + case 'connected': + await context.startDisconnecting(); + context.setConnectedSince(undefined); + break; + } + setBusy(false); + } + }; + + const closeInfoModal = () => context.setShowInfoModal(false); + + if (context.connectionStatus === 'connected') + return ( + + ); + + return ( + + ); +}; diff --git a/nym-connect/src/pages/menu/Apps.tsx b/nym-connect/src/pages/menu/Apps.tsx new file mode 100644 index 0000000000..59d2823b69 --- /dev/null +++ b/nym-connect/src/pages/menu/Apps.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Divider, Typography } from '@mui/material'; +import { Box } from '@mui/system'; + +const appsSchema = { + messagingApps: ['Telegram', 'Keybase'], + wallets: ['Blockstream', 'Electum'], +}; + +export const CompatibleApps = () => ( + + + Supported apps + + + Messaging apps + + + + + + {appsSchema.messagingApps.map((app, i) => ( + + {app} + + ))} + + + Wallets + + + + + + {appsSchema.wallets.map((wallet, i) => ( + + {wallet} + + ))} + + +); diff --git a/nym-connect/src/pages/menu/Guide.tsx b/nym-connect/src/pages/menu/Guide.tsx new file mode 100644 index 0000000000..2323d68a82 --- /dev/null +++ b/nym-connect/src/pages/menu/Guide.tsx @@ -0,0 +1,47 @@ +import React, { useState } from 'react'; +import { HelpPage } from 'src/components/HelpPage'; +import Image1 from '../../assets/help-step-one.png'; +import Image2 from '../../assets/help-step-two.png'; +import Image4 from '../../assets/help-step-four.png'; + +export const HelpGuide = () => { + const [step, setStep] = useState(1); + const TOTAL_STEPS = 3; + + if (step === 1) + return ( + setStep(2)} + /> + ); + + if (step === 2) + return ( + setStep(1)} + onNext={() => setStep(3)} + /> + ); + + if (step === 3) + return ( + setStep(2)} + /> + ); + + return null; +}; diff --git a/nym-connect/src/pages/menu/index.tsx b/nym-connect/src/pages/menu/index.tsx new file mode 100644 index 0000000000..156ab061e4 --- /dev/null +++ b/nym-connect/src/pages/menu/index.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Apps, HelpOutline } from '@mui/icons-material'; +import { Stack, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; +import { Link as RouterLink } from 'react-router-dom'; +import { AppVersion } from 'src/components/AppVersion'; + +const menuSchema = [ + { title: 'Supported apps', icon: Apps, path: 'apps' }, + { title: 'How to connect guide', icon: HelpOutline, path: 'guide' }, +]; + +export const Menu = () => { + return ( + + + {menuSchema.map((item) => ( + + + + {}{' '} + {item.title} + + + + ))} + + + + ); +}; diff --git a/nym-connect/src/routes/index.tsx b/nym-connect/src/routes/index.tsx new file mode 100644 index 0000000000..37bb876d91 --- /dev/null +++ b/nym-connect/src/routes/index.tsx @@ -0,0 +1,18 @@ +import { Routes, Route } from 'react-router-dom'; +import { ConnectionPage } from 'src/pages/connection'; +import { Menu } from 'src/pages/menu'; +import { CompatibleApps } from 'src/pages/menu/Apps'; +import { HelpGuide } from 'src/pages/menu/Guide'; + +export const AppRoutes = () => { + return ( + + } /> + + } /> + } /> + } /> + + + ); +}; diff --git a/nym-connect/src/stories/AppFlow.stories.tsx b/nym-connect/src/stories/AppFlow.stories.tsx index f0c8428058..011a269610 100644 --- a/nym-connect/src/stories/AppFlow.stories.tsx +++ b/nym-connect/src/stories/AppFlow.stories.tsx @@ -4,10 +4,10 @@ import { Box } from '@mui/material'; import { DateTime } from 'luxon'; import { AppWindowFrame } from '../components/AppWindowFrame'; import { useClientContext } from '../context/main'; -import { ConnectionStatusKind } from '../types'; -import { DefaultLayout } from '../layouts/DefaultLayout'; -import { ConnectedLayout } from '../layouts/ConnectedLayout'; import { Services } from '../types/directory'; +import { Disconnected } from 'src/pages/connection/Disconnected'; +import { Connected } from 'src/pages/connection/Connected'; +import { ConnectionStatusKind } from 'src/types'; export default { title: 'App/Flow', @@ -36,15 +36,15 @@ export const Mock: ComponentStory = () => { ]; const handleConnectClick = React.useCallback(() => { const oldStatus = context.connectionStatus; - if (oldStatus === ConnectionStatusKind.connected || oldStatus === ConnectionStatusKind.disconnected) { + if (oldStatus === 'connected' || oldStatus === 'disconnected') { setBusy(true); // eslint-disable-next-line default-case switch (oldStatus) { - case ConnectionStatusKind.disconnected: + case 'disconnected': context.setConnectionStatus(ConnectionStatusKind.connecting); break; - case ConnectionStatusKind.connected: + case 'connected': context.setConnectionStatus(ConnectionStatusKind.disconnecting); break; } @@ -52,11 +52,11 @@ export const Mock: ComponentStory = () => { setTimeout(() => { // eslint-disable-next-line default-case switch (oldStatus) { - case ConnectionStatusKind.disconnected: + case 'disconnected': context.setConnectedSince(DateTime.now()); context.setConnectionStatus(ConnectionStatusKind.connected); break; - case ConnectionStatusKind.connected: + case 'connected': context.setConnectionStatus(ConnectionStatusKind.disconnected); break; } @@ -72,7 +72,7 @@ export const Mock: ComponentStory = () => { return ( - = () => { return ( - undefined} + closeInfoModal={() => undefined} status={context.connectionStatus} busy={busy} onConnectClick={handleConnectClick} diff --git a/nym-connect/src/stories/ConnectedLayout.stories.tsx b/nym-connect/src/stories/ConnectedLayout.stories.tsx index 216e9c38db..b572d58490 100644 --- a/nym-connect/src/stories/ConnectedLayout.stories.tsx +++ b/nym-connect/src/stories/ConnectedLayout.stories.tsx @@ -2,23 +2,28 @@ import React from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; import { Box } from '@mui/material'; import { DateTime } from 'luxon'; -import { ConnectedLayout } from '../layouts/ConnectedLayout'; -import { ConnectionStatusKind } from '../types'; +import { Connected } from 'src/pages/connection/Connected'; +import { ConnectionStatusKind } from 'src/types'; + +const onClick = () => undefined; export default { title: 'Layouts/ConnectedLayout', - component: ConnectedLayout, -} as ComponentMeta; + component: Connected, +} as ComponentMeta; -export const Default: ComponentStory = () => ( +export const Default: ComponentStory = () => ( - undefined} + showInfoModal={false} + closeInfoModal={() => { + return undefined; + }} status={ConnectionStatusKind.connected} connectedSince={DateTime.now()} ipAddress="127.0.0.1" + serviceProvider={{ id: 'service 1', description: 'good services', address: 'abc123', gateway: '8910xyz' }} port={1080} stats={[ { @@ -32,6 +37,7 @@ export const Default: ComponentStory = () => ( rateBytesPerSecond: 1024 * 1024 + 10, }, ]} + onConnectClick={onClick} /> ); diff --git a/nym-connect/src/stories/ConnectionButton.stories.tsx b/nym-connect/src/stories/ConnectionButton.stories.tsx index efce95ace4..d1aa35b0b5 100644 --- a/nym-connect/src/stories/ConnectionButton.stories.tsx +++ b/nym-connect/src/stories/ConnectionButton.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; import { ConnectionButton } from '../components/ConnectionButton'; -import { ConnectionStatusKind } from '../types'; +import { ConnectionStatusKind } from 'src/types'; export default { title: 'Components/ConnectionButton', diff --git a/nym-connect/src/stories/DefaultLayout.stories.tsx b/nym-connect/src/stories/DefaultLayout.stories.tsx index ba311a410b..e7362ae685 100644 --- a/nym-connect/src/stories/DefaultLayout.stories.tsx +++ b/nym-connect/src/stories/DefaultLayout.stories.tsx @@ -1,23 +1,30 @@ import React from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; import { Box } from '@mui/material'; -import { DefaultLayout } from '../layouts/DefaultLayout'; import { ConnectionStatusKind } from '../types'; +import { Disconnected } from 'src/pages/connection/Disconnected'; export default { title: 'Layouts/DefaultLayout', - component: DefaultLayout, -} as ComponentMeta; + component: Disconnected, +} as ComponentMeta; -export const Default: ComponentStory = () => ( +const onClick = () => undefined; + +export const Default: ComponentStory = () => ( - {}} error={undefined} /> + {}} + error={undefined} + onConnectClick={onClick} + /> ); -export const WithServices: ComponentStory = () => ( +export const WithServices: ComponentStory = () => ( - = () => ( ]} clearError={() => {}} error={undefined} + onConnectClick={onClick} /> ); diff --git a/nym-connect/src/stories/PowerButton.stories.tsx b/nym-connect/src/stories/PowerButton.stories.tsx new file mode 100644 index 0000000000..97681cc974 --- /dev/null +++ b/nym-connect/src/stories/PowerButton.stories.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { PowerButton } from 'src/components/PowerButton'; +import { ConnectionStatusKind } from 'src/types'; + +export default { + title: 'Components/PowerButton', + component: PowerButton, +} as ComponentMeta; + +export const Disconnected: ComponentStory = () => ( + +); + +export const Connecting: ComponentStory = () => ( + +); + +export const Connected: ComponentStory = () => ( + +); + +export const Disconnecting: ComponentStory = () => ( + +); + +export const Disabled: ComponentStory = () => ( + +); diff --git a/nym-connect/src/theme/theme.tsx b/nym-connect/src/theme/theme.tsx index abda87ef72..18678fce98 100644 --- a/nym-connect/src/theme/theme.tsx +++ b/nym-connect/src/theme/theme.tsx @@ -20,7 +20,7 @@ import { */ const nymPalette: NymPalette = { /** emphasises important elements */ - highlight: '#FB6E4E', + highlight: '#21D072', success: '#21D073', info: '#60D7EF', warning: '#FFE600', diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 02bf5970f0..9a67556428 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -2710,6 +2710,7 @@ dependencies = [ "cw4", "schemars", "serde", + "thiserror", ] [[package]] diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 9814c3e338..bc48c72adb 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-network-requester" -version = "1.1.7" +version = "1.1.8" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] edition = "2021" rust-version = "1.65" diff --git a/service-providers/network-statistics/Cargo.toml b/service-providers/network-statistics/Cargo.toml index 2e6d067ab4..accdccc977 100644 --- a/service-providers/network-statistics/Cargo.toml +++ b/service-providers/network-statistics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-network-statistics" -version = "1.1.7" +version = "1.1.8" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index f866e7fa82..7680ea44fe 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-cli" -version = "1.1.7" +version = "1.1.8" authors.workspace = true edition = "2021" diff --git a/yarn.lock b/yarn.lock index dc24ba32fd..906ab624b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10715,18 +10715,6 @@ hex-rgb@^4.1.0: resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776" integrity sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw== -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -10736,7 +10724,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -11697,11 +11685,6 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -12969,7 +12952,7 @@ longest-streak@^3.0.0: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== -loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -15078,13 +15061,6 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -16060,7 +16036,7 @@ react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^16.10.2, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: +react-is@^16.10.2, react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -16128,7 +16104,7 @@ react-resize-detector@^7.1.2: dependencies: lodash "^4.17.21" -react-router-dom@6: +react-router-dom@6, react-router-dom@^6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.7.0.tgz#0249f4ca4eb704562b8b0ff29caeb928c3a6ed38" integrity sha512-jQtXUJyhso3kFw430+0SPCbmCmY1/kJv8iRffGHwHy3CkoomGxeYzMkmeSPYo6Egzh3FKJZRAL22yg5p2tXtfg== @@ -16136,34 +16112,6 @@ react-router-dom@6: "@remix-run/router" "1.3.0" react-router "6.7.0" -react-router-dom@^5.2.0: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" - integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.3.4" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router@5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5" - integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - react-router@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.7.0.tgz#db262684c13b5c2970694084ae9e8531718a0681" @@ -16742,11 +16690,6 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -18180,12 +18123,7 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tiny-invariant@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== - -tiny-warning@^1.0.0, tiny-warning@^1.0.2: +tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -18985,11 +18923,6 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"