diff --git a/Cargo.lock b/Cargo.lock index f076131607..f8213321ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3549,6 +3549,7 @@ checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" name = "network-defaults" version = "0.1.0" dependencies = [ + "cfg-if 1.0.0", "hex-literal", "serde", "time 0.3.3", diff --git a/common/network-defaults/Cargo.toml b/common/network-defaults/Cargo.toml index ba50e9c473..dfd640b08a 100644 --- a/common/network-defaults/Cargo.toml +++ b/common/network-defaults/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cfg-if = "1.0.0" hex-literal = "0.3.3" serde = {version = "1.0", features = ["derive"]} url = "2.2" diff --git a/common/network-defaults/src/all.rs b/common/network-defaults/src/all.rs new file mode 100644 index 0000000000..e0b5f11127 --- /dev/null +++ b/common/network-defaults/src/all.rs @@ -0,0 +1,130 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +use crate::{milhon, qa, sandbox, ValidatorDetails}; + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum Network { + MILHON, + QA, + SANDBOX, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct NetworkDetails { + bech32_prefix: String, + denom: String, + mixnet_contract_address: String, + vesting_contract_address: String, + bandwidth_claim_contract_address: String, + rewarding_validator_address: String, + validators: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct SupportedNetworks { + networks: HashMap, +} + +impl SupportedNetworks { + pub fn new(support: Vec) -> Self { + let mut networks = HashMap::new(); + + for network in support { + match network { + Network::MILHON => networks.insert( + Network::MILHON, + NetworkDetails { + bech32_prefix: String::from(milhon::BECH32_PREFIX), + denom: String::from(milhon::DENOM), + mixnet_contract_address: String::from(milhon::MIXNET_CONTRACT_ADDRESS), + vesting_contract_address: String::from(milhon::VESTING_CONTRACT_ADDRESS), + bandwidth_claim_contract_address: String::from( + milhon::BANDWIDTH_CLAIM_CONTRACT_ADDRESS, + ), + rewarding_validator_address: String::from( + milhon::REWARDING_VALIDATOR_ADDRESS, + ), + validators: milhon::validators(), + }, + ), + Network::QA => networks.insert( + Network::QA, + NetworkDetails { + bech32_prefix: String::from(qa::BECH32_PREFIX), + denom: String::from(qa::DENOM), + mixnet_contract_address: String::from(qa::MIXNET_CONTRACT_ADDRESS), + vesting_contract_address: String::from(qa::VESTING_CONTRACT_ADDRESS), + bandwidth_claim_contract_address: String::from( + qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS, + ), + rewarding_validator_address: String::from(qa::REWARDING_VALIDATOR_ADDRESS), + validators: qa::validators(), + }, + ), + Network::SANDBOX => networks.insert( + Network::SANDBOX, + NetworkDetails { + bech32_prefix: String::from(sandbox::BECH32_PREFIX), + denom: String::from(sandbox::DENOM), + mixnet_contract_address: String::from(sandbox::MIXNET_CONTRACT_ADDRESS), + vesting_contract_address: String::from(sandbox::VESTING_CONTRACT_ADDRESS), + bandwidth_claim_contract_address: String::from( + sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS, + ), + rewarding_validator_address: String::from( + sandbox::REWARDING_VALIDATOR_ADDRESS, + ), + validators: sandbox::validators(), + }, + ), + }; + } + SupportedNetworks { networks } + } + + pub fn bech32_prefix(&self, network: Network) -> Option<&str> { + self.networks + .get(&network) + .map(|network_details| network_details.bech32_prefix.as_str()) + } + + pub fn denom(&self, network: Network) -> Option<&str> { + self.networks + .get(&network) + .map(|network_details| network_details.denom.as_str()) + } + + pub fn mixnet_contract_address(&self, network: Network) -> Option<&str> { + self.networks + .get(&network) + .map(|network_details| network_details.mixnet_contract_address.as_str()) + } + + pub fn vesting_contract_address(&self, network: Network) -> Option<&str> { + self.networks + .get(&network) + .map(|network_details| network_details.vesting_contract_address.as_str()) + } + + pub fn bandwidth_claim_contract_address(&self, network: Network) -> Option<&str> { + self.networks + .get(&network) + .map(|network_details| network_details.bandwidth_claim_contract_address.as_str()) + } + + pub fn rewarding_validator_address(&self, network: Network) -> Option<&str> { + self.networks + .get(&network) + .map(|network_details| network_details.rewarding_validator_address.as_str()) + } + + pub fn validators(&self, network: Network) -> Option<&Vec> { + self.networks + .get(&network) + .map(|network_details| &network_details.validators) + } +} diff --git a/common/network-defaults/src/lib.rs b/common/network-defaults/src/lib.rs index f350490376..c3f1638b24 100644 --- a/common/network-defaults/src/lib.rs +++ b/common/network-defaults/src/lib.rs @@ -5,20 +5,63 @@ use std::time::Duration; use time::OffsetDateTime; use url::Url; +pub mod all; pub mod eth_contract; -#[cfg(network = "milhon")] -pub mod milhon; -#[cfg(network = "qa")] -pub mod qa; -#[cfg(network = "sandbox")] -pub mod sandbox; +mod milhon; +mod qa; +mod sandbox; -#[cfg(network = "milhon")] -pub use milhon::*; -#[cfg(network = "qa")] -pub use qa::*; -#[cfg(network = "sandbox")] -pub use sandbox::*; +cfg_if::cfg_if! { + if #[cfg(network = "milhon")] { + pub const BECH32_PREFIX: &str = milhon::BECH32_PREFIX; + pub const DENOM: &str = milhon::DENOM; + + pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = milhon::MIXNET_CONTRACT_ADDRESS; + pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = milhon::VESTING_CONTRACT_ADDRESS; + pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = milhon::BANDWIDTH_CLAIM_CONTRACT_ADDRESS; + pub const DEFAULT_REWARDING_VALIDATOR_ADDRESS: &str = milhon::REWARDING_VALIDATOR_ADDRESS; + + pub fn default_validators() -> Vec { + milhon::validators() + } + + pub fn default_network() -> all::Network { + all::Network::MILHON + } + } else if #[cfg(network = "qa")] { + pub const BECH32_PREFIX: &str = qa::BECH32_PREFIX; + pub const DENOM: &str = qa::DENOM; + + pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = qa::MIXNET_CONTRACT_ADDRESS; + pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = qa::VESTING_CONTRACT_ADDRESS; + pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS; + pub const DEFAULT_REWARDING_VALIDATOR: &str = qa::REWARDING_VALIDATOR_ADDRESS; + + pub fn default_validators() -> Vec { + qa::validators() + } + + pub fn default_network() -> all::Network { + all::Network::QA + } + } else if #[cfg(network = "sandbox")] { + pub const BECH32_PREFIX: &str = sandbox::BECH32_PREFIX; + pub const DENOM: &str = sandbox::DENOM; + + pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = sandbox::MIXNET_CONTRACT_ADDRESS; + pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = sandbox::VESTING_CONTRACT_ADDRESS; + pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS; + pub const DEFAULT_REWARDING_VALIDATOR: &str = sandbox::REWARDING_VALIDATOR_ADDRESS; + + pub fn default_validators() -> Vec { + sandbox::validators() + } + + pub fn default_network() -> all::Network { + all::Network::SANDBOX + } + } +} #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ValidatorDetails { @@ -51,33 +94,6 @@ impl ValidatorDetails { } } -#[cfg(network = "milhon")] -pub fn default_validators() -> Vec { - vec![ - ValidatorDetails::new( - "https://testnet-milhon-validator1.nymtech.net", - Some("https://testnet-milhon-validator1.nymtech.net/api"), - ), - ValidatorDetails::new("https://testnet-milhon-validator2.nymtech.net", None), - ] -} - -#[cfg(network = "qa")] -pub fn default_validators() -> Vec { - vec![ValidatorDetails::new( - "https://qa-validator.nymtech.net", - Some("https://qa-validator.nymtech.net/api"), - )] -} - -#[cfg(network = "sandbox")] -pub fn default_validators() -> Vec { - vec![ValidatorDetails::new( - "https://sandbox-validator.nymtech.net", - Some("https://sandbox-validator.nymtech.net/api"), - )] -} - pub fn default_nymd_endpoints() -> Vec { default_validators() .iter() @@ -92,6 +108,13 @@ pub fn default_api_endpoints() -> Vec { .collect() } +pub const ETH_CONTRACT_ADDRESS: [u8; 20] = + hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102"); +// Name of the event triggered by the eth contract. If the event name is changed, +// this would also need to be changed; It is currently tested against the json abi +pub const ETH_EVENT_NAME: &str = "Burned"; +pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode"; + // Ethereum constants used for token bridge /// How much bandwidth (in bytes) one token can buy const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024; diff --git a/common/network-defaults/src/milhon.rs b/common/network-defaults/src/milhon.rs index 28e28588a4..a4e4f3e640 100644 --- a/common/network-defaults/src/milhon.rs +++ b/common/network-defaults/src/milhon.rs @@ -1,17 +1,23 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub const BECH32_PREFIX: &str = "punk"; -pub const DENOM: &str = "upunk"; +use crate::ValidatorDetails; -pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen"; -pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = ""; -pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82"; -pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3"; -pub const ETH_CONTRACT_ADDRESS: [u8; 20] = - hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102"); +pub(crate) const BECH32_PREFIX: &str = "punk"; +pub(crate) const DENOM: &str = "upunk"; -// Name of the event triggered by the eth contract. If the event name is changed, -// this would also need to be changed; It is currently tested against the json abi -pub const ETH_EVENT_NAME: &str = "Burned"; -pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode"; +pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen"; +pub(crate) const VESTING_CONTRACT_ADDRESS: &str = ""; +pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = + "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82"; +pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3"; + +pub(crate) fn validators() -> Vec { + vec![ + ValidatorDetails::new( + "https://testnet-milhon-validator1.nymtech.net", + Some("https://testnet-milhon-validator1.nymtech.net/api"), + ), + ValidatorDetails::new("https://testnet-milhon-validator2.nymtech.net", None), + ] +} diff --git a/common/network-defaults/src/qa.rs b/common/network-defaults/src/qa.rs index c31b8bc379..1e5fd029ae 100644 --- a/common/network-defaults/src/qa.rs +++ b/common/network-defaults/src/qa.rs @@ -1,17 +1,20 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub const BECH32_PREFIX: &str = "nymt"; -pub const DENOM: &str = "unymt"; +use crate::ValidatorDetails; -pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "nymt14hj2tavq8fpesdwxxcu44rty3hh90vhuysqrsr"; -pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; -pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; -pub const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1dn52nx8wv9wkqmrvj6tcmdzh4es6jt8tr7f6j9"; -pub const ETH_CONTRACT_ADDRESS: [u8; 20] = - hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102"); +pub(crate) const BECH32_PREFIX: &str = "nymt"; +pub(crate) const DENOM: &str = "unymt"; -// Name of the event triggered by the eth contract. If the event name is changed, -// this would also need to be changed; It is currently tested against the json abi -pub const ETH_EVENT_NAME: &str = "Burned"; -pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode"; +pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt14hj2tavq8fpesdwxxcu44rty3hh90vhuysqrsr"; +pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; +pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = + "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; +pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1dn52nx8wv9wkqmrvj6tcmdzh4es6jt8tr7f6j9"; + +pub(crate) fn validators() -> Vec { + vec![ValidatorDetails::new( + "https://qa-validator.nymtech.net", + Some("https://qa-validator.nymtech.net/api"), + )] +} diff --git a/common/network-defaults/src/sandbox.rs b/common/network-defaults/src/sandbox.rs index 951b1a7f39..81b766882e 100644 --- a/common/network-defaults/src/sandbox.rs +++ b/common/network-defaults/src/sandbox.rs @@ -1,17 +1,20 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub const BECH32_PREFIX: &str = "nymt"; -pub const DENOM: &str = "unymt"; +use crate::ValidatorDetails; -pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j"; -pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s"; -pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; -pub const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e"; -pub const ETH_CONTRACT_ADDRESS: [u8; 20] = - hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102"); +pub(crate) const BECH32_PREFIX: &str = "nymt"; +pub(crate) const DENOM: &str = "unymt"; -// Name of the event triggered by the eth contract. If the event name is changed, -// this would also need to be changed; It is currently tested against the json abi -pub const ETH_EVENT_NAME: &str = "Burned"; -pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode"; +pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j"; +pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s"; +pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = + "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; +pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e"; + +pub(crate) fn validators() -> Vec { + vec![ValidatorDetails::new( + "https://sandbox-validator.nymtech.net", + Some("https://sandbox-validator.nymtech.net/api"), + )] +} diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 6654a6ff25..e0ad7ddf60 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -877,6 +877,7 @@ dependencies = [ name = "network-defaults" version = "0.1.0" dependencies = [ + "cfg-if", "hex-literal", "serde", "time 0.3.5", diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index eaff16f8ce..420a011ae0 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -309,7 +309,7 @@ pub mod tests { let mut deps = mock_dependencies(); let env = mock_env(); let msg = InstantiateMsg { - rewarding_validator_address: config::defaults::REWARDING_VALIDATOR_ADDRESS.to_string(), + rewarding_validator_address: config::defaults::DEFAULT_REWARDING_VALIDATOR.to_string(), }; let info = mock_info("creator", &[]); diff --git a/contracts/mixnet/src/support/tests/mod.rs b/contracts/mixnet/src/support/tests/mod.rs index 3218b72162..547c68ffdd 100644 --- a/contracts/mixnet/src/support/tests/mod.rs +++ b/contracts/mixnet/src/support/tests/mod.rs @@ -81,7 +81,7 @@ pub mod test_helpers { pub fn init_contract() -> OwnedDeps> { let mut deps = mock_dependencies(); let msg = InstantiateMsg { - rewarding_validator_address: config::defaults::REWARDING_VALIDATOR_ADDRESS.to_string(), + rewarding_validator_address: config::defaults::DEFAULT_REWARDING_VALIDATOR.to_string(), }; let env = mock_env(); let info = mock_info("creator", &[]); diff --git a/gateway/src/node/client_handling/websocket/connection_handler/eth_events.rs b/gateway/src/node/client_handling/websocket/connection_handler/eth_events.rs index 2c0cb6e8ea..f163daae6b 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/eth_events.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/eth_events.rs @@ -20,7 +20,7 @@ use credentials::token::bandwidth::TokenCredential; use crypto::asymmetric::identity::{PublicKey, Signature}; use gateway_client::bandwidth::eth_contract; use network_defaults::{ - BANDWIDTH_CLAIM_CONTRACT_ADDRESS, DENOM, ETH_EVENT_NAME, ETH_MIN_BLOCK_DEPTH, + DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS, DENOM, ETH_EVENT_NAME, ETH_MIN_BLOCK_DEPTH, }; use validator_client::nymd::{ AccountId, CosmosCoin, Decimal, Denom, NymdClient, SigningNymdClient, @@ -44,7 +44,7 @@ impl ERC20Bridge { Mnemonic::from_str(&cosmos_mnemonic).expect("Invalid Cosmos mnemonic provided"); let nymd_client = NymdClient::connect_with_mnemonic( nymd_url.as_ref(), - AccountId::from_str(BANDWIDTH_CLAIM_CONTRACT_ADDRESS).ok(), + AccountId::from_str(DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS).ok(), None, mnemonic, None, diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 0c30eae3c5..0eb700103b 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -2680,6 +2680,7 @@ checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" name = "network-defaults" version = "0.1.0" dependencies = [ + "cfg-if 1.0.0", "hex-literal", "serde", "time 0.3.5", @@ -2809,6 +2810,7 @@ dependencies = [ "rand 0.6.5", "serde", "serde_json", + "strum 0.23.0", "tauri", "tauri-build", "tendermint-rpc", @@ -4400,6 +4402,15 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" +[[package]] +name = "strum" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" +dependencies = [ + "strum_macros 0.23.1", +] + [[package]] name = "strum_macros" version = "0.18.0" @@ -4424,6 +4435,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subtle" version = "1.0.0" diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index 457444a2c1..7647fc3c2d 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -18,6 +18,7 @@ tauri-build = { version = "1.0.0-beta.4" } [dependencies] serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } +strum = { version = "0.23", features = ["derive"] } tauri = { version = "1.0.0-beta.8", features = ["shell-open"] } tokio = { version = "1.10", features = ["sync"] } dirs = "4.0" diff --git a/nym-wallet/src-tauri/src/config/mod.rs b/nym-wallet/src-tauri/src/config/mod.rs index a5107fe393..95de5b345b 100644 --- a/nym-wallet/src-tauri/src/config/mod.rs +++ b/nym-wallet/src-tauri/src/config/mod.rs @@ -1,10 +1,12 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use config::defaults::{default_validators, ValidatorDetails, DEFAULT_MIXNET_CONTRACT_ADDRESS}; +use crate::network::Network; +use config::defaults::all::SupportedNetworks; use config::NymConfig; use serde::{Deserialize, Serialize}; use std::path::PathBuf; +use strum::IntoEnumIterator; use url::Url; mod template; @@ -20,21 +22,15 @@ pub struct Config { #[derive(Debug, Deserialize, Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct Base { - validators: Vec, - - /// Address of the validator contract managing the network - mixnet_contract_address: String, - - /// Mnemonic (currently of the network monitor) used for rewarding - mnemonic: String, + /// Information on all the networks that the wallet connects to. + networks: SupportedNetworks, } impl Default for Base { fn default() -> Self { + let networks = Network::iter().map(|network| network.into()).collect(); Base { - validators: default_validators(), - mixnet_contract_address: DEFAULT_MIXNET_CONTRACT_ADDRESS.to_string(), - mnemonic: String::default(), + networks: SupportedNetworks::new(networks), } } } @@ -65,33 +61,51 @@ impl NymConfig for Config { } impl Config { - pub fn get_nymd_validator_url(&self) -> Url { + pub fn get_nymd_validator_url(&self, network: Network) -> Url { // TODO make this a random choice - if let Some(validator_details) = self.base.validators.first() { + if let Some(Some(validator_details)) = self + .base + .networks + .validators(network.into()) + .map(|validators| validators.first()) + { validator_details.nymd_url() } else { panic!("No validators found in config") } } - pub fn get_validator_api_url(&self) -> Url { + pub fn get_validator_api_url(&self, network: Network) -> Url { // TODO make this a random choice - if let Some(validator_details) = self.base.validators.first() { + if let Some(Some(validator_details)) = self + .base + .networks + .validators(network.into()) + .map(|validators| validators.first()) + { validator_details.api_url().expect("no api url provided") } else { panic!("No validators found in config") } } - pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId { + pub fn get_mixnet_contract_address(&self, network: Network) -> cosmrs::AccountId { self .base - .mixnet_contract_address + .networks + .mixnet_contract_address(network.into()) + .expect("No mixnet contract address found in config") .parse() .expect("stored mixnet contract address is not a valid account address") } - pub fn get_vesting_contract_address(&self) -> Option { - None + pub fn get_vesting_contract_address(&self, network: Network) -> cosmrs::AccountId { + self + .base + .networks + .vesting_contract_address(network.into()) + .expect("No vesting contract address found in config") + .parse() + .expect("stored vesting contract address is not a valid account address") } } diff --git a/nym-wallet/src-tauri/src/error.rs b/nym-wallet/src-tauri/src/error.rs index a99090ba56..9101549fb5 100644 --- a/nym-wallet/src-tauri/src/error.rs +++ b/nym-wallet/src-tauri/src/error.rs @@ -41,6 +41,8 @@ pub enum BackendError { NoBalance(String), #[error("{0} is not a valid denomination string")] InvalidDenom(String), + #[error("The provided network is not supported (yet)")] + NetworkNotSupported(config::defaults::all::Network), } impl Serialize for BackendError { diff --git a/nym-wallet/src-tauri/src/main.rs b/nym-wallet/src-tauri/src/main.rs index d2e873a297..da5619524d 100644 --- a/nym-wallet/src-tauri/src/main.rs +++ b/nym-wallet/src-tauri/src/main.rs @@ -13,6 +13,7 @@ mod coin; mod config; mod error; mod menu; +mod network; mod operations; mod state; mod utils; @@ -30,6 +31,7 @@ fn main() { .invoke_handler(tauri::generate_handler![ mixnet::account::connect_with_mnemonic, mixnet::account::create_new_account, + mixnet::account::switch_network, mixnet::account::get_balance, mixnet::admin::get_contract_settings, mixnet::admin::update_contract_settings, @@ -80,6 +82,7 @@ mod test { ts_rs::export! { mixnet_contract_common::MixNode => "../src/types/rust/mixnode.ts", crate::coin::Coin => "../src/types/rust/coin.ts", + crate::network::Network => "../src/types/rust/network.ts", crate::mixnet::account::Balance => "../src/types/rust/balance.ts", mixnet_contract_common::Gateway => "../src/types/rust/gateway.ts", crate::mixnet::send::TauriTxResult => "../src/types/rust/tauritxresult.ts", diff --git a/nym-wallet/src-tauri/src/network.rs b/nym-wallet/src-tauri/src/network.rs new file mode 100644 index 0000000000..ff05ea86e2 --- /dev/null +++ b/nym-wallet/src-tauri/src/network.rs @@ -0,0 +1,43 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; +use strum::EnumIter; + +use crate::error::BackendError; +use config::defaults::all::Network as ConfigNetwork; + +#[cfg_attr(test, derive(ts_rs::TS))] +#[derive(Copy, Clone, Debug, Deserialize, EnumIter, Eq, Hash, PartialEq, Serialize)] +pub enum Network { + QA, + SANDBOX, +} + +impl Default for Network { + fn default() -> Self { + Network::SANDBOX + } +} + +impl Into for Network { + fn into(self) -> ConfigNetwork { + match self { + Network::QA => ConfigNetwork::QA, + Network::SANDBOX => ConfigNetwork::SANDBOX, + } + } +} + +impl TryFrom for Network { + type Error = BackendError; + + fn try_from(value: ConfigNetwork) -> Result { + match value { + ConfigNetwork::QA => Ok(Network::QA), + ConfigNetwork::SANDBOX => Ok(Network::SANDBOX), + _ => Err(BackendError::NetworkNotSupported(value)), + } + } +} diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index 320f84e4d4..1fbfa653c6 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -1,16 +1,16 @@ use crate::coin::{Coin, Denom}; -use crate::config::Config; use crate::error::BackendError; +use crate::network::Network; use crate::nymd_client; use crate::state::State; + use bip39::{Language, Mnemonic}; use serde::{Deserialize, Serialize}; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use std::str::FromStr; use std::sync::Arc; +use strum::IntoEnumIterator; use tokio::sync::RwLock; -use validator_client::nymd::SigningNymdClient; -use validator_client::Client; #[cfg_attr(test, derive(ts_rs::TS))] #[derive(Serialize, Deserialize)] @@ -18,7 +18,16 @@ pub struct Account { contract_address: String, client_address: String, denom: Denom, - mnemonic: Option, +} + +impl Account { + pub fn new(contract_address: String, client_address: String, denom: Denom) -> Self { + Account { + contract_address, + client_address, + denom, + } + } } #[cfg_attr(test, derive(ts_rs::TS))] @@ -34,26 +43,7 @@ pub async fn connect_with_mnemonic( state: tauri::State<'_, Arc>>, ) -> Result { let mnemonic = Mnemonic::from_str(&mnemonic)?; - let client = { - let r_state = state.read().await; - _connect_with_mnemonic(mnemonic, &r_state.config()) - }; - - let contract_address = client.nymd.mixnet_contract_address()?.to_string(); - let client_address = client.nymd.address().to_string(); - let denom = client.nymd.denom()?; - - let account = Account { - contract_address, - client_address, - denom: denom.try_into()?, - mnemonic: None, - }; - - let mut w_state = state.write().await; - w_state.set_client(client); - - Ok(account) + _connect_with_mnemonic(mnemonic, state).await } #[tauri::command] @@ -86,9 +76,30 @@ pub async fn create_new_account( state: tauri::State<'_, Arc>>, ) -> Result { let rand_mnemonic = random_mnemonic(); - let mut client = connect_with_mnemonic(rand_mnemonic.to_string(), state).await?; - client.mnemonic = Some(rand_mnemonic.to_string()); - Ok(client) + let account = connect_with_mnemonic(rand_mnemonic.to_string(), state).await?; + Ok(account) +} + +#[tauri::command] +pub async fn switch_network( + state: tauri::State<'_, Arc>>, + network: Network, +) -> Result { + let account = { + let r_state = state.read().await; + let client = r_state.client(network)?; + + Account::new( + client.nymd.mixnet_contract_address()?.to_string(), + client.nymd.address().to_string(), + client.nymd.denom()?.try_into()?, + ) + }; + + let mut w_state = state.write().await; + w_state.set_network(network); + + Ok(account) } fn random_mnemonic() -> Mnemonic { @@ -96,17 +107,42 @@ fn random_mnemonic() -> Mnemonic { Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap() } -fn _connect_with_mnemonic(mnemonic: Mnemonic, config: &Config) -> Client { - match validator_client::Client::new_signing( - validator_client::Config::new( - config.get_nymd_validator_url(), - config.get_validator_api_url(), - Some(config.get_mixnet_contract_address()), - config.get_vesting_contract_address(), - ), - mnemonic, - ) { - Ok(client) => client, - Err(e) => panic!("{}", e), +async fn _connect_with_mnemonic( + mnemonic: Mnemonic, + state: tauri::State<'_, Arc>>, +) -> Result { + let default_network = Network::try_from(config::defaults::default_network())?; + let mut default_account = None; + for network in Network::iter() { + let client = { + let config = state.read().await.config(); + match validator_client::Client::new_signing( + validator_client::Config::new( + config.get_nymd_validator_url(network), + config.get_validator_api_url(network), + Some(config.get_mixnet_contract_address(network)), + Some(config.get_vesting_contract_address(network)), + ), + mnemonic.clone(), + ) { + Ok(client) => client, + Err(e) => panic!("{}", e), + } + }; + + if network == default_network { + default_account = Some(Account::new( + client.nymd.mixnet_contract_address()?.to_string(), + client.nymd.address().to_string(), + client.nymd.denom()?.try_into()?, + )); + } + + let mut w_state = state.write().await; + w_state.add_client(network, client); } + + default_account.ok_or(BackendError::NetworkNotSupported( + config::defaults::default_network(), + )) } diff --git a/nym-wallet/src-tauri/src/operations/mixnet/bond.rs b/nym-wallet/src-tauri/src/operations/mixnet/bond.rs index 9a2cf0cb30..3180bbf991 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/bond.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/bond.rs @@ -66,7 +66,7 @@ pub async fn mixnode_bond_details( state: tauri::State<'_, Arc>>, ) -> Result, BackendError> { let guard = state.read().await; - let client = guard.client()?; + let client = guard.current_client()?; let bond = client.nymd.owns_mixnode(client.nymd.address()).await?; Ok(bond) } @@ -76,7 +76,7 @@ pub async fn gateway_bond_details( state: tauri::State<'_, Arc>>, ) -> Result, BackendError> { let guard = state.read().await; - let client = guard.client()?; + let client = guard.current_client()?; let bond = client.nymd.owns_gateway(client.nymd.address()).await?; Ok(bond) } diff --git a/nym-wallet/src-tauri/src/state.rs b/nym-wallet/src-tauri/src/state.rs index 2b423cf744..b54355d8b4 100644 --- a/nym-wallet/src-tauri/src/state.rs +++ b/nym-wallet/src-tauri/src/state.rs @@ -1,19 +1,30 @@ use crate::config::Config; use crate::error::BackendError; +use crate::network::Network; use validator_client::nymd::SigningNymdClient; use validator_client::Client; +use std::collections::HashMap; + #[derive(Default)] pub struct State { config: Config, - signing_client: Option>, + signing_clients: HashMap>, + current_network: Network, } impl State { - pub fn client(&self) -> Result<&Client, BackendError> { + pub fn client(&self, network: Network) -> Result<&Client, BackendError> { self - .signing_client - .as_ref() + .signing_clients + .get(&network) + .ok_or(BackendError::ClientNotInitialized) + } + + pub fn current_client(&self) -> Result<&Client, BackendError> { + self + .signing_clients + .get(&self.current_network) .ok_or(BackendError::ClientNotInitialized) } @@ -21,28 +32,32 @@ impl State { self.config.clone() } - pub fn set_client(&mut self, signing_client: Client) { - self.signing_client = Some(signing_client) + pub fn add_client(&mut self, network: Network, client: Client) { + self.signing_clients.insert(network, client); + } + + pub fn set_network(&mut self, network: Network) { + self.current_network = network; } } #[macro_export] macro_rules! client { ($state:ident) => { - $state.read().await.client()? + $state.read().await.current_client()? }; } #[macro_export] macro_rules! nymd_client { ($state:ident) => { - $state.read().await.client()?.nymd + $state.read().await.current_client()?.nymd }; } #[macro_export] macro_rules! api_client { ($state:ident) => { - $state.read().await.client()?.validator_api + $state.read().await.current_client()?.validator_api }; } diff --git a/nym-wallet/src/types/rust/account.ts b/nym-wallet/src/types/rust/account.ts index 196968055f..d07f41b6ab 100644 --- a/nym-wallet/src/types/rust/account.ts +++ b/nym-wallet/src/types/rust/account.ts @@ -4,5 +4,4 @@ export interface Account { contract_address: string; client_address: string; denom: Denom; - mnemonic: string | null; } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/network.ts b/nym-wallet/src/types/rust/network.ts new file mode 100644 index 0000000000..037ec89ba1 --- /dev/null +++ b/nym-wallet/src/types/rust/network.ts @@ -0,0 +1 @@ +export type Network = "QA" | "SANDBOX"; \ No newline at end of file